Commit 8050bb6cc8bc29ff4c8b4dafe07a4ab3d7c04668

Authored by 王通
2 parents e1018ca6 d9f05c05

1.部分内容与浦交分支合并

Too many changes to show.

To preserve performance only 24 of 46 files are displayed.

... ... @@ -181,27 +181,32 @@
181 181  
182 182 <!-- pentaho kettle 依赖 -->
183 183 <dependency>
184   - <groupId>com.pentaho.kettle</groupId>
  184 + <groupId>pentaho-kettle</groupId>
185 185 <artifactId>kettle-core</artifactId>
186 186 <version>6.0.1.0-386</version>
  187 + <exclusions>
  188 + <exclusion>
  189 + <groupId>org.apache.xmlgraphics</groupId>
  190 + <artifactId>batik-js</artifactId>
  191 + </exclusion>
  192 + </exclusions>
  193 + </dependency>
  194 + <dependency>
  195 + <groupId>pentaho-kettle</groupId>
  196 + <artifactId>kettle-engine</artifactId>
  197 + <version>6.0.1.0-386</version>
187 198 </dependency>
188   - <dependency>
189   - <groupId>com.pentaho.kettle</groupId>
190   - <artifactId>kettle-engine</artifactId>
191   - <version>6.0.1.0-386</version>
192   - </dependency>
193 199 <dependency>
194   - <groupId>com.pentaho.kettle</groupId>
  200 + <groupId>pentaho</groupId>
195 201 <artifactId>metastore</artifactId>
196 202 <version>6.0.1.0-386</version>
197 203 </dependency>
198 204 <dependency>
199   - <groupId>com.pentaho.kettle</groupId>
200   - <artifactId>vfs2</artifactId>
  205 + <groupId>org.apache.commons</groupId>
  206 + <artifactId>commons-vfs2</artifactId>
201 207 <version>2.1-20150824</version>
202 208 </dependency>
203 209  
204   -
205 210 <dependency>
206 211 <groupId>net.sourceforge.jexcelapi</groupId>
207 212 <artifactId>jxl</artifactId>
... ... @@ -291,12 +296,6 @@
291 296  
292 297  
293 298 <dependency>
294   - <groupId>ojdbc</groupId>
295   - <artifactId>ojdbc</artifactId>
296   - <version>14</version>
297   - </dependency>
298   -
299   - <dependency>
300 299 <groupId>org.apache.mina</groupId>
301 300 <artifactId>mina-core</artifactId>
302 301 <version>2.0.13</version>
... ...
src/main/java/com/bsth/Application.java
... ... @@ -17,7 +17,7 @@ import java.util.concurrent.ScheduledExecutorService;
17 17 @SpringBootApplication
18 18 public class Application extends SpringBootServletInitializer {
19 19  
20   - public static ScheduledExecutorService mainServices = Executors.newScheduledThreadPool(18);
  20 + public static ScheduledExecutorService mainServices = Executors.newScheduledThreadPool(21);
21 21  
22 22 @Override
23 23 protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
... ...
src/main/java/com/bsth/XDApplication.java
... ... @@ -97,8 +97,8 @@ public class XDApplication implements CommandLineRunner {
97 97 timeDiff = (DateUtils.getTimestamp() + 1000 * 60 * 140) - System.currentTimeMillis();
98 98 if (timeDiff < 0)
99 99 timeDiff += (1000 * 60 * 60 * 24);
100   - // 早上07:00
101   - timeDiffTraffic = (DateUtils.getTimestamp() + 1000 * 60 * 60 * 7) - System.currentTimeMillis();
  100 + // 早上09:00
  101 + timeDiffTraffic = (DateUtils.getTimestamp() + 3600000 * 9) - System.currentTimeMillis();
102 102 if (timeDiffTraffic < 0)
103 103 timeDiffTraffic += (1000 * 60 * 60 * 24);
104 104 }
... ... @@ -120,6 +120,9 @@ public class XDApplication implements CommandLineRunner {
120 120 case "test":
121 121 testInit();
122 122 break;
  123 + case "cloud":
  124 + cloudInit();
  125 + break;
123 126 default:
124 127 break;
125 128 }
... ... @@ -266,4 +269,48 @@ public class XDApplication implements CommandLineRunner {
266 269 //线路版本更新
267 270 //sexec.scheduleWithFixedDelay(fixedEnableVerionsThread, 60 * 4, 60 * 2 , TimeUnit.SECONDS);
268 271 }
  272 +
  273 + public void cloudInit(){
  274 + log.info("cloudInit...");
  275 + ScheduledExecutorService sexec = Application.mainServices;
  276 + //安全驾驶
  277 + sexec.scheduleWithFixedDelay(safeDrivDataLoadThread, 180, 10, TimeUnit.SECONDS);
  278 +
  279 + GpsDataLoaderThread.setFlag(-1);
  280 + /** 线调业务 */
  281 + sexec.scheduleWithFixedDelay(scheduleRefreshThread, 10, 120, TimeUnit.SECONDS);//班次更新线程
  282 + sexec.scheduleWithFixedDelay(scheduleLateThread, 140, 20, TimeUnit.SECONDS);//检查班次误点
  283 + sexec.scheduleWithFixedDelay(gpsDataLoader, 0, 2, TimeUnit.SECONDS);//抓取GPS数据
  284 + sexec.scheduleWithFixedDelay(rfidDataLoader, 5, 5, TimeUnit.SECONDS);//抓取RFID数据
  285 + sexec.scheduleWithFixedDelay(fixedCheckStationCodeThread, 60, 60 * 5, TimeUnit.SECONDS);//检查班次站点编码
  286 +
  287 + sexec.scheduleWithFixedDelay(offlineMonitorThread, 120, 60, TimeUnit.SECONDS);//GPS设备掉离线
  288 + sexec.scheduleWithFixedDelay(schedulePstThread, 180, 10, TimeUnit.SECONDS);//班次延迟入库线程
  289 + sexec.scheduleWithFixedDelay(seiPstThread, 180, 60, TimeUnit.SECONDS);//班次修正日志入库
  290 + sexec.scheduleWithFixedDelay(directivesPstThread, 120, 60, TimeUnit.SECONDS);//调度指令延迟入库
  291 + sexec.scheduleWithFixedDelay(threadMonotor, 240, 60, TimeUnit.SECONDS);//线程监听(防止重要的线程阻塞、异常结束。以及部分主备切换工作)
  292 + sexec.scheduleWithFixedDelay(sampleTimeDataLoader, 140, 120 * 60, TimeUnit.SECONDS);//到离站预测需要的站点间耗时数据
  293 + sexec.scheduleWithFixedDelay(basicDataLoader, 1, 1, TimeUnit.HOURS);//基础数据更新
  294 + sexec.scheduleWithFixedDelay(autoExecScanThread, 180, 50, TimeUnit.SECONDS);//班次自动执行
  295 + DirectivePushQueue.start();//消息队列 -指令,系统下发的
  296 + WebSocketPushQueue.start();//消息队列 -webSocket ,推送至线调web页面的
  297 +
  298 + /** 线调为其他程序提供的数据 --写入数据库 */
  299 + sexec.scheduleWithFixedDelay(fcxxUpdateThread, 160, 30, TimeUnit.SECONDS);//发车信息(发车屏、信息发布)
  300 + //线路首末班数据(网关用,班次更新时写入)
  301 + //com.bsth.data.schedule.f_a_l.FirstAndLastHandler
  302 + sexec.scheduleWithFixedDelay(schSiginUpdateDBThread, 160, 60 * 30, TimeUnit.SECONDS);//无法自动完成的班次信息(网关用,补信号)
  303 +
  304 + //运管处静态数据提交
  305 + log.info(timeDiff / 1000 / 60 + "分钟之后提交到运管处");
  306 + sexec.scheduleAtFixedRate(submitToTrafficManage, timeDiffTraffic / 1000, 60 * 60 * 24, TimeUnit.SECONDS);
  307 + //计算油、公里加注
  308 + sexec.scheduleAtFixedRate(calcOilThread, timeDiff / 1000, 60 * 60 * 24, TimeUnit.SECONDS);
  309 +
  310 + //线路版本更新
  311 + sexec.scheduleWithFixedDelay(lineVersionsData, 60 * 5, 60 * 15, TimeUnit.SECONDS);
  312 +
  313 + //线路版本更新
  314 + //sexec.scheduleWithFixedDelay(fixedEnableVerionsThread, 60 * 4, 60 * 2 , TimeUnit.SECONDS);
  315 + }
269 316 }
... ...
src/main/java/com/bsth/common/Constants.java
1   -package com.bsth.common;
2   -
3   -/**
4   - *
5   - * @ClassName: Constants
6   - * @Description: TODO(常量类)
7   - * @author PanZhao
8   - * @date 2016年3月18日 下午11:06:53
9   - *
10   - */
11   -public class Constants {
12   -
13   - /**
14   - * 不需要拦截的资源
15   - */
16   - public static final String LOGIN = "/user/login/**";
17   - public static final String LOGIN_PAGE = "/login.html";
18   - public static final String ASSETS_URL = "/assets/**";
19   - public static final String FAVICON_URL = "/favicon.ico";
20   - public static final String METRONIC_URL = "/metronic_v4.5.4/**";
21   - public static final String LOGIN_FAILURE = "/user/loginFailure";
22   - public static final String CAPTCHA = "/captcha.jpg";
23   -
24   - // springboot manage health的检测url
25   - public static final String ACTUATOR_MANAGEMENT_HEALTH = "/manage/health";
26   - // 车辆数据同步url
27   - public static final String VEHICLE_DATA_SYNC_URL = "/dataSync/vehicle/api/**";
28   -
29   - //对外的营运数据接口
30   - public static final String SERVICE_INTERFACE = "/companyService/**";
31   -
32   - /**
33   - * 线调部分子页面不做拦截,便于浏览器缓存
34   - */
35   - public static final String XD_CHILD_PAGES = "/real_control_v2/**";
36   - public static final String XD_REAL_GPS = "/gps/real/line";
37   - //public static final String XD_TEMPS = "/pages/control/line/temps/**";
38   -
39   - //车载网关上行接口
40   - public static final String UPSTREAM_URL = "/control/upstream";
41   - //rfid 上传入口
42   - public static final String UP_RFID_URL = "/rfid/**";
43   -
44   - public static final String SESSION_USERNAME = "sessionUserName";
45   - public static final String COMPANY_AUTHORITYS = "cmyAuths";
46   - public static final String STATION_AND_SECTION_COUNT = "/station/updateStationAndSectionCode";
47   -
48   - /**
49   - * 解除调度指令和班次的外键约束
50   - */
51   - public static final String REMOVE_DIRECTIVE_SCH_FK = "update bsth_v_directive_60 set sch=NULL where sch=?";
52   -
53   - /**
54   - * 批量解除调度指令和班次的外键约束
55   - */
56   - public static final String MULTI_REMOVE_DIRECTIVE_SCH_FK = "update bsth_v_directive_60 set sch=NULL where sch in ";
57   -
58   - /**
59   - * 批量解除子任务和班次的外键约束
60   - */
61   - public static final String MULTI_REMOVE_CHILDTASK_SCH_FK = "update bsth_c_s_child_task set schedule=NULL where schedule in ";
62   -}
  1 +package com.bsth.common;
  2 +
  3 +/**
  4 + *
  5 + * @ClassName: Constants
  6 + * @Description: TODO(常量类)
  7 + * @author PanZhao
  8 + * @date 2016年3月18日 下午11:06:53
  9 + *
  10 + */
  11 +public class Constants {
  12 +
  13 + /**
  14 + * 不需要拦截的资源
  15 + */
  16 + public static final String LOGIN = "/user/login/**";
  17 + public static final String LOGIN_PAGE = "/login.html";
  18 + public static final String ASSETS_URL = "/assets/**";
  19 + public static final String FAVICON_URL = "/favicon.ico";
  20 + public static final String METRONIC_URL = "/metronic_v4.5.4/**";
  21 + public static final String LOGIN_FAILURE = "/user/loginFailure";
  22 + public static final String CAPTCHA = "/captcha.jpg";
  23 +
  24 + // springboot manage health的检测url
  25 + public static final String ACTUATOR_MANAGEMENT_HEALTH = "/manage/health";
  26 + // 车辆数据同步url
  27 + public static final String VEHICLE_DATA_SYNC_URL = "/dataSync/vehicle/api/**";
  28 +
  29 + //对外的营运数据接口
  30 + public static final String SERVICE_INTERFACE = "/companyService/**";
  31 +
  32 + /**
  33 + * 线调部分子页面不做拦截,便于浏览器缓存
  34 + */
  35 + public static final String XD_CHILD_PAGES = "/real_control_v2/**";
  36 + public static final String XD_REAL_GPS = "/gps/real/line";
  37 + //public static final String XD_TEMPS = "/pages/control/line/temps/**";
  38 +
  39 + //车载网关上行接口
  40 + public static final String UPSTREAM_URL = "/control/upstream";
  41 + //rfid 上传入口
  42 + public static final String UP_RFID_URL = "/rfid/**";
  43 +
  44 + public static final String SESSION_USERNAME = "sessionUserName";
  45 + public static final String COMPANY_AUTHORITYS = "cmyAuths";
  46 + public static final String STATION_AND_SECTION_COUNT = "/station/updateStationAndSectionCode";
  47 +
  48 + /**
  49 + * 解除调度指令和班次的外键约束
  50 + */
  51 + public static final String REMOVE_DIRECTIVE_SCH_FK = "update bsth_v_directive_60 set sch=NULL where sch=?";
  52 +
  53 + /**
  54 + * 批量解除调度指令和班次的外键约束
  55 + */
  56 + public static final String MULTI_REMOVE_DIRECTIVE_SCH_FK = "update bsth_v_directive_60 set sch=NULL where sch in ";
  57 +
  58 + /**
  59 + * 批量解除子任务和班次的外键约束
  60 + */
  61 + public static final String MULTI_REMOVE_CHILDTASK_SCH_FK = "update bsth_c_s_child_task set schedule=NULL where schedule in ";
  62 +
  63 + public static final String WEAK_CIPHER = "weakCipher";
  64 +
  65 + public static final String FILE_AUTH = "/.well-known/pki-validation/fileauth.txt";
  66 +}
... ...
src/main/java/com/bsth/controller/realcontrol/ServiceDataInterface.java
... ... @@ -345,8 +345,8 @@ public class ServiceDataInterface {
345 345 for (Map.Entry<String, String> m : BasicData.lineCode2NameMap.entrySet()){
346 346 for (Map<String,String> emer : emergencyList){
347 347 for (Map.Entry<String,String> t : emer.entrySet()){
348   - if(m.getKey().equals(t.getKey())){
349   - emergencyListAll.add(emer); //
  348 + if (m.getKey().equals(t.getKey())) {
  349 + emergencyListAll.add(emer);
350 350 Line line = lineRepository.findById(Integer.parseInt(t.getKey())).get();
351 351 line.setName(t.getValue());
352 352 Map<String, Object> status = service.update(line);
... ...
src/main/java/com/bsth/controller/schedule/TrafficManageController.java
1   -package com.bsth.controller.schedule;
2   -
3   -import com.bsth.service.TrafficManageService;
4   -
5   -import org.springframework.beans.factory.annotation.Autowired;
6   -import org.springframework.web.bind.annotation.RequestMapping;
7   -import org.springframework.web.bind.annotation.RequestMethod;
8   -import org.springframework.web.bind.annotation.RequestParam;
9   -import org.springframework.web.bind.annotation.RestController;
10   -
11   -/**
12   - *
13   - * @author BSTH
14   - *
15   - */
16   -@RestController
17   -@RequestMapping("trmg")
18   -public class TrafficManageController {
19   -
20   - @Autowired
21   - private TrafficManageService trManageService;
22   -
23   -
24   - @RequestMapping(value = "/setXL", method = RequestMethod.GET)
25   - public String setXL(@RequestParam("ids") String ids) throws Exception {
26   - try {
27   - return trManageService.setXL(ids);
28   - } catch (Exception exp) {
29   - throw new Exception(exp.getCause());
30   - }
31   - }
32   -
33   - @RequestMapping(value = "/setXLByInUse", method = RequestMethod.GET)
34   - public String setXLByInUse(@RequestParam("inUse") String inUse) throws Exception {
35   - try {
36   - return trManageService.setXLByInUse(inUse);
37   - } catch (Exception exp) {
38   - throw new Exception(exp.getCause());
39   - }
40   - }
41   -
42   - @RequestMapping(value = "/setCL", method = RequestMethod.GET)
43   - public String setCL() throws Exception {
44   - try {
45   - return trManageService.setCL();
46   - } catch (Exception exp) {
47   - throw new Exception(exp.getCause());
48   - }
49   - }
50   -
51   - @RequestMapping(value = "/setSJ", method = RequestMethod.GET)
52   - public String setSJ() throws Exception {
53   - try {
54   - return trManageService.setSJ();
55   - } catch (Exception exp) {
56   - throw new Exception(exp.getCause());
57   - }
58   - }
59   -
60   - @RequestMapping(value = "/setLD", method = RequestMethod.GET)
61   - public String setLD() throws Exception {
62   - try {
63   - return trManageService.setLD();
64   - } catch (Exception exp) {
65   - throw new Exception(exp.getCause());
66   - }
67   - }
68   -
69   - @RequestMapping(value = "/setLDByDate", method = RequestMethod.GET)
70   - public String setLDByDate(@RequestParam("theDate") String theDate) throws Exception {
71   - try {
72   - return trManageService.setLD(theDate);
73   - } catch (Exception exp) {
74   - throw new Exception(exp.getCause());
75   - }
76   - }
77   -
78   - @RequestMapping(value = "/setLDFile", method = RequestMethod.GET)
79   - public String setLDFile() throws Exception {
80   - try {
81   - return trManageService.setLDFile();
82   - } catch (Exception exp) {
83   - throw new Exception(exp.getCause());
84   - }
85   - }
86   -
87   - @RequestMapping(value = "/setLCYH", method = RequestMethod.GET)
88   - public String setLCYH() throws Exception {
89   - try {
90   - return trManageService.setLCYH();
91   - } catch (Exception exp) {
92   - throw new Exception(exp.getCause());
93   - }
94   - }
95   -
96   - @RequestMapping(value = "/setDDRB", method = RequestMethod.GET)
97   - public String setDDRB() throws Exception {
98   - try {
99   - return trManageService.setDDRB();
100   - } catch (Exception exp) {
101   - throw new Exception(exp.getCause());
102   - }
103   - }
104   -
105   - @RequestMapping(value = "/setJHBC", method = RequestMethod.GET)
106   - public String setJHBC() throws Exception {
107   - try {
108   - return trManageService.setJHBC();
109   - } catch (Exception exp) {
110   - throw new Exception(exp.getCause());
111   - }
112   - }
113   -
114   - @RequestMapping(value = "/setJHBCByDate", method = RequestMethod.GET)
115   - public String setJHBCByDate(@RequestParam("theDate") String theDate) throws Exception {
116   - try {
117   - return trManageService.setJHBC(theDate);
118   - } catch (Exception exp) {
119   - throw new Exception(exp.getCause());
120   - }
121   - }
122   -
123   - @RequestMapping(value = "/setSKB", method = RequestMethod.GET)
124   - public String setSKB(@RequestParam("ids") String ids) throws Exception {
125   - try {
126   - return trManageService.setSKB(ids);
127   - } catch (Exception exp) {
128   - throw new Exception(exp.getCause());
129   - }
130   - }
131   -
132   - @RequestMapping(value = "/setXLPC", method = RequestMethod.GET)
133   - public String setXLPC() throws Exception {
134   - try {
135   - return trManageService.setXLPC();
136   - } catch (Exception exp) {
137   - throw new Exception(exp.getCause());
138   - }
139   - }
140   -
141   - @RequestMapping(value = "/setCS", method = RequestMethod.GET)
142   - public String setCS() throws Exception {
143   - try {
144   - return trManageService.setCS();
145   - } catch (Exception exp) {
146   - throw new Exception(exp.getCause());
147   - }
148   - }
149   -
150   - @RequestMapping(value = "/getDownLoadAllDataFile", method = RequestMethod.GET)
151   - public String getDownLoadAllDataFile() throws Exception {
152   - try {
153   - return trManageService.getDownLoadAllDataFile();
154   - } catch (Exception exp) {
155   - throw new Exception(exp.getCause());
156   - }
157   - }
158   -
159   -}
  1 +package com.bsth.controller.schedule;
  2 +
  3 +import com.bsth.service.TrafficManageService;
  4 +
  5 +import org.springframework.beans.factory.annotation.Autowired;
  6 +import org.springframework.web.bind.annotation.RequestMapping;
  7 +import org.springframework.web.bind.annotation.RequestMethod;
  8 +import org.springframework.web.bind.annotation.RequestParam;
  9 +import org.springframework.web.bind.annotation.RestController;
  10 +
  11 +/**
  12 + *
  13 + * @author BSTH
  14 + *
  15 + */
  16 +@RestController
  17 +@RequestMapping("trmg")
  18 +public class TrafficManageController {
  19 +
  20 + @Autowired
  21 + private TrafficManageService trManageService;
  22 +
  23 +
  24 + @RequestMapping(value = "/setXL", method = RequestMethod.GET)
  25 + public String setXL(@RequestParam("ids") String ids) throws Exception {
  26 + try {
  27 + return trManageService.setXL(ids);
  28 + } catch (Exception exp) {
  29 + throw new Exception(exp.getCause());
  30 + }
  31 + }
  32 +
  33 + @RequestMapping(value = "/setXLByInUse", method = RequestMethod.GET)
  34 + public String setXLByInUse(@RequestParam("inUse") String inUse) throws Exception {
  35 + try {
  36 + return trManageService.setXLByInUse(inUse);
  37 + } catch (Exception exp) {
  38 + throw new Exception(exp.getCause());
  39 + }
  40 + }
  41 +
  42 + @RequestMapping(value = "/setCL", method = RequestMethod.GET)
  43 + public String setCL() throws Exception {
  44 + try {
  45 + return trManageService.setCL();
  46 + } catch (Exception exp) {
  47 + throw new Exception(exp.getCause());
  48 + }
  49 + }
  50 +
  51 + @RequestMapping(value = "/setSJ", method = RequestMethod.GET)
  52 + public String setSJ() throws Exception {
  53 + try {
  54 + return trManageService.setSJ();
  55 + } catch (Exception exp) {
  56 + throw new Exception(exp.getCause());
  57 + }
  58 + }
  59 +
  60 + @RequestMapping(value = "/setLD", method = RequestMethod.GET)
  61 + public String setLD() throws Exception {
  62 + try {
  63 + return trManageService.setLD();
  64 + } catch (Exception exp) {
  65 + throw new Exception(exp.getCause());
  66 + }
  67 + }
  68 +
  69 + @RequestMapping(value = "/setLDByDate", method = RequestMethod.GET)
  70 + public String setLDByDate(@RequestParam("theDate") String theDate) throws Exception {
  71 + try {
  72 + return trManageService.setLD(theDate);
  73 + } catch (Exception exp) {
  74 + throw new Exception(exp.getCause());
  75 + }
  76 + }
  77 +
  78 + @RequestMapping(value = "/setLDFile", method = RequestMethod.GET)
  79 + public String setLDFile() throws Exception {
  80 + try {
  81 + return trManageService.setLDFile();
  82 + } catch (Exception exp) {
  83 + throw new Exception(exp.getCause());
  84 + }
  85 + }
  86 +
  87 + @RequestMapping(value = "/setLCYH", method = RequestMethod.GET)
  88 + public String setLCYH() throws Exception {
  89 + try {
  90 + return trManageService.setLCYH();
  91 + } catch (Exception exp) {
  92 + throw new Exception(exp.getCause());
  93 + }
  94 + }
  95 +
  96 + @RequestMapping(value = "/setDDRB", method = RequestMethod.GET)
  97 + public String setDDRB() throws Exception {
  98 + try {
  99 + return trManageService.setDDRB();
  100 + } catch (Exception exp) {
  101 + throw new Exception(exp.getCause());
  102 + }
  103 + }
  104 +
  105 + @RequestMapping(value = "/setJHBC", method = RequestMethod.GET)
  106 + public String setJHBC() throws Exception {
  107 + try {
  108 + return trManageService.setJHBC();
  109 + } catch (Exception exp) {
  110 + throw new Exception(exp.getCause());
  111 + }
  112 + }
  113 +
  114 + @RequestMapping(value = "/setJHBCByDate", method = RequestMethod.GET)
  115 + public String setJHBCByDate(@RequestParam("theDate") String theDate) throws Exception {
  116 + try {
  117 + return trManageService.setJHBC(theDate);
  118 + } catch (Exception exp) {
  119 + throw new Exception(exp.getCause());
  120 + }
  121 + }
  122 +
  123 + @RequestMapping(value = "/setSKB", method = RequestMethod.GET)
  124 + public String setSKB(@RequestParam("ids") String ids, @RequestParam("qyrqs") String qyrqs) throws Exception {
  125 + try {
  126 + return trManageService.setSKB(ids, qyrqs);
  127 + } catch (Exception exp) {
  128 + throw new Exception(exp.getCause());
  129 + }
  130 + }
  131 +
  132 + @RequestMapping(value = "/setXLPC", method = RequestMethod.GET)
  133 + public String setXLPC() throws Exception {
  134 + try {
  135 + return trManageService.setXLPC();
  136 + } catch (Exception exp) {
  137 + throw new Exception(exp.getCause());
  138 + }
  139 + }
  140 +
  141 + @RequestMapping(value = "/setCS", method = RequestMethod.GET)
  142 + public String setCS() throws Exception {
  143 + try {
  144 + return trManageService.setCS();
  145 + } catch (Exception exp) {
  146 + throw new Exception(exp.getCause());
  147 + }
  148 + }
  149 +
  150 + @RequestMapping(value = "/getDownLoadAllDataFile", method = RequestMethod.GET)
  151 + public String getDownLoadAllDataFile() throws Exception {
  152 + try {
  153 + return trManageService.getDownLoadAllDataFile();
  154 + } catch (Exception exp) {
  155 + throw new Exception(exp.getCause());
  156 + }
  157 + }
  158 +
  159 +}
... ...
src/main/java/com/bsth/controller/sys/UserController.java
1   -package com.bsth.controller.sys;
2   -
3   -import com.bsth.common.Constants;
4   -import com.bsth.common.ResponseCode;
5   -import com.bsth.controller.BaseController;
6   -import com.bsth.controller.sys.dto.CompanyData;
7   -import com.bsth.controller.sys.util.RSAUtils;
8   -import com.bsth.entity.sys.CompanyAuthority;
9   -import com.bsth.entity.sys.SysUser;
10   -import com.bsth.security.util.SecurityUtils;
11   -import com.bsth.service.sys.CompanyAuthorityService;
12   -import com.bsth.service.sys.SysUserService;
13   -import com.google.common.collect.ArrayListMultimap;
14   -import org.apache.commons.lang3.StringUtils;
15   -import org.slf4j.Logger;
16   -import org.slf4j.LoggerFactory;
17   -import org.springframework.beans.factory.annotation.Autowired;
18   -import org.springframework.security.authentication.BadCredentialsException;
19   -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
20   -import org.springframework.security.web.authentication.session.SessionAuthenticationException;
21   -import org.springframework.web.bind.annotation.RequestMapping;
22   -import org.springframework.web.bind.annotation.RequestMethod;
23   -import org.springframework.web.bind.annotation.RequestParam;
24   -import org.springframework.web.bind.annotation.RestController;
25   -
26   -import javax.servlet.http.HttpServletRequest;
27   -import javax.servlet.http.HttpSession;
28   -import java.util.*;
29   -
30   -@RestController
31   -@RequestMapping("user")
32   -public class UserController extends BaseController<SysUser, Integer> {
33   -
34   - Logger logger = LoggerFactory.getLogger(this.getClass());
35   -
36   - @Autowired
37   - SysUserService sysUserService;
38   -
39   - @Autowired
40   - CompanyAuthorityService companyAuthorityService;
41   -
42   - @RequestMapping(value = "/login/jCryptionKey")
43   - public Map<String, Object> jCryptionKey(HttpServletRequest request) {
44   - //公匙返回页面
45   - Map<String, Object> rs = new HashMap<>();
46   - rs.put("publickey", RSAUtils.generateBase64PublicKey());
47   - return rs;
48   - }
49   -
50   - @RequestMapping(value = "/getCurrentUser")
51   - public SysUser getCurrentUser() {
52   - SysUser user = SecurityUtils.getCurrentUser();
53   - return user;
54   - }
55   -
56   - //需要验证码的账号
57   - public static Map<String, Integer> captchaMap = new HashMap<>();
58   -
59   - @RequestMapping(value = "/login", method = RequestMethod.POST)
60   - public Map<String, Object> login(HttpServletRequest request, @RequestParam String userName,
61   - @RequestParam String password, String captcha) {
62   -
63   - Map<String, Object> rs = new HashMap<>();
64   - rs.put("status", ResponseCode.ERROR);
65   - try {
66   - HttpSession session = request.getSession();
67   - rs.put("captcha", session.getAttribute("captcha"));
68   -
69   - if (captchaMap.get(userName) != null && captchaMap.get(userName) >= 3) {
70   - //校验验证码
71   - String verCode = (String) session
72   - .getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
73   -
74   - if (StringUtils.isBlank(captcha))
75   - return put(rs, "msg", "请输入验证码");
76   -
77   - if (!verCode.equals(captcha))
78   - return put(rs, "msg", "验证码有误,请刷新后重新输入");
79   - }
80   -
81   - //解密RSA
82   - try {
83   - userName = RSAUtils.decryptBase64(userName);
84   - password = RSAUtils.decryptBase64(password);
85   - } catch (RuntimeException e) {
86   - return put(rs, "msg", "decrypt RSA fail!可能页面已过期,尝试刷新页面。");
87   - }
88   -
89   - SysUser user = sysUserService.findByUserName(userName);
90   - if (null == user)
91   - return put(rs, "msg", "不存在的用户");
92   -
93   - if (!user.isEnabled())
94   - return put(rs, "msg", "该用户已被锁定,请联系管理员");
95   -
96   - // 校验密码
97   - boolean matchStatus = new BCryptPasswordEncoder(4).matches(password, user.getPassword());
98   - if (!matchStatus) {
99   - rs.put("msg", "密码有误");
100   -
101   - Integer captchSize = captchaMap.get(userName);
102   - if (null == captchSize)
103   - captchSize = 0;
104   -
105   - captchSize++;
106   - captchaMap.put(userName, captchSize);
107   - return rs;
108   - }
109   -
110   - // 登录
111   - SecurityUtils.login(user, request);
112   - //session里写入用户名,webSocket连接时标识身份用
113   - session.setAttribute(Constants.SESSION_USERNAME, user.getUserName());
114   -
115   - //获取公司权限数据
116   - List<CompanyAuthority> cmyAuths = companyAuthorityService.findByUser(user);
117   - session.setAttribute(Constants.COMPANY_AUTHORITYS, cmyAuths);
118   -
119   - captchaMap.remove(userName);
120   - rs.put("status", ResponseCode.SUCCESS);
121   - logger.error("用户:" + user.getUserName() + "登录");
122   - } catch (Exception e) {
123   - logger.error("", e);
124   - rs.put("msg", "服务器出现异常,请联系管理员");
125   - }
126   - return rs;
127   - }
128   -
129   - @RequestMapping(value = "/change_user", method = RequestMethod.POST)
130   - public Map<String, Object> changeUser(HttpServletRequest request, @RequestParam String userName,
131   - @RequestParam String password) {
132   -
133   - Map<String, Object> rs = new HashMap<>();
134   - rs.put("status", ResponseCode.ERROR);
135   - try {
136   - HttpSession session = request.getSession();
137   -
138   - SysUser user = sysUserService.findByUserName(userName);
139   - if (null == user)
140   - return put(rs, "msg", "不存在的用户");
141   -
142   - if (!user.isEnabled())
143   - return put(rs, "msg", "该用户已被锁定,请联系管理员");
144   -
145   - // 校验密码
146   - boolean matchStatus = new BCryptPasswordEncoder(4).matches(password, user.getPassword());
147   - if (!matchStatus)
148   - return put(rs, "msg", "密码有误");
149   -
150   - // 登录
151   - SecurityUtils.login(user, request);
152   - //session里写入用户名,webSocket连接时标识身份用
153   - session.setAttribute(Constants.SESSION_USERNAME, user.getUserName());
154   -
155   - //获取公司权限数据
156   - List<CompanyAuthority> cmyAuths = companyAuthorityService.findByUser(user);
157   - session.setAttribute(Constants.COMPANY_AUTHORITYS, cmyAuths);
158   - rs.put("status", ResponseCode.SUCCESS);
159   - } catch (Exception e) {
160   - logger.error("", e);
161   - rs.put("msg", "服务器出现异常,请联系管理员");
162   - }
163   - return rs;
164   - }
165   -
166   - /**
167   - * 返回当前用户的公司权限数据,用于构建页面级联下拉框
168   - *
169   - * @return
170   - */
171   - @RequestMapping("companyData")
172   - public List<CompanyData> companyData(HttpServletRequest request) {
173   - List<CompanyData> rs = new ArrayList<>();
174   - CompanyData companyData;
175   -
176   - ArrayListMultimap<String, CompanyAuthority> map = ArrayListMultimap.create();
177   - List<CompanyAuthority> cmyAuths = (List<CompanyAuthority>) request.getSession().getAttribute(Constants.COMPANY_AUTHORITYS);
178   -
179   - for (CompanyAuthority cAuth : cmyAuths) {
180   - map.put(cAuth.getCompanyCode() + "_" + cAuth.getCompanyName(), cAuth);
181   - }
182   -
183   - Set<String> keys = map.keySet();
184   - String[] temps;
185   - for (String k : keys) {
186   - temps = k.split("_");
187   -
188   - companyData = new CompanyData();
189   - companyData.setCompanyCode(temps[0]);
190   - companyData.setCompanyName(temps[1]);
191   - companyData.setChildren(new ArrayList<CompanyData.ChildrenCompany>());
192   -
193   - cmyAuths = map.get(k);
194   - for (CompanyAuthority c : cmyAuths) {
195   - companyData.getChildren().add(new CompanyData.ChildrenCompany(c.getSubCompanyCode(), c.getSubCompanyName()));
196   - }
197   -
198   - rs.add(companyData);
199   - }
200   -
201   - return rs;
202   - }
203   -
204   - @RequestMapping(value = "/login/captchaStatus")
205   - public int captchaStatus(String userName) {
206   - Integer size = captchaMap.get(userName);
207   - return size == null ? 0 : size;
208   - }
209   -
210   - public Map<String, Object> put(Map<String, Object> rs, String key, Object val) {
211   - rs.put(key, val);
212   - return rs;
213   - }
214   -
215   - /**
216   - * @Title: loginFailure @Description: TODO(查询登录失败的详细信息) @param @param
217   - * request @return String 返回类型 @throws
218   - */
219   - @RequestMapping("/loginFailure")
220   - public String loginFailure(HttpServletRequest request) {
221   - String msg = "";
222   - HttpSession session = request.getSession();
223   -
224   - Object obj = session.getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
225   -
226   - if (obj instanceof BadCredentialsException)
227   - msg = "登录失败,用户名或密码错误.";
228   - else if (obj instanceof SessionAuthenticationException)
229   - msg = "登录失败,当前策略不允许重复登录.";
230   - session.removeAttribute("SPRING_SECURITY_LAST_EXCEPTION");
231   - return msg;
232   - }
233   -
234   - @RequestMapping("/currentUser")
235   - public SysUser currentUser() {
236   - return SecurityUtils.getCurrentUser();
237   - }
238   -
239   - /**
240   - * @param id 用户ID
241   - * @param enabled 状态
242   - * @return
243   - * @Title changeEnabled
244   - * @Description: TODO(改变用户状态)
245   - */
246   - @RequestMapping("/changeEnabled")
247   - public int changeEnabled(@RequestParam int id, @RequestParam int enabled) {
248   - return sysUserService.changeEnabled(id, enabled);
249   - }
250   -
251   - /**
252   - * @param oldPWD 原始密码
253   - * @param newPWD 新密码
254   - * @param cnewPWD 确认新密码
255   - * @return
256   - * @Title changePWD
257   - * @Description: TODO(修改密码)
258   - */
259   - @RequestMapping(value = "/changePWD", method = RequestMethod.POST)
260   - public String changePWD(@RequestParam String oldPWD, @RequestParam String newPWD, @RequestParam String cnewPWD) {
261   - SysUser sysUser = SecurityUtils.getCurrentUser();
262   - String msg = "";
263   -
264   - //解密RSA
265   - try{
266   - oldPWD = (RSAUtils.decryptBase64(oldPWD));
267   - newPWD = (RSAUtils.decryptBase64(newPWD));
268   - cnewPWD = (RSAUtils.decryptBase64(cnewPWD));
269   - }catch (RuntimeException e) {
270   - return "网络延迟,解密失败,请重新添加!";
271   - }
272   - if (new BCryptPasswordEncoder(4).matches(oldPWD, sysUser.getPassword())) {
273   - if (oldPWD.equals(newPWD)) {
274   - msg = "新密码不能跟原始密码一样!";
275   - } else {
276   - if (newPWD.equals(cnewPWD)) {
277   - sysUserService.changePWD(sysUser.getId(), newPWD);
278   - msg = "修改成功!";
279   - } else {
280   - msg = "新密码两次输入不一致!";
281   - }
282   - }
283   - } else {
284   - msg = "原始密码错误!";
285   - }
286   - return msg;
287   - }
288   -
289   - @RequestMapping(value = "/register", method = RequestMethod.POST)
290   - public Map<String, Object> register(SysUser u) {
291   - return sysUserService.register(u);
292   - }
293   -
294   - // 查询用户下所有下级角色
295   - @RequestMapping(value = "/all_distinct")
296   - public List<SysUser> findAll_distinct() {
297   - return sysUserService.findAll_distinct();
298   - }
299   -
300   - // 重置密码
301   - @RequestMapping(value = "/resetPassword", method = RequestMethod.POST)
302   - public Map<String, Object> resetPassword(@RequestParam Integer id) {
303   - return sysUserService.resetPassword(id);
304   - }
305   -
306   -}
  1 +package com.bsth.controller.sys;
  2 +
  3 +import com.bsth.common.Constants;
  4 +import com.bsth.common.ResponseCode;
  5 +import com.bsth.controller.BaseController;
  6 +import com.bsth.controller.sys.dto.CompanyData;
  7 +import com.bsth.controller.sys.util.RSAUtils;
  8 +import com.bsth.email.entity.EmailBean;
  9 +import com.bsth.entity.sys.CompanyAuthority;
  10 +import com.bsth.entity.sys.Role;
  11 +import com.bsth.entity.sys.SysUser;
  12 +import com.bsth.security.util.SecurityUtils;
  13 +import com.bsth.service.sys.CompanyAuthorityService;
  14 +import com.bsth.service.sys.SysUserService;
  15 +import com.bsth.service.sys.impl.PwdGenerator;
  16 +import com.bsth.util.IpUtils;
  17 +import com.google.common.collect.ArrayListMultimap;
  18 +import org.apache.commons.lang3.StringUtils;
  19 +import org.slf4j.Logger;
  20 +import org.slf4j.LoggerFactory;
  21 +import org.springframework.beans.factory.annotation.Autowired;
  22 +import org.springframework.security.authentication.BadCredentialsException;
  23 +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  24 +import org.springframework.security.web.authentication.session.SessionAuthenticationException;
  25 +import org.springframework.web.bind.annotation.RequestMapping;
  26 +import org.springframework.web.bind.annotation.RequestMethod;
  27 +import org.springframework.web.bind.annotation.RequestParam;
  28 +import org.springframework.web.bind.annotation.RestController;
  29 +
  30 +import javax.servlet.http.HttpServletRequest;
  31 +import javax.servlet.http.HttpSession;
  32 +import java.util.*;
  33 +import java.util.regex.Matcher;
  34 +import java.util.regex.Pattern;
  35 +
  36 +@RestController
  37 +@RequestMapping("user")
  38 +public class UserController extends BaseController<SysUser, Integer> {
  39 +
  40 + Logger logger = LoggerFactory.getLogger(this.getClass());
  41 +
  42 + @Autowired
  43 + SysUserService sysUserService;
  44 +
  45 + @Autowired
  46 + CompanyAuthorityService companyAuthorityService;
  47 +
  48 + private Pattern pattern = Pattern.compile("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*?[#?!@$%^&*-.]).{8,16}$");
  49 +
  50 + @RequestMapping(value = "/login/jCryptionKey")
  51 + public Map<String, Object> jCryptionKey(HttpServletRequest request) {
  52 + //公匙返回页面
  53 + Map<String, Object> rs = new HashMap<>();
  54 + rs.put("publickey", RSAUtils.generateBase64PublicKey());
  55 + return rs;
  56 + }
  57 +
  58 + @RequestMapping(value = "/getCurrentUser")
  59 + public SysUser getCurrentUser() {
  60 + SysUser user = SecurityUtils.getCurrentUser();
  61 + return user;
  62 + }
  63 +
  64 + //需要验证码的账号
  65 + public static Map<String, Integer> USER_ERRTIMES = new HashMap<>();
  66 + public static Map<String, Long> USER_LOCKTIME = new HashMap<>();
  67 +
  68 + @RequestMapping(value = "/login", method = RequestMethod.POST)
  69 + public Map<String, Object> login(HttpServletRequest request, @RequestParam String userName,
  70 + @RequestParam String password, String captcha) {
  71 +
  72 + Map<String, Object> rs = new HashMap<>();
  73 + rs.put("status", ResponseCode.ERROR);
  74 + try {
  75 + HttpSession session = request.getSession();
  76 + rs.put("captcha", session.getAttribute("captcha"));
  77 +
  78 + //解密RSA
  79 + try {
  80 + userName = RSAUtils.decryptBase64(userName);
  81 + password = RSAUtils.decryptBase64(password);
  82 + } catch (RuntimeException e) {
  83 + return put(rs, "msg", "decrypt RSA fail!可能页面已过期,尝试刷新页面。");
  84 + }
  85 +
  86 + SysUser user = sysUserService.findByUserName(userName);
  87 +
  88 + // 校验用户状态
  89 + if (!user.isEnabled()) {
  90 + return put(rs, "msg", "该用户已被锁定,请联系管理员");
  91 + }
  92 +
  93 + // 校验临时状态
  94 + if (USER_LOCKTIME.get(userName) != null && USER_LOCKTIME.get(userName) >= System.currentTimeMillis()) {
  95 + return put(rs, "msg", "您的账户因密码错误次数过多,处于锁定状态中");
  96 + }
  97 +
  98 + // 校验验证码
  99 + if (USER_ERRTIMES.get(userName) != null && USER_ERRTIMES.get(userName) > 1) {
  100 + String verCode = (String) session.getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
  101 + if (StringUtils.isBlank(captcha)) {
  102 + return put(rs, "msg", "请输入验证码");
  103 + }
  104 + if (!verCode.equals(captcha)) {
  105 + return put(rs, "msg", "验证码有误,请刷新后重新输入");
  106 + }
  107 + }
  108 +
  109 + // 校验密码
  110 + boolean matchStatus = new BCryptPasswordEncoder(4).matches(password, user.getPassword());
  111 + if (null == user || !matchStatus) {
  112 + rs.put("msg", "密码有误");
  113 +
  114 + Integer errTimes = USER_ERRTIMES.get(userName);
  115 + if (null == errTimes) {
  116 + errTimes = 0;
  117 + }
  118 + USER_ERRTIMES.put(userName, ++errTimes);
  119 + if (errTimes > 3) {
  120 + USER_LOCKTIME.put(userName, System.currentTimeMillis() + 600000);
  121 + USER_ERRTIMES.put(userName, 0);
  122 + put(rs, "msg", "密码错误4次,账户将被锁定10分钟");
  123 + }
  124 +
  125 + return rs;
  126 + }
  127 +
  128 + // 弱密码检查
  129 + Matcher matcher = pattern.matcher(password);
  130 + if (!matcher.matches()) {
  131 + session.setAttribute(Constants.WEAK_CIPHER, 1);
  132 + }
  133 +
  134 + // 登录
  135 + SecurityUtils.login(user, request);
  136 + sysUserService.recordLoginDate(userName);
  137 + //session里写入用户名,webSocket连接时标识身份用
  138 + session.setAttribute(Constants.SESSION_USERNAME, user.getUserName());
  139 +
  140 + //获取公司权限数据
  141 + List<CompanyAuthority> cmyAuths = companyAuthorityService.findByUser(user);
  142 + session.setAttribute(Constants.COMPANY_AUTHORITYS, cmyAuths);
  143 +
  144 + USER_ERRTIMES.remove(userName);
  145 + rs.put("status", ResponseCode.SUCCESS);
  146 + logger.error("用户:" + user.getUserName() + "登录");
  147 + } catch (Exception e) {
  148 + logger.error("", e);
  149 + rs.put("msg", "服务器出现异常,请联系管理员");
  150 + }
  151 + return rs;
  152 + }
  153 +
  154 + @RequestMapping(value = "/change_user", method = RequestMethod.POST)
  155 + public Map<String, Object> changeUser(HttpServletRequest request, @RequestParam String userName,
  156 + @RequestParam String password) {
  157 +
  158 + Map<String, Object> rs = new HashMap<>();
  159 + rs.put("status", ResponseCode.ERROR);
  160 + try {
  161 + HttpSession session = request.getSession();
  162 +
  163 + SysUser user = sysUserService.findByUserName(userName);
  164 + if (null == user)
  165 + return put(rs, "msg", "不存在的用户");
  166 +
  167 + if (!user.isEnabled())
  168 + return put(rs, "msg", "该用户已被锁定,请联系管理员");
  169 +
  170 + // 校验密码
  171 + boolean matchStatus = new BCryptPasswordEncoder(4).matches(password, user.getPassword());
  172 + if (!matchStatus)
  173 + return put(rs, "msg", "密码有误");
  174 +
  175 + // 登录
  176 + SecurityUtils.login(user, request);
  177 + //session里写入用户名,webSocket连接时标识身份用
  178 + session.setAttribute(Constants.SESSION_USERNAME, user.getUserName());
  179 +
  180 + //获取公司权限数据
  181 + List<CompanyAuthority> cmyAuths = companyAuthorityService.findByUser(user);
  182 + session.setAttribute(Constants.COMPANY_AUTHORITYS, cmyAuths);
  183 + rs.put("status", ResponseCode.SUCCESS);
  184 + } catch (Exception e) {
  185 + logger.error("", e);
  186 + rs.put("msg", "服务器出现异常,请联系管理员");
  187 + }
  188 + return rs;
  189 + }
  190 +
  191 + /**
  192 + * 返回当前用户的公司权限数据,用于构建页面级联下拉框
  193 + *
  194 + * @return
  195 + */
  196 + @RequestMapping("companyData")
  197 + public List<CompanyData> companyData(HttpServletRequest request) {
  198 + List<CompanyData> rs = new ArrayList<>();
  199 + CompanyData companyData;
  200 +
  201 + ArrayListMultimap<String, CompanyAuthority> map = ArrayListMultimap.create();
  202 + List<CompanyAuthority> cmyAuths = (List<CompanyAuthority>) request.getSession().getAttribute(Constants.COMPANY_AUTHORITYS);
  203 +
  204 + for (CompanyAuthority cAuth : cmyAuths) {
  205 + map.put(cAuth.getCompanyCode() + "_" + cAuth.getCompanyName(), cAuth);
  206 + }
  207 +
  208 + Set<String> keys = map.keySet();
  209 + String[] temps;
  210 + for (String k : keys) {
  211 + temps = k.split("_");
  212 +
  213 + companyData = new CompanyData();
  214 + companyData.setCompanyCode(temps[0]);
  215 + companyData.setCompanyName(temps[1]);
  216 + companyData.setChildren(new ArrayList<CompanyData.ChildrenCompany>());
  217 +
  218 + cmyAuths = map.get(k);
  219 + for (CompanyAuthority c : cmyAuths) {
  220 + companyData.getChildren().add(new CompanyData.ChildrenCompany(c.getSubCompanyCode(), c.getSubCompanyName()));
  221 + }
  222 +
  223 + rs.add(companyData);
  224 + }
  225 +
  226 + return rs;
  227 + }
  228 +
  229 + @RequestMapping(value = "/login/captchaStatus")
  230 + public int captchaStatus(String userName) {
  231 + Integer size = USER_ERRTIMES.get(userName);
  232 + return size == null ? 0 : size;
  233 + }
  234 +
  235 + public Map<String, Object> put(Map<String, Object> rs, String key, Object val) {
  236 + rs.put(key, val);
  237 + return rs;
  238 + }
  239 +
  240 + /**
  241 + * @Title: loginFailure @Description: TODO(查询登录失败的详细信息) @param @param
  242 + * request @return String 返回类型 @throws
  243 + */
  244 + @RequestMapping("/loginFailure")
  245 + public String loginFailure(HttpServletRequest request) {
  246 + String msg = "";
  247 + HttpSession session = request.getSession();
  248 +
  249 + Object obj = session.getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
  250 +
  251 + if (obj instanceof BadCredentialsException)
  252 + msg = "登录失败,用户名或密码错误.";
  253 + else if (obj instanceof SessionAuthenticationException)
  254 + msg = "登录失败,当前策略不允许重复登录.";
  255 + session.removeAttribute("SPRING_SECURITY_LAST_EXCEPTION");
  256 + return msg;
  257 + }
  258 +
  259 + @RequestMapping("/currentUser")
  260 + public SysUser currentUser() {
  261 + return SecurityUtils.getCurrentUser();
  262 + }
  263 +
  264 + /**
  265 + * @param id 用户ID
  266 + * @param enabled 状态
  267 + * @return
  268 + * @Title changeEnabled
  269 + * @Description: TODO(改变用户状态)
  270 + */
  271 + @RequestMapping("/changeEnabled")
  272 + public int changeEnabled(@RequestParam int id, @RequestParam int enabled) {
  273 + return sysUserService.changeEnabled(id, enabled);
  274 + }
  275 +
  276 + /**
  277 + * @param oldPWD 原始密码
  278 + * @param newPWD 新密码
  279 + * @param cnewPWD 确认新密码
  280 + * @return
  281 + * @Title changePWD
  282 + * @Description: TODO(修改密码)
  283 + */
  284 + @RequestMapping(value = "/changePWD", method = RequestMethod.POST)
  285 + public String changePWD(@RequestParam String oldPWD, @RequestParam String newPWD, @RequestParam String cnewPWD, HttpServletRequest request) {
  286 + SysUser sysUser = SecurityUtils.getCurrentUser();
  287 + String msg = "";
  288 +
  289 + //解密RSA
  290 + try{
  291 + oldPWD = (RSAUtils.decryptBase64(oldPWD));
  292 + newPWD = (RSAUtils.decryptBase64(newPWD));
  293 + cnewPWD = (RSAUtils.decryptBase64(cnewPWD));
  294 + }catch (RuntimeException e) {
  295 + return "网络延迟,解密失败,请重新添加!";
  296 + }
  297 + if (new BCryptPasswordEncoder(4).matches(oldPWD, sysUser.getPassword())) {
  298 + if (oldPWD.equals(newPWD)) {
  299 + msg = "新密码不能跟原始密码一样!";
  300 + } else {
  301 + if (newPWD.equals(cnewPWD)) {
  302 + sysUserService.changePWD(sysUser.getId(), newPWD);
  303 + request.getSession().setAttribute(Constants.WEAK_CIPHER, 0);
  304 + msg = "修改成功!";
  305 + } else {
  306 + msg = "新密码两次输入不一致!";
  307 + }
  308 + }
  309 + } else {
  310 + msg = "原始密码错误!";
  311 + }
  312 + return msg;
  313 + }
  314 +
  315 + @RequestMapping(value = "/register", method = RequestMethod.POST)
  316 + public Map<String, Object> register(SysUser u) {
  317 + return sysUserService.register(u);
  318 + }
  319 +
  320 + // 查询用户下所有下级角色
  321 + @RequestMapping(value = "/all_distinct")
  322 + public List<SysUser> findAll_distinct() {
  323 + return sysUserService.findAll_distinct();
  324 + }
  325 +
  326 + // 重置密码
  327 + @RequestMapping(value = "/resetPassword", method = RequestMethod.POST)
  328 + public Map<String, Object> resetPassword(@RequestParam Integer id) {
  329 + return sysUserService.resetPassword(id);
  330 + }
  331 +
  332 + /**
  333 + * 解除临时锁定
  334 + * @param userName
  335 + * @return
  336 + */
  337 + @RequestMapping(value = "/unlock", method = RequestMethod.POST)
  338 + public Map<String, Object> unlock(@RequestParam String userName) {
  339 + Map<String, Object> result = new HashMap<>();
  340 + // 获取当前用户
  341 + SysUser user = SecurityUtils.getCurrentUser();
  342 + Iterator<Role> itRole = user.getRoles().iterator();
  343 + Role ro = new Role();
  344 + boolean isSuper = false;
  345 + while (itRole.hasNext()) {//判断是否有下一个
  346 + ro = itRole.next();
  347 + if (ro.getLevel() == 1) {
  348 + isSuper = true;
  349 + }
  350 + }
  351 + if (isSuper) {
  352 + USER_LOCKTIME.remove(userName);
  353 + USER_ERRTIMES.remove(userName);
  354 + result.put("status", ResponseCode.SUCCESS);
  355 + result.put("msg", "用户解锁成功!");
  356 + } else {
  357 + result.put("status", ResponseCode.ERROR);
  358 + result.put("msg", "您不是管理员无用户解锁权限");
  359 + }
  360 +
  361 + return result;
  362 + }
  363 +
  364 + /**
  365 + * 解除临时锁定
  366 + * @param request
  367 + * @return
  368 + */
  369 + @RequestMapping(value = "/isWeakCipher", method = RequestMethod.POST)
  370 + public Map<String, Object> isWeakCipher(HttpServletRequest request) {
  371 + Map<String, Object> result = new HashMap<>();
  372 + result.put("status", ResponseCode.SUCCESS);
  373 + result.put("data", request.getSession().getAttribute(Constants.WEAK_CIPHER));
  374 +
  375 + return result;
  376 + }
  377 +
  378 +}
... ...
src/main/java/com/bsth/entity/sys/SysUser.java
1 1 package com.bsth.entity.sys;
2 2  
  3 +import com.fasterxml.jackson.annotation.JsonIgnore;
3 4 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4 5  
5 6 import javax.persistence.*;
... ... @@ -25,13 +26,16 @@ public class SysUser implements Serializable {
25 26 private String userName;
26 27  
27 28 private String name;
28   -
  29 +
  30 + @JsonIgnore
29 31 private String password;
30 32  
31 33 @Column(updatable = false, name = "create_date", columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
32 34 private Date createDate;
  35 +
  36 + @Column(name = "update_date", columnDefinition = "timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
  37 + private Date updateDate;
33 38  
34   - @Column(name = "last_loginDate", columnDefinition = "timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
35 39 private Date lastLoginDate;
36 40  
37 41 private String agencies;
... ... @@ -74,6 +78,14 @@ public class SysUser implements Serializable {
74 78 this.createDate = createDate;
75 79 }
76 80  
  81 + public Date getUpdateDate() {
  82 + return updateDate;
  83 + }
  84 +
  85 + public void setUpdateDate(Date updateDate) {
  86 + this.updateDate = updateDate;
  87 + }
  88 +
77 89 public Date getLastLoginDate() {
78 90 return lastLoginDate;
79 91 }
... ...
src/main/java/com/bsth/filter/BaseFilter.java
1   -package com.bsth.filter;
2   -
3   -import com.bsth.common.Constants;
4   -import org.springframework.util.AntPathMatcher;
5   -import org.springframework.util.PathMatcher;
6   -
7   -import javax.servlet.*;
8   -import javax.servlet.http.HttpServletRequest;
9   -import javax.servlet.http.HttpServletResponse;
10   -import java.io.IOException;
11   -
12   -public abstract class BaseFilter implements Filter {
13   -
14   - private final PathMatcher pathMatcher = new AntPathMatcher();
15   -
16   - /**
17   - * 白名单
18   - */
19   - private String[] whiteListURLs = { Constants.LOGIN_PAGE,Constants.CAPTCHA, Constants.SERVICE_INTERFACE,
20   - Constants.ASSETS_URL, Constants.FAVICON_URL, Constants.METRONIC_URL, Constants.LOGIN, Constants.LOGIN_FAILURE, Constants.UPSTREAM_URL, Constants.XD_CHILD_PAGES, Constants.XD_REAL_GPS, Constants.UP_RFID_URL, Constants.STATION_AND_SECTION_COUNT, Constants.ACTUATOR_MANAGEMENT_HEALTH,
21   - Constants.VEHICLE_DATA_SYNC_URL };
22   -
23   - @Override
24   - public void destroy() {
25   -
26   - }
27   -
28   - @Override
29   - public void doFilter(ServletRequest request, ServletResponse response,
30   - FilterChain chain) throws IOException, ServletException {
31   -
32   - HttpServletRequest httpRequest = (HttpServletRequest) request;
33   - HttpServletResponse httpResponse = (HttpServletResponse) response;
34   -
35   - String currentURL = httpRequest.getServletPath();
36   -
37   - if (isWhiteURL(currentURL)) {
38   - chain.doFilter(request, response);
39   - return;
40   - }
41   -
42   - doFilter(httpRequest, httpResponse, chain);
43   - return;
44   - }
45   -
46   - public void doFilter(HttpServletRequest request,
47   - HttpServletResponse response, FilterChain chain)
48   - throws IOException, ServletException {
49   - chain.doFilter(request, response);
50   - }
51   -
52   - @Override
53   - public void init(FilterConfig arg0) throws ServletException {
54   -
55   - }
56   -
57   - private boolean isWhiteURL(String currentURL) {
58   - for (String whiteURL : whiteListURLs) {
59   - if (pathMatcher.match(whiteURL, currentURL)) {
60   - return true;
61   - }
62   - }
63   - return false;
64   - }
65   -}
  1 +package com.bsth.filter;
  2 +
  3 +import com.bsth.common.Constants;
  4 +import org.springframework.util.AntPathMatcher;
  5 +import org.springframework.util.PathMatcher;
  6 +
  7 +import javax.servlet.*;
  8 +import javax.servlet.http.HttpServletRequest;
  9 +import javax.servlet.http.HttpServletResponse;
  10 +import java.io.IOException;
  11 +
  12 +public abstract class BaseFilter implements Filter {
  13 +
  14 + private final PathMatcher pathMatcher = new AntPathMatcher();
  15 +
  16 + /**
  17 + * 白名单
  18 + */
  19 + private String[] whiteListURLs = { Constants.LOGIN_PAGE,Constants.CAPTCHA, Constants.SERVICE_INTERFACE,
  20 + Constants.ASSETS_URL, Constants.FAVICON_URL, Constants.METRONIC_URL, Constants.LOGIN, Constants.LOGIN_FAILURE,
  21 + Constants.UPSTREAM_URL, Constants.XD_CHILD_PAGES, Constants.XD_REAL_GPS, Constants.UP_RFID_URL,
  22 + Constants.STATION_AND_SECTION_COUNT, Constants.ACTUATOR_MANAGEMENT_HEALTH, Constants.VEHICLE_DATA_SYNC_URL,
  23 + Constants.FILE_AUTH};
  24 +
  25 + @Override
  26 + public void destroy() {
  27 +
  28 + }
  29 +
  30 + @Override
  31 + public void doFilter(ServletRequest request, ServletResponse response,
  32 + FilterChain chain) throws IOException, ServletException {
  33 +
  34 + HttpServletRequest httpRequest = (HttpServletRequest) request;
  35 + HttpServletResponse httpResponse = (HttpServletResponse) response;
  36 +
  37 + String currentURL = httpRequest.getServletPath();
  38 +
  39 + if (isWhiteURL(currentURL)) {
  40 + chain.doFilter(request, response);
  41 + return;
  42 + }
  43 +
  44 + doFilter(httpRequest, httpResponse, chain);
  45 + return;
  46 + }
  47 +
  48 + public void doFilter(HttpServletRequest request,
  49 + HttpServletResponse response, FilterChain chain)
  50 + throws IOException, ServletException {
  51 + chain.doFilter(request, response);
  52 + }
  53 +
  54 + @Override
  55 + public void init(FilterConfig arg0) throws ServletException {
  56 +
  57 + }
  58 +
  59 + private boolean isWhiteURL(String currentURL) {
  60 + for (String whiteURL : whiteListURLs) {
  61 + if (pathMatcher.match(whiteURL, currentURL)) {
  62 + return true;
  63 + }
  64 + }
  65 + return false;
  66 + }
  67 +}
... ...
src/main/java/com/bsth/repository/sys/SysUserRepository.java
1   -package com.bsth.repository.sys;
2   -
3   -import com.bsth.entity.sys.SysUser;
4   -import com.bsth.repository.BaseRepository;
5   -import org.springframework.data.jpa.repository.EntityGraph;
6   -import org.springframework.data.jpa.repository.Modifying;
7   -import org.springframework.data.jpa.repository.Query;
8   -import org.springframework.stereotype.Repository;
9   -import org.springframework.transaction.annotation.Transactional;
10   -
11   -import java.util.List;
12   -
13   -@Repository
14   -public interface SysUserRepository extends BaseRepository<SysUser, Integer>{
15   -
16   - SysUser findByUserName(String userName);
17   -
18   - @Transactional
19   - @Modifying
20   - @Query(value="update bsth_c_sys_user set enabled=?2 where id=?1",nativeQuery=true)
21   - int changeEnabled(int id,int enabled);
22   -
23   - @Transactional
24   - @Modifying
25   - @Query(value="update bsth_c_sys_user set password=?2 where id=?1",nativeQuery=true)
26   - int changePWD(int id,String newPWD);
27   -
28   - @EntityGraph(value = "sysUser_role", type = EntityGraph.EntityGraphType.FETCH)
29   - @Query(value = "select DISTINCT u from SysUser u")
30   - List<SysUser> findAll_distinct();
31   -}
  1 +package com.bsth.repository.sys;
  2 +
  3 +import com.bsth.entity.sys.SysUser;
  4 +import com.bsth.repository.BaseRepository;
  5 +import org.springframework.data.jpa.repository.EntityGraph;
  6 +import org.springframework.data.jpa.repository.Modifying;
  7 +import org.springframework.data.jpa.repository.Query;
  8 +import org.springframework.stereotype.Repository;
  9 +import org.springframework.transaction.annotation.Transactional;
  10 +
  11 +import java.util.List;
  12 +
  13 +@Repository
  14 +public interface SysUserRepository extends BaseRepository<SysUser, Integer>{
  15 +
  16 + SysUser findByUserName(String userName);
  17 +
  18 + @Transactional
  19 + @Modifying
  20 + @Query(value="update bsth_c_sys_user set enabled=?2 where id=?1",nativeQuery=true)
  21 + int changeEnabled(int id,int enabled);
  22 +
  23 + @Transactional
  24 + @Modifying
  25 + @Query(value="update bsth_c_sys_user set password=?2 where id=?1",nativeQuery=true)
  26 + int changePWD(int id,String newPWD);
  27 +
  28 + @EntityGraph(value = "sysUser_role", type = EntityGraph.EntityGraphType.FETCH)
  29 + @Query(value = "select DISTINCT u from SysUser u")
  30 + List<SysUser> findAll_distinct();
  31 +
  32 + @Modifying
  33 + @Query(value="update bsth_c_sys_user set last_login_date=now() where user_name=?1",nativeQuery=true)
  34 + void recordLoginDate(String userName);
  35 +}
... ...
src/main/java/com/bsth/security/WebSecurityConfig.java
... ... @@ -38,7 +38,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
38 38 public void configure(WebSecurity web) throws Exception {
39 39 // 白名单
40 40 web.ignoring().antMatchers(Constants.LOGIN_PAGE, Constants.LOGIN, Constants.ASSETS_URL, Constants.FAVICON_URL, Constants.CAPTCHA,
41   - Constants.SERVICE_INTERFACE, Constants.METRONIC_URL, Constants.LOGIN_FAILURE, Constants.UPSTREAM_URL, Constants.XD_CHILD_PAGES, Constants.UP_RFID_URL,Constants.STATION_AND_SECTION_COUNT);
  41 + Constants.SERVICE_INTERFACE, Constants.METRONIC_URL, Constants.LOGIN_FAILURE, Constants.UPSTREAM_URL, Constants.XD_CHILD_PAGES,
  42 + Constants.UP_RFID_URL, Constants.STATION_AND_SECTION_COUNT, Constants.FILE_AUTH);
42 43 }
43 44  
44 45 @Override
... ...
src/main/java/com/bsth/security/filter/LoginInterceptor.java
... ... @@ -33,8 +33,9 @@ public class LoginInterceptor implements Filter {
33 33 * 相比于 BaseFilter,此处对线调GPS请求进行了拦截验证
34 34 */
35 35 private String[] whiteListURLs = { Constants.LOGIN_PAGE,Constants.CAPTCHA, Constants.SERVICE_INTERFACE,
36   - Constants.ASSETS_URL, Constants.FAVICON_URL, Constants.METRONIC_URL, Constants.LOGIN, Constants.LOGIN_FAILURE, Constants.UPSTREAM_URL, Constants.XD_CHILD_PAGES, Constants.UP_RFID_URL,Constants.STATION_AND_SECTION_COUNT,
37   - Constants.VEHICLE_DATA_SYNC_URL };
  36 + Constants.ASSETS_URL, Constants.FAVICON_URL, Constants.METRONIC_URL, Constants.LOGIN,
  37 + Constants.LOGIN_FAILURE, Constants.UPSTREAM_URL, Constants.XD_CHILD_PAGES, Constants.UP_RFID_URL,
  38 + Constants.STATION_AND_SECTION_COUNT, Constants.VEHICLE_DATA_SYNC_URL, Constants.FILE_AUTH };
38 39  
39 40  
40 41 @Override
... ...
src/main/java/com/bsth/service/TrafficManageService.java
1   -package com.bsth.service;
2   -
3   -/**
4   - *
5   - * @Interface: LineService(线路service业务层实现接口)
6   - *
7   - * @extends : BaseService
8   - *
9   - * @Description: TODO(线路service业务层实现接口)
10   - *
11   - * @Author bsth@lq
12   - *
13   - * @Date 2016年4月28日 上午9:21:17
14   - *
15   - * @Version 公交调度系统BS版 0.1
16   - *
17   - */
18   -public interface TrafficManageService {
19   -
20   - /**
21   - * 上传线路信息
22   - *
23   - * @return 调用接口返回信息
24   - */
25   - String setXL(String ids);
26   -
27   - /**
28   - * 上传线路信息
29   - *
30   - * @return 调用接口返回信息
31   - */
32   - String setXLByInUse(String ids);
33   -
34   - /**
35   - * 上传车辆信息
36   - *
37   - * @return 调用接口返回信息
38   - */
39   - String setCL();
40   -
41   - /**
42   - * 上传司机信息
43   - * @return 调用接口返回信息
44   - */
45   - String setSJ();
46   -
47   - /**
48   - * 上传超速数据
49   - *
50   - * @return 调用接口返回信息
51   - */
52   - String setCS();
53   -
54   - /**
55   - * 上传线路班次时刻表数据
56   - *
57   - * @return 调用接口返回信息
58   - */
59   - String setSKB(String ids);
60   -
61   - /**
62   - * 线路人员车辆配置信息
63   - * @return 调用接口返回信息
64   - */
65   - String setXLPC();
66   -
67   - /**
68   - * 线路计划班次表
69   - * @return 调用接口返回信息
70   - */
71   - String setJHBC();
72   -
73   - String setJHBC(String theDate);
74   -
75   - String setLD(String theDate);
76   -
77   - String setLD();
78   -
79   - String setLDFile();
80   -
81   - String setLCYH();
82   -
83   - String setDDRB();
84   -
85   - /**
86   - * 下载全量的公交基础数据
87   - * @return
88   - */
89   - String getDownLoadAllDataFile();
90   -
91   - /**
92   - * 下载增量的公交基础数据
93   - * @return
94   - */
95   - String getDownLoadIncreaseDataFile();
96   -
97   - /**
98   - * 指定线路查询方式公交基础数据下载
99   - * @return
100   - */
101   - String getDownLoadWarrantsBusLineStation();
102   -}
  1 +package com.bsth.service;
  2 +
  3 +/**
  4 + *
  5 + * @Interface: LineService(线路service业务层实现接口)
  6 + *
  7 + * @extends : BaseService
  8 + *
  9 + * @Description: TODO(线路service业务层实现接口)
  10 + *
  11 + * @Author bsth@lq
  12 + *
  13 + * @Date 2016年4月28日 上午9:21:17
  14 + *
  15 + * @Version 公交调度系统BS版 0.1
  16 + *
  17 + */
  18 +public interface TrafficManageService {
  19 +
  20 + /**
  21 + * 上传线路信息
  22 + *
  23 + * @return 调用接口返回信息
  24 + */
  25 + String setXL(String ids);
  26 +
  27 + /**
  28 + * 上传线路信息
  29 + *
  30 + * @return 调用接口返回信息
  31 + */
  32 + String setXLByInUse(String ids);
  33 +
  34 + /**
  35 + * 上传车辆信息
  36 + *
  37 + * @return 调用接口返回信息
  38 + */
  39 + String setCL();
  40 +
  41 + /**
  42 + * 上传司机信息
  43 + * @return 调用接口返回信息
  44 + */
  45 + String setSJ();
  46 +
  47 + /**
  48 + * 上传超速数据
  49 + *
  50 + * @return 调用接口返回信息
  51 + */
  52 + String setCS();
  53 +
  54 + /**
  55 + * 上传线路班次时刻表数据
  56 + *
  57 + * @return 调用接口返回信息
  58 + */
  59 + String setSKB(String ids, String qyrqs);
  60 +
  61 + /**
  62 + * 线路人员车辆配置信息
  63 + * @return 调用接口返回信息
  64 + */
  65 + String setXLPC();
  66 +
  67 + /**
  68 + * 线路计划班次表
  69 + * @return 调用接口返回信息
  70 + */
  71 + String setJHBC();
  72 +
  73 + String setJHBC(String theDate);
  74 +
  75 + String setLD(String theDate);
  76 +
  77 + String setLD();
  78 +
  79 + String setLDFile();
  80 +
  81 + String setLCYH();
  82 +
  83 + String setDDRB();
  84 +
  85 + /**
  86 + * 下载全量的公交基础数据
  87 + * @return
  88 + */
  89 + String getDownLoadAllDataFile();
  90 +
  91 + /**
  92 + * 下载增量的公交基础数据
  93 + * @return
  94 + */
  95 + String getDownLoadIncreaseDataFile();
  96 +
  97 + /**
  98 + * 指定线路查询方式公交基础数据下载
  99 + * @return
  100 + */
  101 + String getDownLoadWarrantsBusLineStation();
  102 +}
... ...
src/main/java/com/bsth/service/impl/TrafficManageServiceImpl.java
... ... @@ -19,7 +19,6 @@ import com.bsth.repository.traffic.SKBUploadLoggerRepository;
19 19 import com.bsth.security.util.SecurityUtils;
20 20 import com.bsth.service.TrafficManageService;
21 21 import com.bsth.service.traffic.YgcBasicDataService;
22   -import com.bsth.util.IpUtils;
23 22 import com.bsth.util.TimeUtils;
24 23 import com.bsth.util.db.DBUtils_MS;
25 24 import com.bsth.webService.trafficManage.org.tempuri.Results;
... ... @@ -529,7 +528,7 @@ public class TrafficManageServiceImpl implements TrafficManageService{
529 528 try {
530 529 //发送邮件
531 530 EmailBean mail = new EmailBean();
532   - mail.setSubject(IpUtils.getLocalIpAddress() +":路单日志数据"+date);
  531 + mail.setSubject(InetAddress.getLocalHost().getHostAddress()+":路单日志数据"+date);
533 532 mail.setContent("总数:" + (listGroup == null ? 0 : listGroup.size()) + "<br/>成功数:" + scount + "<br/>跳过数:" + ccount + "<br/>耗时:" + (System.currentTimeMillis() - start));
534 533 sendEmailController.sendMail(emailSendToAddress, mail);
535 534 logger.info("setLD-sendMail:邮件发送成功!");
... ... @@ -1474,8 +1473,6 @@ public class TrafficManageServiceImpl implements TrafficManageService{
1474 1473 company = "浦东南汇公交公司";
1475 1474 }else if(company.equals("青浦公交")){
1476 1475 company = "浦东青浦公交公司";
1477   - }else if(company.equals("临港公交")){
1478   - company = "临港公交公司";
1479 1476 }
1480 1477 }
1481 1478 /**
... ...
src/main/java/com/bsth/service/schedule/impl/SchedulePlanServiceImpl.java
... ... @@ -205,7 +205,7 @@ public class SchedulePlanServiceImpl extends BServiceImpl&lt;SchedulePlan, Long&gt; im
205 205  
206 206 session.fireAllRules();
207 207  
208   - session.dispose();;
  208 + session.dispose();
209 209  
210 210 return result;
211 211 }
... ...
src/main/java/com/bsth/service/sys/SysUserService.java
1   -package com.bsth.service.sys;
2   -
3   -import com.bsth.entity.sys.SysUser;
4   -import com.bsth.service.BaseService;
5   -import org.springframework.web.bind.annotation.RequestParam;
6   -
7   -import java.util.List;
8   -import java.util.Map;
9   -
10   -public interface SysUserService extends BaseService<SysUser, Integer>{
11   -
12   - SysUser findByUserName(String name);
13   -
14   - int changeEnabled(int id,int enabled);
15   -
16   - int changePWD(int id,String newPWD);
17   -
18   - Map<String,Object> register(SysUser u);
19   -
20   - List<SysUser> findAll_distinct();
21   -
22   - Map<String, Object> resetPassword(@RequestParam Integer id);
23   -}
  1 +package com.bsth.service.sys;
  2 +
  3 +import com.bsth.entity.sys.SysUser;
  4 +import com.bsth.service.BaseService;
  5 +import org.springframework.web.bind.annotation.RequestParam;
  6 +
  7 +import java.util.List;
  8 +import java.util.Map;
  9 +
  10 +public interface SysUserService extends BaseService<SysUser, Integer>{
  11 +
  12 + SysUser findByUserName(String name);
  13 +
  14 + int changeEnabled(int id,int enabled);
  15 +
  16 + int changePWD(int id,String newPWD);
  17 +
  18 + Map<String,Object> register(SysUser u);
  19 +
  20 + List<SysUser> findAll_distinct();
  21 +
  22 + Map<String, Object> resetPassword(@RequestParam Integer id);
  23 +
  24 + void recordLoginDate(String userName);
  25 +}
... ...
src/main/java/com/bsth/service/sys/impl/PwdGenerator.java 0 → 100644
  1 +package com.bsth.service.sys.impl;
  2 +
  3 +import java.util.Random;
  4 +
  5 +public class PwdGenerator {
  6 + private static final String SPECIAL_CHARS = "!@#$%^&*_=+-/";
  7 +
  8 + /**
  9 + * 查找一个char数组中还没有填充字符的位置
  10 + */
  11 + private static int nextIndex(char[] chars, Random rnd) {
  12 + int index = rnd.nextInt(chars.length);
  13 + while (chars[index] != 0) {
  14 + index = rnd.nextInt(chars.length);
  15 + }
  16 + return index;
  17 + }
  18 +
  19 + /**
  20 + * 返回一个随机的特殊字符
  21 + */
  22 + private static char nextSpecialChar(Random rnd) {
  23 + return SPECIAL_CHARS.charAt(rnd.nextInt(SPECIAL_CHARS.length()));
  24 + }
  25 +
  26 + /**
  27 + * 返回一个随机的大写字母
  28 + */
  29 + private static char nextUpperLetter(Random rnd) {
  30 + return (char) ('A' + rnd.nextInt(26));
  31 + }
  32 +
  33 + /**
  34 + * 返回一个随机的小写字母
  35 + */
  36 + private static char nextLowerLetter(Random rnd) {
  37 + return (char) ('a' + rnd.nextInt(26));
  38 + }
  39 +
  40 + /**
  41 + * 返回一个随机的数字
  42 + */
  43 + private static char nextNumLetter(Random rnd) {
  44 + return (char) ('0' + rnd.nextInt(10));
  45 + }
  46 +
  47 + /**
  48 + * 返回一个随机的字符
  49 + */
  50 + private static char nextChar(Random rnd) {
  51 + switch (rnd.nextInt(4)) {
  52 + case 0:
  53 + return (char) ('a' + rnd.nextInt(26));
  54 + case 1:
  55 + return (char) ('A' + rnd.nextInt(26));
  56 + case 2:
  57 + return (char) ('0' + rnd.nextInt(10));
  58 + default:
  59 + return SPECIAL_CHARS.charAt(rnd.nextInt(SPECIAL_CHARS.length()));
  60 + }
  61 + }
  62 +
  63 + /**
  64 + * 生成指定位数的随机数
  65 + */
  66 + public static String randomPassword(int length) {
  67 + if(length < 3){
  68 + return "";
  69 + }
  70 + char[] chars = new char[length];
  71 + Random rnd = new Random();
  72 +
  73 + //1. 至少生成一个大写字母、小写字母、特殊字符、数字
  74 + chars[nextIndex(chars, rnd)] = nextUpperLetter(rnd);
  75 + chars[nextIndex(chars, rnd)] = nextLowerLetter(rnd);
  76 + chars[nextIndex(chars, rnd)] = nextNumLetter(rnd);
  77 +
  78 + //2. 填补其他位置的字符
  79 + for (int i = 0; i < length; i++) {
  80 + if (chars[i] == 0) {
  81 + chars[i] = nextChar(rnd);
  82 + }
  83 + }
  84 +
  85 + //3. 返回结果
  86 + return new String(chars);
  87 + }
  88 +
  89 +
  90 + /**
  91 + * 测试代码
  92 + */
  93 + public static void main(String[] args) {
  94 + for (int i = 0; i < 10; i++) {
  95 + System.out.println(randomPassword(16));
  96 + }
  97 +
  98 + }
  99 +
  100 +}
... ...
src/main/java/com/bsth/service/sys/impl/SysUserServiceImpl.java
... ... @@ -2,6 +2,8 @@ package com.bsth.service.sys.impl;
2 2  
3 3 import com.bsth.common.ResponseCode;
4 4 import com.bsth.controller.sys.util.RSAUtils;
  5 +import com.bsth.email.SendEmailController;
  6 +import com.bsth.email.entity.EmailBean;
5 7 import com.bsth.entity.sys.Role;
6 8 import com.bsth.entity.sys.SysUser;
7 9 import com.bsth.repository.sys.SysUserRepository;
... ... @@ -9,6 +11,8 @@ import com.bsth.security.util.SecurityUtils;
9 11 import com.bsth.service.impl.BaseServiceImpl;
10 12 import com.bsth.service.sys.RoleService;
11 13 import com.bsth.service.sys.SysUserService;
  14 +import com.bsth.util.IpUtils;
  15 +import com.bsth.util.MailUtils;
12 16 import com.google.gson.Gson;
13 17 import com.google.gson.reflect.TypeToken;
14 18 import org.slf4j.Logger;
... ... @@ -16,6 +20,7 @@ import org.slf4j.LoggerFactory;
16 20 import org.springframework.beans.factory.annotation.Autowired;
17 21 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
18 22 import org.springframework.stereotype.Service;
  23 +import org.springframework.transaction.annotation.Transactional;
19 24 import org.springframework.web.bind.annotation.RequestParam;
20 25  
21 26 import java.util.ArrayList;
... ... @@ -33,6 +38,10 @@ public class SysUserServiceImpl extends BaseServiceImpl&lt;SysUser, Integer&gt; implem
33 38 @Autowired
34 39 RoleService roleService;
35 40  
  41 + // 发送邮件
  42 + @Autowired
  43 + private MailUtils mailUtils;
  44 +
36 45 Logger logger = LoggerFactory.getLogger(this.getClass());
37 46  
38 47 @Override
... ... @@ -166,12 +175,19 @@ public class SysUserServiceImpl extends BaseServiceImpl&lt;SysUser, Integer&gt; implem
166 175 Legality = true;
167 176 }
168 177 if(Legality){
169   - sysUserRepository.changePWD(id,new BCryptPasswordEncoder(4).encode("123456"));
  178 + String pwd = PwdGenerator.randomPassword(16);
  179 + sysUserRepository.changePWD(id,new BCryptPasswordEncoder(4).encode(pwd));
  180 + //发送邮件
  181 + EmailBean mail = new EmailBean();
  182 + mail.setSubject(IpUtils.getLocalIpAddress() +":密码重置");
  183 + mail.setContent(pwd);
  184 + mailUtils.sendMail(mail);
  185 + logger.info("setLD-sendMail:邮件发送成功!");
170 186 rs.put("status", ResponseCode.SUCCESS);
171 187 rs.put("msg", "密码重置成功!");
172 188 }else {
173 189 rs.put("status", ResponseCode.ERROR);
174   - rs.put("msg", "您不是超级管理员无权限重置其他用户密码");
  190 + rs.put("msg", "您不是管理员无权限重置其他用户密码");
175 191 }
176 192 }catch (Exception e){
177 193 logger.error("", e);
... ... @@ -180,4 +196,10 @@ public class SysUserServiceImpl extends BaseServiceImpl&lt;SysUser, Integer&gt; implem
180 196 }
181 197 return rs;
182 198 }
  199 +
  200 + @Override
  201 + @Transactional(rollbackFor = Exception.class)
  202 + public void recordLoginDate(String userName) {
  203 + sysUserRepository.recordLoginDate(userName);
  204 + }
183 205 }
... ...
src/main/java/com/bsth/util/MailUtils.java 0 → 100644
  1 +package com.bsth.util;
  2 +
  3 +import com.bsth.email.SimpleMailSender;
  4 +import com.bsth.email.entity.EmailBean;
  5 +import org.springframework.beans.factory.annotation.Value;
  6 +import org.springframework.stereotype.Component;
  7 +
  8 +import java.util.List;
  9 +
  10 +/**
  11 + * @author Hill
  12 + */
  13 +@Component
  14 +public class MailUtils {
  15 +
  16 + @Value("${admin.mail}")
  17 + private String emailSendToAddress;
  18 +
  19 + private Tools tools = new Tools("mailbox.properties");
  20 +
  21 + private SimpleMailSender sms = new SimpleMailSender(tools.getValue("username"),tools.getValue("password"));
  22 +
  23 + public String getEmailSendToAddress() {
  24 + return emailSendToAddress;
  25 + }
  26 +
  27 + public void setEmailSendToAddress(String emailSendToAddress) {
  28 + this.emailSendToAddress = emailSendToAddress;
  29 + }
  30 +
  31 + /**
  32 + * recipients
  33 + * 收件人集合
  34 + * mail
  35 + * 邮件
  36 + */
  37 + public int sendMail(List<String> recipients, EmailBean mail){
  38 + try {
  39 + for (String recipient : recipients) {
  40 + sms.send(recipient, mail.getSubject(),mail.getContent());
  41 + }
  42 + } catch (Exception e) {
  43 + e.printStackTrace();
  44 + return -1;
  45 + }
  46 + return 1;
  47 + }
  48 +
  49 + /**
  50 + * recipient
  51 + * 收件人
  52 + * mail
  53 + * 邮件
  54 + */
  55 + public int sendMail(String recipient,EmailBean mail){
  56 + try {
  57 + sms.send(recipient, mail.getSubject(),mail.getContent());
  58 + } catch (Exception e) {
  59 + e.printStackTrace();
  60 + return -1;
  61 + }
  62 + return 1;
  63 + }
  64 +
  65 + public int sendMail(EmailBean mail){
  66 + return sendMail(emailSendToAddress, mail);
  67 + }
  68 +}
... ...
src/main/resources/application-dev.properties
... ... @@ -52,4 +52,6 @@ ms.fl.generate=true
52 52 ## dsm ack interface
53 53 dsm.ack.url= http://211.95.61.66:9008/modules/dsmCheckTheRecord/addDsm?
54 54 ## cp ack interface
55   -cp.ack.url= http://114.80.178.12:8778/prod-api/serverApi/instructionsIssue/confirm/
56 55 \ No newline at end of file
  56 +cp.ack.url= http://114.80.178.12:8778/prod-api/serverApi/instructionsIssue/confirm/
  57 +## admin mail
  58 +admin.mail= 3090342880@qq.com
57 59 \ No newline at end of file
... ...
src/main/resources/application-prod.properties
... ... @@ -54,4 +54,6 @@ ms.fl.generate=true
54 54 ## dsm ack interface
55 55 dsm.ack.url= http://211.95.61.66:9008/modules/dsmCheckTheRecord/addDsm?
56 56 ## cp ack interface
57   -cp.ack.url= http://114.80.178.12:8778/prod-api/serverApi/instructionsIssue/confirm/
58 57 \ No newline at end of file
  58 +cp.ack.url= http://114.80.178.12:8778/prod-api/serverApi/instructionsIssue/confirm/
  59 +## admin mail
  60 +admin.mail= 3090342880@qq.com
59 61 \ No newline at end of file
... ...
src/main/resources/application-test.properties
... ... @@ -54,4 +54,6 @@ ms.fl.generate=false
54 54 ## dsm ack interface
55 55 dsm.ack.url= http://211.95.61.66:9008/modules/dsmCheckTheRecord/addDsm?
56 56 ## cp ack interface
57   -cp.ack.url= http://114.80.178.12:8778/prod-api/serverApi/instructionsIssue/confirm/
58 57 \ No newline at end of file
  58 +cp.ack.url= http://114.80.178.12:8778/prod-api/serverApi/instructionsIssue/confirm/
  59 +## admin mail
  60 +admin.mail= 3090342880@qq.com
59 61 \ No newline at end of file
... ...
src/main/resources/static/assets/css/TrafficControl.css
1   -.maplibTc {
2   - font-size: 12px;
3   - width: 253px;
4   - padding: 8px 5px 8px 8px;
5   - background: #3B3F51;
6   - position: absolute;
7   - color: white;
8   - box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0
9   - rgba(0, 0, 0, 0.19);
10   - top: 63px;
11   -}
12   -
13   -.maplibTc a {
14   - text-decoration: none;
15   -}
16   -
17   -.maplibTcColor {
18   - background: url("../img/tools_menu.png") no-repeat scroll 128px -86px
19   - transparent;
20   - font-weight: bold;
21   - margin-bottom: 9px;
22   - height: 18px;
23   -}
24   -
25   -.maplibTcUpdate {
26   - float: left;
27   - width: 13px;
28   - height: 14px;
29   - background: url(../img/tools_menu.png) no-repeat -12px -19px;
30   - margin-left: 5px;
31   - cursor: pointer;
32   - margin-top: 2px;
33   -}
34   -
35   -.maplibTcView {
36   - float: right;
37   - color: #26c281;
38   - text-decoration: none;
39   - line-height: 15px;
40   - *line-height: 18px
41   -}
42   -
43   -a.maplibTcView:hover {
44   - color: #C6DDD3;
45   -}
46   -
47   -a.maplibTcView:focus {
48   - color: #26c281;
49   -}
50   -
51   -.maplibTcCurTime {
52   - float: left;
53   - color: #ddd;
54   -}
55   -
56   -.maplibTcTime {
57   - height: 20px;
58   - padding: 5px 3px 0 0;
59   -}
60   -
61   -.maplibTcWeekDay {
62   - height: 22px;
63   - color: #6688CA;
64   - padding: 3px 0;
65   -}
66   -
67   -.maplibTcWeekDay a {
68   - color: #6688CA;
69   - padding: 3px 2px;
70   -}
71   -
72   -.maplibTcWeekDay ul {
73   - float: left;
74   - margin: 0;
75   - padding: 0;
76   -}
77   -
78   -.maplibTcWeekDay span {
79   - float: left;
80   - line-height: 23px;
81   -}
82   -
83   -.maplibTcWeekDay li {
84   - float: left;
85   - padding: 0 6px;
86   - list-style: none;
87   - line-height: 23px;
88   -}
89   -
90   -.maplibTcRule {
91   - background: url("../img/bar.png") no-repeat scroll 0 10px transparent;
92   - width: 195px;
93   - float: left;
94   - margin-left: 20px;
95   - *margin-left: 10px;
96   -}
97   -
98   -.maplibTcRuleTxt {
99   - float: left;
100   - line-height: 44px;
101   -}
102   -
103   -.maplibTcClear {
104   - clear: both;
105   -}
106   -
107   -.maplibTcTimeBox {
108   - color: #6688CA;
109   - margin-left: 137.5px;
110   - font-size: 11px;
111   - overflow: hidden;
112   -}
113   -
114   -.maplibTcTimeline {
115   - height: 34px;
116   -}
117   -
118   -.maplibTcTimelinePrev {
119   - overflow: hidden;
120   - width: 9px;
121   - height: 9px;
122   - cursor: pointer;
123   - float: left;
124   - margin-top: 3px
125   -}
126   -
127   -.maplibTcTimelineNext {
128   - overflow: hidden;
129   - width: 11px;
130   - *width: 10px;
131   - height: 9px;
132   - cursor: pointer;
133   - float: right;
134   - margin-top: 3px
135   -}
136   -
137   -.maplibTcTimeMove {
138   - width: 9px;
139   - height: 18px;
140   - background: url("../img/tools_menu.png") no-repeat scroll 0pt -32px
141   - transparent;
142   - float: left;
143   - cursor: pointer;
144   - margin-left: 137.5px;
145   - margin-top: 0px;
146   -}
147   -
148   -.maplibTcHide {
149   - display: none;
150   -}
151   -
152   -.maplibTcBtn_deskTop {
153   - background: url(http://api.map.baidu.com/images/bgs.gif) no-repeat
154   - scroll 0px -271px transparent;
155   - cursor: pointer;
156   - height: 22px;
157   - width: 73px;
158   - z-index: 10;
159   - position: absolute;
160   -}
161   -
162   -.maplibTcBtn_mobile {
163   - background: url(http://api.map.baidu.com/images/traffic_bgs.png)
164   - rgba(255, 255, 255, 0.8) no-repeat scroll -30px 0px;
165   - border: 1px solid #AFAFAF;
166   - background-size: 60px 30px;
167   - cursor: pointer;
168   - height: 30px;
169   - width: 30px;
170   - z-index: 10;
171   - position: absolute;
172   -}
173   -
174   -.maplibTcBtn_deskTop {
175   - background-position: 0px -249px
176   -}
177   -
178   -.maplibTcBtnOff_mobile {
179   - background-position: 0px 0px;
180   -}
181   -
182   -.maplibTcColon {
183   - float: left;
184   -}
185   -
186   -.maplibTcOn {
187   - background: #E6EFF8;
188   -}
189   -
190   -.maplibTcClose {
191   - background: url("../img/tools_menu.png") no-repeat scroll 2px -19px
192   - transparent;
193   - border: 0 none;
194   - cursor: pointer;
195   - height: 12px;
196   - position: absolute;
197   - right: 7px;
198   - top: 9px;
199   - width: 15px;
200   -}
201   -
202   -/*s--------------交通流量-----------------*/
203   -.maplibTfctr {
204   - min-width: 9em;
205   - height: 2.2em;
206   - display: -webkit-box;
207   - -webkit-box-align: center;
208   - -webkit-border-radius: 0.3em;
209   - border: .1em solid #989898;
210   - -webkit-box-sizing: border-box;
211   - background-color: #fff;
212   - font-size: 14px;
213   -}
214   -
215   -.maplibTfctrHide {
216   - display: none;
217   -}
218   -
219   -.maplibTfctr_c {
220   - -webkit-box-flex: 1;
221   -}
222   -
223   -.maplibTfctr_status {
224   - width: 4em;
225   - margin-right: .45em;
226   -}
227   -
228   -.maplibTfctr_status span {
229   - display: inline-block;
230   - margin-left: .3em;
231   - font-size: 14px;
232   -}
233   -
234   -.maplibTfctr div,.maplibTfctr span {
235   - -webkit-box-sizing: border-box;
236   -}
237   -
238   -.maplibTfctr_l {
239   - margin: 0 .15em;
240   -}
241   -
242   -.maplibY {
243   - background: #ffae00;
244   -}
245   -
246   -.maplibR {
247   - background: #ff0000;
248   -}
249   -
250   -.maplibG {
251   - background: #1fba00;
252   -}
  1 +.maplibTc {
  2 + font-size: 12px;
  3 + width: 253px;
  4 + padding: 8px 5px 8px 8px;
  5 + background: #3B3F51;
  6 + position: absolute;
  7 + color: white;
  8 + box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0
  9 + rgba(0, 0, 0, 0.19);
  10 + top: 63px;
  11 +}
  12 +
  13 +.maplibTc a {
  14 + text-decoration: none;
  15 +}
  16 +
  17 +.maplibTcColor {
  18 + background: url("../img/tools_menu.png") no-repeat scroll 128px -86px
  19 + transparent;
  20 + font-weight: bold;
  21 + margin-bottom: 9px;
  22 + height: 18px;
  23 +}
  24 +
  25 +.maplibTcUpdate {
  26 + float: left;
  27 + width: 13px;
  28 + height: 14px;
  29 + background: url(../img/tools_menu.png) no-repeat -12px -19px;
  30 + margin-left: 5px;
  31 + cursor: pointer;
  32 + margin-top: 2px;
  33 +}
  34 +
  35 +.maplibTcView {
  36 + float: right;
  37 + color: #26c281;
  38 + text-decoration: none;
  39 + line-height: 15px;
  40 + *line-height: 18px
  41 +}
  42 +
  43 +a.maplibTcView:hover {
  44 + color: #C6DDD3;
  45 +}
  46 +
  47 +a.maplibTcView:focus {
  48 + color: #26c281;
  49 +}
  50 +
  51 +.maplibTcCurTime {
  52 + float: left;
  53 + color: #ddd;
  54 +}
  55 +
  56 +.maplibTcTime {
  57 + height: 20px;
  58 + padding: 5px 3px 0 0;
  59 +}
  60 +
  61 +.maplibTcWeekDay {
  62 + height: 22px;
  63 + color: #6688CA;
  64 + padding: 3px 0;
  65 +}
  66 +
  67 +.maplibTcWeekDay a {
  68 + color: #6688CA;
  69 + padding: 3px 2px;
  70 +}
  71 +
  72 +.maplibTcWeekDay ul {
  73 + float: left;
  74 + margin: 0;
  75 + padding: 0;
  76 +}
  77 +
  78 +.maplibTcWeekDay span {
  79 + float: left;
  80 + line-height: 23px;
  81 +}
  82 +
  83 +.maplibTcWeekDay li {
  84 + float: left;
  85 + padding: 0 6px;
  86 + list-style: none;
  87 + line-height: 23px;
  88 +}
  89 +
  90 +.maplibTcRule {
  91 + background: url("../img/bar.png") no-repeat scroll 0 10px transparent;
  92 + width: 195px;
  93 + float: left;
  94 + margin-left: 20px;
  95 + *margin-left: 10px;
  96 +}
  97 +
  98 +.maplibTcRuleTxt {
  99 + float: left;
  100 + line-height: 44px;
  101 +}
  102 +
  103 +.maplibTcClear {
  104 + clear: both;
  105 +}
  106 +
  107 +.maplibTcTimeBox {
  108 + color: #6688CA;
  109 + margin-left: 137.5px;
  110 + font-size: 11px;
  111 + overflow: hidden;
  112 +}
  113 +
  114 +.maplibTcTimeline {
  115 + height: 34px;
  116 +}
  117 +
  118 +.maplibTcTimelinePrev {
  119 + overflow: hidden;
  120 + width: 9px;
  121 + height: 9px;
  122 + cursor: pointer;
  123 + float: left;
  124 + margin-top: 3px
  125 +}
  126 +
  127 +.maplibTcTimelineNext {
  128 + overflow: hidden;
  129 + width: 11px;
  130 + *width: 10px;
  131 + height: 9px;
  132 + cursor: pointer;
  133 + float: right;
  134 + margin-top: 3px
  135 +}
  136 +
  137 +.maplibTcTimeMove {
  138 + width: 9px;
  139 + height: 18px;
  140 + background: url("../img/tools_menu.png") no-repeat scroll 0pt -32px
  141 + transparent;
  142 + float: left;
  143 + cursor: pointer;
  144 + margin-left: 137.5px;
  145 + margin-top: 0px;
  146 +}
  147 +
  148 +.maplibTcHide {
  149 + display: none;
  150 +}
  151 +
  152 +.maplibTcBtn_deskTop {
  153 + background: url(//api.map.baidu.com/images/bgs.gif) no-repeat
  154 + scroll 0px -271px transparent;
  155 + cursor: pointer;
  156 + height: 22px;
  157 + width: 73px;
  158 + z-index: 10;
  159 + position: absolute;
  160 +}
  161 +
  162 +.maplibTcBtn_mobile {
  163 + background: url(//api.map.baidu.com/images/traffic_bgs.png)
  164 + rgba(255, 255, 255, 0.8) no-repeat scroll -30px 0px;
  165 + border: 1px solid #AFAFAF;
  166 + background-size: 60px 30px;
  167 + cursor: pointer;
  168 + height: 30px;
  169 + width: 30px;
  170 + z-index: 10;
  171 + position: absolute;
  172 +}
  173 +
  174 +.maplibTcBtn_deskTop {
  175 + background-position: 0px -249px
  176 +}
  177 +
  178 +.maplibTcBtnOff_mobile {
  179 + background-position: 0px 0px;
  180 +}
  181 +
  182 +.maplibTcColon {
  183 + float: left;
  184 +}
  185 +
  186 +.maplibTcOn {
  187 + background: #E6EFF8;
  188 +}
  189 +
  190 +.maplibTcClose {
  191 + background: url("../img/tools_menu.png") no-repeat scroll 2px -19px
  192 + transparent;
  193 + border: 0 none;
  194 + cursor: pointer;
  195 + height: 12px;
  196 + position: absolute;
  197 + right: 7px;
  198 + top: 9px;
  199 + width: 15px;
  200 +}
  201 +
  202 +/*s--------------交通流量-----------------*/
  203 +.maplibTfctr {
  204 + min-width: 9em;
  205 + height: 2.2em;
  206 + display: -webkit-box;
  207 + -webkit-box-align: center;
  208 + -webkit-border-radius: 0.3em;
  209 + border: .1em solid #989898;
  210 + -webkit-box-sizing: border-box;
  211 + background-color: #fff;
  212 + font-size: 14px;
  213 +}
  214 +
  215 +.maplibTfctrHide {
  216 + display: none;
  217 +}
  218 +
  219 +.maplibTfctr_c {
  220 + -webkit-box-flex: 1;
  221 +}
  222 +
  223 +.maplibTfctr_status {
  224 + width: 4em;
  225 + margin-right: .45em;
  226 +}
  227 +
  228 +.maplibTfctr_status span {
  229 + display: inline-block;
  230 + margin-left: .3em;
  231 + font-size: 14px;
  232 +}
  233 +
  234 +.maplibTfctr div,.maplibTfctr span {
  235 + -webkit-box-sizing: border-box;
  236 +}
  237 +
  238 +.maplibTfctr_l {
  239 + margin: 0 .15em;
  240 +}
  241 +
  242 +.maplibY {
  243 + background: #ffae00;
  244 +}
  245 +
  246 +.maplibR {
  247 + background: #ff0000;
  248 +}
  249 +
  250 +.maplibG {
  251 + background: #1fba00;
  252 +}
253 253 /*e--------------交通流量-----------------*/
254 254 \ No newline at end of file
... ...
src/main/resources/static/assets/js/baidu/TextIconOverlay.js
1   -/**
2   - * @fileoverview 此类表示地图上的一个覆盖物,该覆盖物由文字和图标组成,从Overlay继承。
3   - * 主入口类是<a href="symbols/BMapLib.TextIconOverlay.html">TextIconOverlay</a>,
4   - * 基于Baidu Map API 1.2。
5   - *
6   - * @author Baidu Map Api Group
7   - * @version 1.2
8   - */
9   -
10   -
11   - /**
12   - * @namespace BMap的所有library类均放在BMapLib命名空间下
13   - */
14   -var BMapLib = window.BMapLib = BMapLib || {};
15   -
16   -(function () {
17   -
18   - /**
19   - * 声明baidu包
20   - */
21   - var T,
22   - baidu = T = baidu || {version: "1.3.8"};
23   -
24   - (function (){
25   - //提出guid,防止在与老版本Tangram混用时
26   - //在下一行错误的修改window[undefined]
27   - baidu.guid = "$BAIDU$";
28   -
29   - //Tangram可能被放在闭包中
30   - //一些页面级别唯一的属性,需要挂载在window[baidu.guid]上
31   - window[baidu.guid] = window[baidu.guid] || {};
32   -
33   - /**
34   - * @ignore
35   - * @namespace baidu.dom 操作dom的方法。
36   - */
37   - baidu.dom = baidu.dom || {};
38   -
39   -
40   - /**
41   - * 从文档中获取指定的DOM元素
42   - * @name baidu.dom.g
43   - * @function
44   - * @grammar baidu.dom.g(id)
45   - * @param {string|HTMLElement} id 元素的id或DOM元素
46   - * @shortcut g,T.G
47   - * @meta standard
48   - * @see baidu.dom.q
49   - *
50   - * @returns {HTMLElement|null} 获取的元素,查找不到时返回null,如果参数不合法,直接返回参数
51   - */
52   - baidu.dom.g = function (id) {
53   - if ('string' == typeof id || id instanceof String) {
54   - return document.getElementById(id);
55   - } else if (id && id.nodeName && (id.nodeType == 1 || id.nodeType == 9)) {
56   - return id;
57   - }
58   - return null;
59   - };
60   -
61   - // 声明快捷方法
62   - baidu.g = baidu.G = baidu.dom.g;
63   -
64   - /**
65   - * 获取目标元素所属的document对象
66   - * @name baidu.dom.getDocument
67   - * @function
68   - * @grammar baidu.dom.getDocument(element)
69   - * @param {HTMLElement|string} element 目标元素或目标元素的id
70   - * @meta standard
71   - * @see baidu.dom.getWindow
72   - *
73   - * @returns {HTMLDocument} 目标元素所属的document对象
74   - */
75   - baidu.dom.getDocument = function (element) {
76   - element = baidu.dom.g(element);
77   - return element.nodeType == 9 ? element : element.ownerDocument || element.document;
78   - };
79   -
80   - /**
81   - * @ignore
82   - * @namespace baidu.lang 对语言层面的封装,包括类型判断、模块扩展、继承基类以及对象自定义事件的支持。
83   - */
84   - baidu.lang = baidu.lang || {};
85   -
86   - /**
87   - * 判断目标参数是否string类型或String对象
88   - * @name baidu.lang.isString
89   - * @function
90   - * @grammar baidu.lang.isString(source)
91   - * @param {Any} source 目标参数
92   - * @shortcut isString
93   - * @meta standard
94   - * @see baidu.lang.isObject,baidu.lang.isNumber,baidu.lang.isArray,baidu.lang.isElement,baidu.lang.isBoolean,baidu.lang.isDate
95   - *
96   - * @returns {boolean} 类型判断结果
97   - */
98   - baidu.lang.isString = function (source) {
99   - return '[object String]' == Object.prototype.toString.call(source);
100   - };
101   -
102   - // 声明快捷方法
103   - baidu.isString = baidu.lang.isString;
104   -
105   - /**
106   - * 从文档中获取指定的DOM元素
107   - * **内部方法**
108   - *
109   - * @param {string|HTMLElement} id 元素的id或DOM元素
110   - * @meta standard
111   - * @return {HTMLElement} DOM元素,如果不存在,返回null,如果参数不合法,直接返回参数
112   - */
113   - baidu.dom._g = function (id) {
114   - if (baidu.lang.isString(id)) {
115   - return document.getElementById(id);
116   - }
117   - return id;
118   - };
119   -
120   - // 声明快捷方法
121   - baidu._g = baidu.dom._g;
122   -
123   - /**
124   - * @ignore
125   - * @namespace baidu.browser 判断浏览器类型和特性的属性。
126   - */
127   - baidu.browser = baidu.browser || {};
128   -
129   - if (/msie (\d+\.\d)/i.test(navigator.userAgent)) {
130   - //IE 8下,以documentMode为准
131   - //在百度模板中,可能会有$,防止冲突,将$1 写成 \x241
132   - /**
133   - * 判断是否为ie浏览器
134   - * @property ie ie版本号
135   - * @grammar baidu.browser.ie
136   - * @meta standard
137   - * @shortcut ie
138   - * @see baidu.browser.firefox,baidu.browser.safari,baidu.browser.opera,baidu.browser.chrome,baidu.browser.maxthon
139   - */
140   - baidu.browser.ie = baidu.ie = document.documentMode || + RegExp['\x241'];
141   - }
142   -
143   - /**
144   - * 获取目标元素的computed style值。如果元素的样式值不能被浏览器计算,则会返回空字符串(IE)
145   - *
146   - * @author berg
147   - * @name baidu.dom.getComputedStyle
148   - * @function
149   - * @grammar baidu.dom.getComputedStyle(element, key)
150   - * @param {HTMLElement|string} element 目标元素或目标元素的id
151   - * @param {string} key 要获取的样式名
152   - *
153   - * @see baidu.dom.getStyle
154   - *
155   - * @returns {string} 目标元素的computed style值
156   - */
157   -
158   - baidu.dom.getComputedStyle = function(element, key){
159   - element = baidu.dom._g(element);
160   - var doc = baidu.dom.getDocument(element),
161   - styles;
162   - if (doc.defaultView && doc.defaultView.getComputedStyle) {
163   - styles = doc.defaultView.getComputedStyle(element, null);
164   - if (styles) {
165   - return styles[key] || styles.getPropertyValue(key);
166   - }
167   - }
168   - return '';
169   - };
170   -
171   - /**
172   - * 提供给setStyle与getStyle使用
173   - */
174   - baidu.dom._styleFixer = baidu.dom._styleFixer || {};
175   -
176   - /**
177   - * 提供给setStyle与getStyle使用
178   - */
179   - baidu.dom._styleFilter = baidu.dom._styleFilter || [];
180   -
181   - /**
182   - * 为获取和设置样式的过滤器
183   - * @private
184   - * @meta standard
185   - */
186   - baidu.dom._styleFilter.filter = function (key, value, method) {
187   - for (var i = 0, filters = baidu.dom._styleFilter, filter; filter = filters[i]; i++) {
188   - if (filter = filter[method]) {
189   - value = filter(key, value);
190   - }
191   - }
192   - return value;
193   - };
194   -
195   - /**
196   - * @ignore
197   - * @namespace baidu.string 操作字符串的方法。
198   - */
199   - baidu.string = baidu.string || {};
200   -
201   - /**
202   - * 将目标字符串进行驼峰化处理
203   - * @name baidu.string.toCamelCase
204   - * @function
205   - * @grammar baidu.string.toCamelCase(source)
206   - * @param {string} source 目标字符串
207   - * @remark
208   - * 支持单词以“-_”分隔
209   - * @meta standard
210   - *
211   - * @returns {string} 驼峰化处理后的字符串
212   - */
213   - baidu.string.toCamelCase = function (source) {
214   - //提前判断,提高getStyle等的效率 thanks xianwei
215   - if (source.indexOf('-') < 0 && source.indexOf('_') < 0) {
216   - return source;
217   - }
218   - return source.replace(/[-_][^-_]/g, function (match) {
219   - return match.charAt(1).toUpperCase();
220   - });
221   - };
222   -
223   - /**
224   - * 获取目标元素的样式值
225   - * @name baidu.dom.getStyle
226   - * @function
227   - * @grammar baidu.dom.getStyle(element, key)
228   - * @param {HTMLElement|string} element 目标元素或目标元素的id
229   - * @param {string} key 要获取的样式名
230   - * @remark
231   - *
232   - * 为了精简代码,本模块默认不对任何浏览器返回值进行归一化处理(如使用getStyle时,不同浏览器下可能返回rgb颜色或hex颜色),也不会修复浏览器的bug和差异性(如设置IE的float属性叫styleFloat,firefox则是cssFloat)。<br />
233   - * baidu.dom._styleFixer和baidu.dom._styleFilter可以为本模块提供支持。<br />
234   - * 其中_styleFilter能对颜色和px进行归一化处理,_styleFixer能对display,float,opacity,textOverflow的浏览器兼容性bug进行处理。
235   - * @shortcut getStyle
236   - * @meta standard
237   - * @see baidu.dom.setStyle,baidu.dom.setStyles, baidu.dom.getComputedStyle
238   - *
239   - * @returns {string} 目标元素的样式值
240   - */
241   - baidu.dom.getStyle = function (element, key) {
242   - var dom = baidu.dom;
243   -
244   - element = dom.g(element);
245   - key = baidu.string.toCamelCase(key);
246   - //computed style, then cascaded style, then explicitly set style.
247   - var value = element.style[key] ||
248   - (element.currentStyle ? element.currentStyle[key] : "") ||
249   - dom.getComputedStyle(element, key);
250   -
251   - // 在取不到值的时候,用fixer进行修正
252   - if (!value) {
253   - var fixer = dom._styleFixer[key];
254   - if(fixer){
255   - value = fixer.get ? fixer.get(element) : baidu.dom.getStyle(element, fixer);
256   - }
257   - }
258   -
259   - /* 检查结果过滤器 */
260   - if (fixer = dom._styleFilter) {
261   - value = fixer.filter(key, value, 'get');
262   - }
263   -
264   - return value;
265   - };
266   -
267   - // 声明快捷方法
268   - baidu.getStyle = baidu.dom.getStyle;
269   -
270   -
271   - if (/opera\/(\d+\.\d)/i.test(navigator.userAgent)) {
272   - /**
273   - * 判断是否为opera浏览器
274   - * @property opera opera版本号
275   - * @grammar baidu.browser.opera
276   - * @meta standard
277   - * @see baidu.browser.ie,baidu.browser.firefox,baidu.browser.safari,baidu.browser.chrome
278   - */
279   - baidu.browser.opera = + RegExp['\x241'];
280   - }
281   -
282   - /**
283   - * 判断是否为webkit内核
284   - * @property isWebkit
285   - * @grammar baidu.browser.isWebkit
286   - * @meta standard
287   - * @see baidu.browser.isGecko
288   - */
289   - baidu.browser.isWebkit = /webkit/i.test(navigator.userAgent);
290   -
291   - /**
292   - * 判断是否为gecko内核
293   - * @property isGecko
294   - * @grammar baidu.browser.isGecko
295   - * @meta standard
296   - * @see baidu.browser.isWebkit
297   - */
298   - baidu.browser.isGecko = /gecko/i.test(navigator.userAgent) && !/like gecko/i.test(navigator.userAgent);
299   -
300   - /**
301   - * 判断是否严格标准的渲染模式
302   - * @property isStrict
303   - * @grammar baidu.browser.isStrict
304   - * @meta standard
305   - */
306   - baidu.browser.isStrict = document.compatMode == "CSS1Compat";
307   -
308   - /**
309   - * 获取目标元素相对于整个文档左上角的位置
310   - * @name baidu.dom.getPosition
311   - * @function
312   - * @grammar baidu.dom.getPosition(element)
313   - * @param {HTMLElement|string} element 目标元素或目标元素的id
314   - * @meta standard
315   - *
316   - * @returns {Object} 目标元素的位置,键值为top和left的Object。
317   - */
318   - baidu.dom.getPosition = function (element) {
319   - element = baidu.dom.g(element);
320   - var doc = baidu.dom.getDocument(element),
321   - browser = baidu.browser,
322   - getStyle = baidu.dom.getStyle,
323   - // Gecko 1.9版本以下用getBoxObjectFor计算位置
324   - // 但是某些情况下是有bug的
325   - // 对于这些有bug的情况
326   - // 使用递归查找的方式
327   - BUGGY_GECKO_BOX_OBJECT = browser.isGecko > 0 &&
328   - doc.getBoxObjectFor &&
329   - getStyle(element, 'position') == 'absolute' &&
330   - (element.style.top === '' || element.style.left === ''),
331   - pos = {"left":0,"top":0},
332   - viewport = (browser.ie && !browser.isStrict) ? doc.body : doc.documentElement,
333   - parent,
334   - box;
335   -
336   - if(element == viewport){
337   - return pos;
338   - }
339   -
340   - if(element.getBoundingClientRect){ // IE and Gecko 1.9+
341   -
342   - //当HTML或者BODY有border width时, 原生的getBoundingClientRect返回值是不符合预期的
343   - //考虑到通常情况下 HTML和BODY的border只会设成0px,所以忽略该问题.
344   - box = element.getBoundingClientRect();
345   -
346   - pos.left = Math.floor(box.left) + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft);
347   - pos.top = Math.floor(box.top) + Math.max(doc.documentElement.scrollTop, doc.body.scrollTop);
348   -
349   - // IE会给HTML元素添加一个border,默认是medium(2px)
350   - // 但是在IE 6 7 的怪异模式下,可以被html { border: 0; } 这条css规则覆盖
351   - // 在IE7的标准模式下,border永远是2px,这个值通过clientLeft 和 clientTop取得
352   - // 但是。。。在IE 6 7的怪异模式,如果用户使用css覆盖了默认的medium
353   - // clientTop和clientLeft不会更新
354   - pos.left -= doc.documentElement.clientLeft;
355   - pos.top -= doc.documentElement.clientTop;
356   -
357   - var htmlDom = doc.body,
358   - // 在这里,不使用element.style.borderLeftWidth,只有computedStyle是可信的
359   - htmlBorderLeftWidth = parseInt(getStyle(htmlDom, 'borderLeftWidth')),
360   - htmlBorderTopWidth = parseInt(getStyle(htmlDom, 'borderTopWidth'));
361   - if(browser.ie && !browser.isStrict){
362   - pos.left -= isNaN(htmlBorderLeftWidth) ? 2 : htmlBorderLeftWidth;
363   - pos.top -= isNaN(htmlBorderTopWidth) ? 2 : htmlBorderTopWidth;
364   - }
365   - } else {
366   - // safari/opera/firefox
367   - parent = element;
368   -
369   - do {
370   - pos.left += parent.offsetLeft;
371   - pos.top += parent.offsetTop;
372   -
373   - // safari里面,如果遍历到了一个fixed的元素,后面的offset都不准了
374   - if (browser.isWebkit > 0 && getStyle(parent, 'position') == 'fixed') {
375   - pos.left += doc.body.scrollLeft;
376   - pos.top += doc.body.scrollTop;
377   - break;
378   - }
379   -
380   - parent = parent.offsetParent;
381   - } while (parent && parent != element);
382   -
383   - // 对body offsetTop的修正
384   - if(browser.opera > 0 || (browser.isWebkit > 0 && getStyle(element, 'position') == 'absolute')){
385   - pos.top -= doc.body.offsetTop;
386   - }
387   -
388   - // 计算除了body的scroll
389   - parent = element.offsetParent;
390   - while (parent && parent != doc.body) {
391   - pos.left -= parent.scrollLeft;
392   - // see https://bugs.opera.com/show_bug.cgi?id=249965
393   - if (!browser.opera || parent.tagName != 'TR') {
394   - pos.top -= parent.scrollTop;
395   - }
396   - parent = parent.offsetParent;
397   - }
398   - }
399   -
400   - return pos;
401   - };
402   -
403   - /**
404   - * @ignore
405   - * @namespace baidu.event 屏蔽浏览器差异性的事件封装。
406   - * @property target 事件的触发元素
407   - * @property pageX 鼠标事件的鼠标x坐标
408   - * @property pageY 鼠标事件的鼠标y坐标
409   - * @property keyCode 键盘事件的键值
410   - */
411   - baidu.event = baidu.event || {};
412   -
413   - /**
414   - * 事件监听器的存储表
415   - * @private
416   - * @meta standard
417   - */
418   - baidu.event._listeners = baidu.event._listeners || [];
419   -
420   - /**
421   - * 为目标元素添加事件监听器
422   - * @name baidu.event.on
423   - * @function
424   - * @grammar baidu.event.on(element, type, listener)
425   - * @param {HTMLElement|string|window} element 目标元素或目标元素id
426   - * @param {string} type 事件类型
427   - * @param {Function} listener 需要添加的监听器
428   - * @remark
429   - *
430   - 1. 不支持跨浏览器的鼠标滚轮事件监听器添加<br>
431   - 2. 改方法不为监听器灌入事件对象,以防止跨iframe事件挂载的事件对象获取失败
432   -
433   - * @shortcut on
434   - * @meta standard
435   - * @see baidu.event.un
436   - *
437   - * @returns {HTMLElement|window} 目标元素
438   - */
439   - baidu.event.on = function (element, type, listener) {
440   - type = type.replace(/^on/i, '');
441   - element = baidu.dom._g(element);
442   -
443   - var realListener = function (ev) {
444   - // 1. 这里不支持EventArgument, 原因是跨frame的事件挂载
445   - // 2. element是为了修正this
446   - listener.call(element, ev);
447   - },
448   - lis = baidu.event._listeners,
449   - filter = baidu.event._eventFilter,
450   - afterFilter,
451   - realType = type;
452   - type = type.toLowerCase();
453   - // filter过滤
454   - if(filter && filter[type]){
455   - afterFilter = filter[type](element, type, realListener);
456   - realType = afterFilter.type;
457   - realListener = afterFilter.listener;
458   - }
459   -
460   - // 事件监听器挂载
461   - if (element.addEventListener) {
462   - element.addEventListener(realType, realListener, false);
463   - } else if (element.attachEvent) {
464   - element.attachEvent('on' + realType, realListener);
465   - }
466   -
467   - // 将监听器存储到数组中
468   - lis[lis.length] = [element, type, listener, realListener, realType];
469   - return element;
470   - };
471   -
472   - // 声明快捷方法
473   - baidu.on = baidu.event.on;
474   -
475   - /**
476   - * 返回一个当前页面的唯一标识字符串。
477   - * @name baidu.lang.guid
478   - * @function
479   - * @grammar baidu.lang.guid()
480   - * @version 1.1.1
481   - * @meta standard
482   - *
483   - * @returns {String} 当前页面的唯一标识字符串
484   - */
485   -
486   - (function(){
487   - //不直接使用window,可以提高3倍左右性能
488   - var guid = window[baidu.guid];
489   -
490   - baidu.lang.guid = function() {
491   - return "TANGRAM__" + (guid._counter ++).toString(36);
492   - };
493   -
494   - guid._counter = guid._counter || 1;
495   - })();
496   -
497   - /**
498   - * 所有类的实例的容器
499   - * key为每个实例的guid
500   - * @meta standard
501   - */
502   -
503   - window[baidu.guid]._instances = window[baidu.guid]._instances || {};
504   -
505   - /**
506   - * 判断目标参数是否为function或Function实例
507   - * @name baidu.lang.isFunction
508   - * @function
509   - * @grammar baidu.lang.isFunction(source)
510   - * @param {Any} source 目标参数
511   - * @version 1.2
512   - * @see baidu.lang.isString,baidu.lang.isObject,baidu.lang.isNumber,baidu.lang.isArray,baidu.lang.isElement,baidu.lang.isBoolean,baidu.lang.isDate
513   - * @meta standard
514   - * @returns {boolean} 类型判断结果
515   - */
516   - baidu.lang.isFunction = function (source) {
517   - // chrome下,'function' == typeof /a/ 为true.
518   - return '[object Function]' == Object.prototype.toString.call(source);
519   - };
520   -
521   - /**
522   - *
523   - * @ignore
524   - * @class Tangram继承机制提供的一个基类,用户可以通过继承baidu.lang.Class来获取它的属性及方法。
525   - * @name baidu.lang.Class
526   - * @grammar baidu.lang.Class(guid)
527   - * @param {string} guid 对象的唯一标识
528   - * @meta standard
529   - * @remark baidu.lang.Class和它的子类的实例均包含一个全局唯一的标识guid。guid是在构造函数中生成的,因此,继承自baidu.lang.Class的类应该直接或者间接调用它的构造函数。<br>baidu.lang.Class的构造函数中产生guid的方式可以保证guid的唯一性,及每个实例都有一个全局唯一的guid。
530   - * @meta standard
531   - * @see baidu.lang.inherits,baidu.lang.Event
532   - */
533   - baidu.lang.Class = function(guid) {
534   - this.guid = guid || baidu.lang.guid();
535   - window[baidu.guid]._instances[this.guid] = this;
536   - };
537   - window[baidu.guid]._instances = window[baidu.guid]._instances || {};
538   -
539   - /**
540   - * 释放对象所持有的资源,主要是自定义事件。
541   - * @name dispose
542   - * @grammar obj.dispose()
543   - */
544   - baidu.lang.Class.prototype.dispose = function(){
545   - delete window[baidu.guid]._instances[this.guid];
546   -
547   - for(var property in this){
548   - if (!baidu.lang.isFunction(this[property])) {
549   - delete this[property];
550   - }
551   - }
552   - this.disposed = true;
553   - };
554   -
555   - /**
556   - * 重载了默认的toString方法,使得返回信息更加准确一些。
557   - * @return {string} 对象的String表示形式
558   - */
559   - baidu.lang.Class.prototype.toString = function(){
560   - return "[object " + (this._className || "Object" ) + "]";
561   - };
562   -
563   - /**
564   - * @ignore
565   - * @class 自定义的事件对象。
566   - * @name baidu.lang.Event
567   - * @grammar baidu.lang.Event(type[, target])
568   - * @param {string} type 事件类型名称。为了方便区分事件和一个普通的方法,事件类型名称必须以"on"(小写)开头。
569   - * @param {Object} [target]触发事件的对象
570   - * @meta standard
571   - * @remark 引入该模块,会自动为Class引入3个事件扩展方法:addEventListener、removeEventListener和dispatchEvent。
572   - * @meta standard
573   - * @see baidu.lang.Class
574   - */
575   - baidu.lang.Event = function (type, target) {
576   - this.type = type;
577   - this.returnValue = true;
578   - this.target = target || null;
579   - this.currentTarget = null;
580   - };
581   -
582   - /**
583   - * 注册对象的事件监听器。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
584   - * @grammar obj.addEventListener(type, handlers[, key])
585   - * @param {string} type 自定义事件的名称
586   - * @param {Function} handler 自定义事件被触发时应该调用的回调函数
587   - * @param {string} [key] 为事件监听函数指定的名称,可在移除时使用。如果不提供,方法会默认为它生成一个全局唯一的key。
588   - * @remark 事件类型区分大小写。如果自定义事件名称不是以小写"on"开头,该方法会给它加上"on"再进行判断,即"click"和"onclick"会被认为是同一种事件。
589   - */
590   - baidu.lang.Class.prototype.addEventListener = function (type, handler, key) {
591   - if (!baidu.lang.isFunction(handler)) {
592   - return;
593   - }
594   -
595   - !this.__listeners && (this.__listeners = {});
596   -
597   - var t = this.__listeners, id;
598   - if (typeof key == "string" && key) {
599   - if (/[^\w\-]/.test(key)) {
600   - throw("nonstandard key:" + key);
601   - } else {
602   - handler.hashCode = key;
603   - id = key;
604   - }
605   - }
606   - type.indexOf("on") != 0 && (type = "on" + type);
607   -
608   - typeof t[type] != "object" && (t[type] = {});
609   - id = id || baidu.lang.guid();
610   - handler.hashCode = id;
611   - t[type][id] = handler;
612   - };
613   -
614   - /**
615   - * 移除对象的事件监听器。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
616   - * @grammar obj.removeEventListener(type, handlers)
617   - * @param {string} type 事件类型
618   - * @param {Function|string} handler 要移除的事件监听函数或者监听函数的key
619   - * @remark 如果第二个参数handler没有被绑定到对应的自定义事件中,什么也不做。
620   - */
621   - baidu.lang.Class.prototype.removeEventListener = function (type, handler) {
622   - if (typeof handler != "undefined") {
623   - if ( (baidu.lang.isFunction(handler) && ! (handler = handler.hashCode))
624   - || (! baidu.lang.isString(handler))
625   - ){
626   - return;
627   - }
628   - }
629   -
630   - !this.__listeners && (this.__listeners = {});
631   -
632   - type.indexOf("on") != 0 && (type = "on" + type);
633   -
634   - var t = this.__listeners;
635   - if (!t[type]) {
636   - return;
637   - }
638   - if (typeof handler != "undefined") {
639   - t[type][handler] && delete t[type][handler];
640   - } else {
641   - for(var guid in t[type]){
642   - delete t[type][guid];
643   - }
644   - }
645   - };
646   -
647   - /**
648   - * 派发自定义事件,使得绑定到自定义事件上面的函数都会被执行。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
649   - * @grammar obj.dispatchEvent(event, options)
650   - * @param {baidu.lang.Event|String} event Event对象,或事件名称(1.1.1起支持)
651   - * @param {Object} options 扩展参数,所含属性键值会扩展到Event对象上(1.2起支持)
652   - * @remark 处理会调用通过addEventListenr绑定的自定义事件回调函数之外,还会调用直接绑定到对象上面的自定义事件。例如:<br>
653   - myobj.onMyEvent = function(){}<br>
654   - myobj.addEventListener("onMyEvent", function(){});
655   - */
656   - baidu.lang.Class.prototype.dispatchEvent = function (event, options) {
657   - if (baidu.lang.isString(event)) {
658   - event = new baidu.lang.Event(event);
659   - }
660   - !this.__listeners && (this.__listeners = {});
661   -
662   - // 20100603 添加本方法的第二个参数,将 options extend到event中去传递
663   - options = options || {};
664   - for (var i in options) {
665   - event[i] = options[i];
666   - }
667   -
668   - var i, t = this.__listeners, p = event.type;
669   - event.target = event.target || this;
670   - event.currentTarget = this;
671   -
672   - p.indexOf("on") != 0 && (p = "on" + p);
673   -
674   - baidu.lang.isFunction(this[p]) && this[p].apply(this, arguments);
675   -
676   - if (typeof t[p] == "object") {
677   - for (i in t[p]) {
678   - t[p][i].apply(this, arguments);
679   - }
680   - }
681   - return event.returnValue;
682   - };
683   -
684   -
685   - baidu.lang.inherits = function (subClass, superClass, className) {
686   - var key, proto,
687   - selfProps = subClass.prototype,
688   - clazz = new Function();
689   -
690   - clazz.prototype = superClass.prototype;
691   - proto = subClass.prototype = new clazz();
692   - for (key in selfProps) {
693   - proto[key] = selfProps[key];
694   - }
695   - subClass.prototype.constructor = subClass;
696   - subClass.superClass = superClass.prototype;
697   -
698   - // 类名标识,兼容Class的toString,基本没用
699   - if ("string" == typeof className) {
700   - proto._className = className;
701   - }
702   - };
703   - // 声明快捷方法
704   - baidu.inherits = baidu.lang.inherits;
705   - })();
706   -
707   -
708   - /**
709   -
710   - * 图片的路径
711   -
712   - * @private
713   - * @type {String}
714   -
715   - */
716   - var _IMAGE_PATH = 'http://api.map.baidu.com/library/TextIconOverlay/1.2/src/images/m';
717   -
718   - /**
719   -
720   - * 图片的后缀名
721   -
722   - * @private
723   - * @type {String}
724   -
725   - */
726   - var _IMAGE_EXTENSION = 'png';
727   -
728   - /**
729   - *@exports TextIconOverlay as BMapLib.TextIconOverlay
730   - */
731   - var TextIconOverlay =
732   - /**
733   - * TextIconOverlay
734   - * @class 此类表示地图上的一个覆盖物,该覆盖物由文字和图标组成,从Overlay继承。文字通常是数字(0-9)或字母(A-Z ),而文字与图标之间有一定的映射关系。
735   - *该覆盖物适用于以下类似的场景:需要在地图上添加一系列覆盖物,这些覆盖物之间用不同的图标和文字来区分,文字可能表示了该覆盖物的某一属性值,根据该文字和一定的映射关系,自动匹配相应颜色和大小的图标。
736   - *
737   - *@constructor
738   - *@param {Point} position 表示一个经纬度坐标位置。
739   - *@param {String} text 表示该覆盖物显示的文字信息。
740   - *@param {Json Object} options 可选参数,可选项包括:<br />
741   - *"<b>styles</b>":{Array<IconStyle>} 一组图标风格。单个图表风格包括以下几个属性:<br />
742   - * url {String} 图片的url地址。(必选)<br />
743   - * size {Size} 图片的大小。(必选)<br />
744   - * anchor {Size} 图标定位在地图上的位置相对于图标左上角的偏移值,默认偏移值为图标的中心位置。(可选)<br />
745   - * offset {Size} 图片相对于可视区域的偏移值,此功能的作用等同于CSS中的background-position属性。(可选)<br />
746   - * textSize {Number} 文字的大小。(可选,默认10)<br />
747   - * textColor {String} 文字的颜色。(可选,默认black)<br />
748   - */
749   - BMapLib.TextIconOverlay = function(position, text, options){
750   - this._position = position;
751   - this._text = text;
752   - this._options = options || {};
753   - this._styles = this._options['styles'] || [];
754   - (!this._styles.length) && this._setupDefaultStyles();
755   - };
756   -
757   - T.lang.inherits(TextIconOverlay, BMap.Overlay, "TextIconOverlay");
758   -
759   - TextIconOverlay.prototype._setupDefaultStyles = function(){
760   - var sizes = [53, 56, 66, 78, 90];
761   - for(var i = 0, size; size = sizes[i]; i++){
762   - this._styles.push({
763   - url:_IMAGE_PATH + i + '.' + _IMAGE_EXTENSION,
764   - size: new BMap.Size(size, size)
765   - });
766   - }//for循环的简洁写法
767   - };
768   -
769   - /**
770   - *继承Overlay的intialize方法,自定义覆盖物时必须。
771   - *@param {Map} map BMap.Map的实例化对象。
772   - *@return {HTMLElement} 返回覆盖物对应的HTML元素。
773   - */
774   - TextIconOverlay.prototype.initialize = function(map){
775   - this._map = map;
776   -
777   - this._domElement = document.createElement('div');
778   - this._updateCss();
779   - this._updateText();
780   - this._updatePosition();
781   -
782   - this._bind();
783   -
784   - this._map.getPanes().markerMouseTarget.appendChild(this._domElement);
785   - return this._domElement;
786   - };
787   -
788   - /**
789   - *继承Overlay的draw方法,自定义覆盖物时必须。
790   - *@return 无返回值。
791   - */
792   - TextIconOverlay.prototype.draw = function(){
793   - this._map && this._updatePosition();
794   - };
795   -
796   - /**
797   - *获取该覆盖物上的文字。
798   - *@return {String} 该覆盖物上的文字。
799   - */
800   - TextIconOverlay.prototype.getText = function(){
801   - return this._text;
802   - };
803   -
804   - /**
805   - *设置该覆盖物上的文字。
806   - *@param {String} text 要设置的文字,通常是字母A-Z或数字0-9。
807   - *@return 无返回值。
808   - */
809   - TextIconOverlay.prototype.setText = function(text){
810   - if(text && (!this._text || (this._text.toString() != text.toString()))){
811   - this._text = text;
812   - this._updateText();
813   - this._updateCss();
814   - this._updatePosition();
815   - }
816   - };
817   -
818   - /**
819   - *获取该覆盖物的位置。
820   - *@return {Point} 该覆盖物的经纬度坐标。
821   - */
822   - TextIconOverlay.prototype.getPosition = function () {
823   - return this._position;
824   - };
825   -
826   - /**
827   - *设置该覆盖物的位置。
828   - *@param {Point} position 要设置的经纬度坐标。
829   - *@return 无返回值。
830   - */
831   - TextIconOverlay.prototype.setPosition = function (position) {
832   - if(position && (!this._position || !this._position.equals(position))){
833   - this._position = position;
834   - this._updatePosition();
835   - }
836   - };
837   -
838   - /**
839   - *由文字信息获取风格数组的对应索引值。
840   - *内部默认的对应函数为文字转换为数字除以10的结果,比如文字8返回索引0,文字25返回索引2.
841   - *如果需要自定义映射关系,请覆盖该函数。
842   - *@param {String} text 文字。
843   - *@param {Array<IconStyle>} styles 一组图标风格。
844   - *@return {Number} 对应的索引值。
845   - */
846   - TextIconOverlay.prototype.getStyleByText = function(text, styles){
847   - var count = parseInt(text);
848   - var index = parseInt(count / 10);
849   - index = Math.max(0, index);
850   - index = Math.min(index, styles.length - 1);
851   - return styles[index];
852   - }
853   -
854   - /**
855   - *更新相应的CSS。
856   - *@return 无返回值。
857   - */
858   - TextIconOverlay.prototype._updateCss = function(){
859   - var style = this.getStyleByText(this._text, this._styles);
860   - this._domElement.style.cssText = this._buildCssText(style);
861   - };
862   -
863   - /**
864   - *更新覆盖物的显示文字。
865   - *@return 无返回值。
866   - */
867   - TextIconOverlay.prototype._updateText = function(){
868   - if (this._domElement) {
869   - this._domElement.innerHTML = this._text;
870   - }
871   - };
872   -
873   - /**
874   - *调整覆盖物在地图上的位置更新覆盖物的显示文字。
875   - *@return 无返回值。
876   - */
877   - TextIconOverlay.prototype._updatePosition = function(){
878   - if (this._domElement && this._position) {
879   - var style = this._domElement.style;
880   - var pixelPosition= this._map.pointToOverlayPixel(this._position);
881   - pixelPosition.x -= Math.ceil(parseInt(style.width) / 2);
882   - pixelPosition.y -= Math.ceil(parseInt(style.height) / 2);
883   - style.left = pixelPosition.x + "px";
884   - style.top = pixelPosition.y + "px";
885   - }
886   - };
887   -
888   - /**
889   - * 为该覆盖物的HTML元素构建CSS
890   - * @param {IconStyle} 一个图标的风格。
891   - * @return {String} 构建完成的CSSTEXT。
892   - */
893   - TextIconOverlay.prototype._buildCssText = function(style) {
894   - //根据style来确定一些默认值
895   - var url = style['url'];
896   - var size = style['size'];
897   - var anchor = style['anchor'];
898   - var offset = style['offset'];
899   - var textColor = style['textColor'] || 'black';
900   - var textSize = style['textSize'] || 10;
901   -
902   - var csstext = [];
903   - if (T.browser["ie"] < 7) {
904   - csstext.push('filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(' +
905   - 'sizingMethod=scale,src="' + url + '");');
906   - } else {
907   - csstext.push('background-image:url(' + url + ');');
908   - var backgroundPosition = '0 0';
909   - (offset instanceof BMap.Size) && (backgroundPosition = offset.width + 'px' + ' ' + offset.height + 'px');
910   - csstext.push('background-position:' + backgroundPosition + ';');
911   - }
912   -
913   - if (size instanceof BMap.Size){
914   - if (anchor instanceof BMap.Size) {
915   - if (anchor.height > 0 && anchor.height < size.height) {
916   - csstext.push('height:' + (size.height - anchor.height) + 'px; padding-top:' + anchor.height + 'px;');
917   - }
918   - if(anchor.width > 0 && anchor.width < size.width){
919   - csstext.push('width:' + (size.width - anchor.width) + 'px; padding-left:' + anchor.width + 'px;');
920   - }
921   - } else {
922   - csstext.push('height:' + size.height + 'px; line-height:' + size.height + 'px;');
923   - csstext.push('width:' + size.width + 'px; text-align:center;');
924   - }
925   - }
926   -
927   - csstext.push('cursor:pointer; color:' + textColor + '; position:absolute; font-size:' +
928   - textSize + 'px; font-family:Arial,sans-serif; font-weight:bold');
929   - return csstext.join('');
930   - };
931   -
932   -
933   - /**
934   -
935   - * 当鼠标点击该覆盖物时会触发该事件
936   -
937   - * @name TextIconOverlay#click
938   -
939   - * @event
940   -
941   - * @param {Event Object} e 回调函数会返回event参数,包括以下返回值:
942   -
943   - * <br />"<b>type</b> : {String} 事件类型
944   -
945   - * <br />"<b>target</b>:{BMapLib.TextIconOverlay} 事件目标
946   -
947   - *
948   -
949   - */
950   -
951   - /**
952   -
953   - * 当鼠标进入该覆盖物区域时会触发该事件
954   -
955   - * @name TextIconOverlay#mouseover
956   -
957   - * @event
958   - * @param {Event Object} e 回调函数会返回event参数,包括以下返回值:
959   -
960   - * <br />"<b>type</b> : {String} 事件类型
961   -
962   - * <br />"<b>target</b>:{BMapLib.TextIconOverlay} 事件目标
963   -
964   - * <br />"<b>point</b> : {BMap.Point} 最新添加上的节点BMap.Point对象
965   -
966   - * <br />"<b>pixel</b>:{BMap.pixel} 最新添加上的节点BMap.Pixel对象
967   -
968   - *
969   -
970   - * @example <b>参考示例:</b><br />
971   -
972   - * myTextIconOverlay.addEventListener("mouseover", function(e) { alert(e.point); });
973   -
974   - */
975   -
976   - /**
977   -
978   - * 当鼠标离开该覆盖物区域时会触发该事件
979   -
980   - * @name TextIconOverlay#mouseout
981   -
982   - * @event
983   -
984   - * @param {Event Object} e 回调函数会返回event参数,包括以下返回值:
985   -
986   - * <br />"<b>type</b> : {String} 事件类型
987   -
988   - * <br />"<b>target</b>:{BMapLib.TextIconOverlay} 事件目标
989   -
990   - * <br />"<b>point</b> : {BMap.Point} 最新添加上的节点BMap.Point对象
991   -
992   - * <br />"<b>pixel</b>:{BMap.pixel} 最新添加上的节点BMap.Pixel对象
993   -
994   - *
995   -
996   - * @example <b>参考示例:</b><br />
997   -
998   - * myTextIconOverlay.addEventListener("mouseout", function(e) { alert(e.point); });
999   -
1000   - */
1001   -
1002   -
1003   - /**
1004   - * 为该覆盖物绑定一系列事件
1005   - * 当前支持click mouseover mouseout
1006   - * @return 无返回值。
1007   - */
1008   - TextIconOverlay.prototype._bind = function(){
1009   - if (!this._domElement){
1010   - return;
1011   - }
1012   -
1013   - var me = this;
1014   - var map = this._map;
1015   -
1016   - var BaseEvent = T.lang.Event;
1017   - function eventExtend(e, be){
1018   - var elem = e.srcElement || e.target;
1019   - var x = e.clientX || e.pageX;
1020   - var y = e.clientY || e.pageY;
1021   - if (e && be && x && y && elem){
1022   - var offset = T.dom.getPosition(map.getContainer());
1023   - be.pixel = new BMap.Pixel(x - offset.left, y - offset.top);
1024   - be.point = map.pixelToPoint(be.pixel);
1025   - }
1026   - return be;
1027   - }//给事件参数增加pixel和point两个值
1028   -
1029   - T.event.on(this._domElement,"mouseover", function(e){
1030   - me.dispatchEvent(eventExtend(e, new BaseEvent("onmouseover")));
1031   - });
1032   - T.event.on(this._domElement,"mouseout", function(e){
1033   - me.dispatchEvent(eventExtend(e, new BaseEvent("onmouseout")));
1034   - });
1035   - T.event.on(this._domElement,"click", function(e){
1036   - me.dispatchEvent(eventExtend(e, new BaseEvent("onclick")));
1037   - });
1038   - };
1039   -
  1 +/**
  2 + * @fileoverview 此类表示地图上的一个覆盖物,该覆盖物由文字和图标组成,从Overlay继承。
  3 + * 主入口类是<a href="symbols/BMapLib.TextIconOverlay.html">TextIconOverlay</a>,
  4 + * 基于Baidu Map API 1.2。
  5 + *
  6 + * @author Baidu Map Api Group
  7 + * @version 1.2
  8 + */
  9 +
  10 +
  11 + /**
  12 + * @namespace BMap的所有library类均放在BMapLib命名空间下
  13 + */
  14 +var BMapLib = window.BMapLib = BMapLib || {};
  15 +
  16 +(function () {
  17 +
  18 + /**
  19 + * 声明baidu包
  20 + */
  21 + var T,
  22 + baidu = T = baidu || {version: "1.3.8"};
  23 +
  24 + (function (){
  25 + //提出guid,防止在与老版本Tangram混用时
  26 + //在下一行错误的修改window[undefined]
  27 + baidu.guid = "$BAIDU$";
  28 +
  29 + //Tangram可能被放在闭包中
  30 + //一些页面级别唯一的属性,需要挂载在window[baidu.guid]上
  31 + window[baidu.guid] = window[baidu.guid] || {};
  32 +
  33 + /**
  34 + * @ignore
  35 + * @namespace baidu.dom 操作dom的方法。
  36 + */
  37 + baidu.dom = baidu.dom || {};
  38 +
  39 +
  40 + /**
  41 + * 从文档中获取指定的DOM元素
  42 + * @name baidu.dom.g
  43 + * @function
  44 + * @grammar baidu.dom.g(id)
  45 + * @param {string|HTMLElement} id 元素的id或DOM元素
  46 + * @shortcut g,T.G
  47 + * @meta standard
  48 + * @see baidu.dom.q
  49 + *
  50 + * @returns {HTMLElement|null} 获取的元素,查找不到时返回null,如果参数不合法,直接返回参数
  51 + */
  52 + baidu.dom.g = function (id) {
  53 + if ('string' == typeof id || id instanceof String) {
  54 + return document.getElementById(id);
  55 + } else if (id && id.nodeName && (id.nodeType == 1 || id.nodeType == 9)) {
  56 + return id;
  57 + }
  58 + return null;
  59 + };
  60 +
  61 + // 声明快捷方法
  62 + baidu.g = baidu.G = baidu.dom.g;
  63 +
  64 + /**
  65 + * 获取目标元素所属的document对象
  66 + * @name baidu.dom.getDocument
  67 + * @function
  68 + * @grammar baidu.dom.getDocument(element)
  69 + * @param {HTMLElement|string} element 目标元素或目标元素的id
  70 + * @meta standard
  71 + * @see baidu.dom.getWindow
  72 + *
  73 + * @returns {HTMLDocument} 目标元素所属的document对象
  74 + */
  75 + baidu.dom.getDocument = function (element) {
  76 + element = baidu.dom.g(element);
  77 + return element.nodeType == 9 ? element : element.ownerDocument || element.document;
  78 + };
  79 +
  80 + /**
  81 + * @ignore
  82 + * @namespace baidu.lang 对语言层面的封装,包括类型判断、模块扩展、继承基类以及对象自定义事件的支持。
  83 + */
  84 + baidu.lang = baidu.lang || {};
  85 +
  86 + /**
  87 + * 判断目标参数是否string类型或String对象
  88 + * @name baidu.lang.isString
  89 + * @function
  90 + * @grammar baidu.lang.isString(source)
  91 + * @param {Any} source 目标参数
  92 + * @shortcut isString
  93 + * @meta standard
  94 + * @see baidu.lang.isObject,baidu.lang.isNumber,baidu.lang.isArray,baidu.lang.isElement,baidu.lang.isBoolean,baidu.lang.isDate
  95 + *
  96 + * @returns {boolean} 类型判断结果
  97 + */
  98 + baidu.lang.isString = function (source) {
  99 + return '[object String]' == Object.prototype.toString.call(source);
  100 + };
  101 +
  102 + // 声明快捷方法
  103 + baidu.isString = baidu.lang.isString;
  104 +
  105 + /**
  106 + * 从文档中获取指定的DOM元素
  107 + * **内部方法**
  108 + *
  109 + * @param {string|HTMLElement} id 元素的id或DOM元素
  110 + * @meta standard
  111 + * @return {HTMLElement} DOM元素,如果不存在,返回null,如果参数不合法,直接返回参数
  112 + */
  113 + baidu.dom._g = function (id) {
  114 + if (baidu.lang.isString(id)) {
  115 + return document.getElementById(id);
  116 + }
  117 + return id;
  118 + };
  119 +
  120 + // 声明快捷方法
  121 + baidu._g = baidu.dom._g;
  122 +
  123 + /**
  124 + * @ignore
  125 + * @namespace baidu.browser 判断浏览器类型和特性的属性。
  126 + */
  127 + baidu.browser = baidu.browser || {};
  128 +
  129 + if (/msie (\d+\.\d)/i.test(navigator.userAgent)) {
  130 + //IE 8下,以documentMode为准
  131 + //在百度模板中,可能会有$,防止冲突,将$1 写成 \x241
  132 + /**
  133 + * 判断是否为ie浏览器
  134 + * @property ie ie版本号
  135 + * @grammar baidu.browser.ie
  136 + * @meta standard
  137 + * @shortcut ie
  138 + * @see baidu.browser.firefox,baidu.browser.safari,baidu.browser.opera,baidu.browser.chrome,baidu.browser.maxthon
  139 + */
  140 + baidu.browser.ie = baidu.ie = document.documentMode || + RegExp['\x241'];
  141 + }
  142 +
  143 + /**
  144 + * 获取目标元素的computed style值。如果元素的样式值不能被浏览器计算,则会返回空字符串(IE)
  145 + *
  146 + * @author berg
  147 + * @name baidu.dom.getComputedStyle
  148 + * @function
  149 + * @grammar baidu.dom.getComputedStyle(element, key)
  150 + * @param {HTMLElement|string} element 目标元素或目标元素的id
  151 + * @param {string} key 要获取的样式名
  152 + *
  153 + * @see baidu.dom.getStyle
  154 + *
  155 + * @returns {string} 目标元素的computed style值
  156 + */
  157 +
  158 + baidu.dom.getComputedStyle = function(element, key){
  159 + element = baidu.dom._g(element);
  160 + var doc = baidu.dom.getDocument(element),
  161 + styles;
  162 + if (doc.defaultView && doc.defaultView.getComputedStyle) {
  163 + styles = doc.defaultView.getComputedStyle(element, null);
  164 + if (styles) {
  165 + return styles[key] || styles.getPropertyValue(key);
  166 + }
  167 + }
  168 + return '';
  169 + };
  170 +
  171 + /**
  172 + * 提供给setStyle与getStyle使用
  173 + */
  174 + baidu.dom._styleFixer = baidu.dom._styleFixer || {};
  175 +
  176 + /**
  177 + * 提供给setStyle与getStyle使用
  178 + */
  179 + baidu.dom._styleFilter = baidu.dom._styleFilter || [];
  180 +
  181 + /**
  182 + * 为获取和设置样式的过滤器
  183 + * @private
  184 + * @meta standard
  185 + */
  186 + baidu.dom._styleFilter.filter = function (key, value, method) {
  187 + for (var i = 0, filters = baidu.dom._styleFilter, filter; filter = filters[i]; i++) {
  188 + if (filter = filter[method]) {
  189 + value = filter(key, value);
  190 + }
  191 + }
  192 + return value;
  193 + };
  194 +
  195 + /**
  196 + * @ignore
  197 + * @namespace baidu.string 操作字符串的方法。
  198 + */
  199 + baidu.string = baidu.string || {};
  200 +
  201 + /**
  202 + * 将目标字符串进行驼峰化处理
  203 + * @name baidu.string.toCamelCase
  204 + * @function
  205 + * @grammar baidu.string.toCamelCase(source)
  206 + * @param {string} source 目标字符串
  207 + * @remark
  208 + * 支持单词以“-_”分隔
  209 + * @meta standard
  210 + *
  211 + * @returns {string} 驼峰化处理后的字符串
  212 + */
  213 + baidu.string.toCamelCase = function (source) {
  214 + //提前判断,提高getStyle等的效率 thanks xianwei
  215 + if (source.indexOf('-') < 0 && source.indexOf('_') < 0) {
  216 + return source;
  217 + }
  218 + return source.replace(/[-_][^-_]/g, function (match) {
  219 + return match.charAt(1).toUpperCase();
  220 + });
  221 + };
  222 +
  223 + /**
  224 + * 获取目标元素的样式值
  225 + * @name baidu.dom.getStyle
  226 + * @function
  227 + * @grammar baidu.dom.getStyle(element, key)
  228 + * @param {HTMLElement|string} element 目标元素或目标元素的id
  229 + * @param {string} key 要获取的样式名
  230 + * @remark
  231 + *
  232 + * 为了精简代码,本模块默认不对任何浏览器返回值进行归一化处理(如使用getStyle时,不同浏览器下可能返回rgb颜色或hex颜色),也不会修复浏览器的bug和差异性(如设置IE的float属性叫styleFloat,firefox则是cssFloat)。<br />
  233 + * baidu.dom._styleFixer和baidu.dom._styleFilter可以为本模块提供支持。<br />
  234 + * 其中_styleFilter能对颜色和px进行归一化处理,_styleFixer能对display,float,opacity,textOverflow的浏览器兼容性bug进行处理。
  235 + * @shortcut getStyle
  236 + * @meta standard
  237 + * @see baidu.dom.setStyle,baidu.dom.setStyles, baidu.dom.getComputedStyle
  238 + *
  239 + * @returns {string} 目标元素的样式值
  240 + */
  241 + baidu.dom.getStyle = function (element, key) {
  242 + var dom = baidu.dom;
  243 +
  244 + element = dom.g(element);
  245 + key = baidu.string.toCamelCase(key);
  246 + //computed style, then cascaded style, then explicitly set style.
  247 + var value = element.style[key] ||
  248 + (element.currentStyle ? element.currentStyle[key] : "") ||
  249 + dom.getComputedStyle(element, key);
  250 +
  251 + // 在取不到值的时候,用fixer进行修正
  252 + if (!value) {
  253 + var fixer = dom._styleFixer[key];
  254 + if(fixer){
  255 + value = fixer.get ? fixer.get(element) : baidu.dom.getStyle(element, fixer);
  256 + }
  257 + }
  258 +
  259 + /* 检查结果过滤器 */
  260 + if (fixer = dom._styleFilter) {
  261 + value = fixer.filter(key, value, 'get');
  262 + }
  263 +
  264 + return value;
  265 + };
  266 +
  267 + // 声明快捷方法
  268 + baidu.getStyle = baidu.dom.getStyle;
  269 +
  270 +
  271 + if (/opera\/(\d+\.\d)/i.test(navigator.userAgent)) {
  272 + /**
  273 + * 判断是否为opera浏览器
  274 + * @property opera opera版本号
  275 + * @grammar baidu.browser.opera
  276 + * @meta standard
  277 + * @see baidu.browser.ie,baidu.browser.firefox,baidu.browser.safari,baidu.browser.chrome
  278 + */
  279 + baidu.browser.opera = + RegExp['\x241'];
  280 + }
  281 +
  282 + /**
  283 + * 判断是否为webkit内核
  284 + * @property isWebkit
  285 + * @grammar baidu.browser.isWebkit
  286 + * @meta standard
  287 + * @see baidu.browser.isGecko
  288 + */
  289 + baidu.browser.isWebkit = /webkit/i.test(navigator.userAgent);
  290 +
  291 + /**
  292 + * 判断是否为gecko内核
  293 + * @property isGecko
  294 + * @grammar baidu.browser.isGecko
  295 + * @meta standard
  296 + * @see baidu.browser.isWebkit
  297 + */
  298 + baidu.browser.isGecko = /gecko/i.test(navigator.userAgent) && !/like gecko/i.test(navigator.userAgent);
  299 +
  300 + /**
  301 + * 判断是否严格标准的渲染模式
  302 + * @property isStrict
  303 + * @grammar baidu.browser.isStrict
  304 + * @meta standard
  305 + */
  306 + baidu.browser.isStrict = document.compatMode == "CSS1Compat";
  307 +
  308 + /**
  309 + * 获取目标元素相对于整个文档左上角的位置
  310 + * @name baidu.dom.getPosition
  311 + * @function
  312 + * @grammar baidu.dom.getPosition(element)
  313 + * @param {HTMLElement|string} element 目标元素或目标元素的id
  314 + * @meta standard
  315 + *
  316 + * @returns {Object} 目标元素的位置,键值为top和left的Object。
  317 + */
  318 + baidu.dom.getPosition = function (element) {
  319 + element = baidu.dom.g(element);
  320 + var doc = baidu.dom.getDocument(element),
  321 + browser = baidu.browser,
  322 + getStyle = baidu.dom.getStyle,
  323 + // Gecko 1.9版本以下用getBoxObjectFor计算位置
  324 + // 但是某些情况下是有bug的
  325 + // 对于这些有bug的情况
  326 + // 使用递归查找的方式
  327 + BUGGY_GECKO_BOX_OBJECT = browser.isGecko > 0 &&
  328 + doc.getBoxObjectFor &&
  329 + getStyle(element, 'position') == 'absolute' &&
  330 + (element.style.top === '' || element.style.left === ''),
  331 + pos = {"left":0,"top":0},
  332 + viewport = (browser.ie && !browser.isStrict) ? doc.body : doc.documentElement,
  333 + parent,
  334 + box;
  335 +
  336 + if(element == viewport){
  337 + return pos;
  338 + }
  339 +
  340 + if(element.getBoundingClientRect){ // IE and Gecko 1.9+
  341 +
  342 + //当HTML或者BODY有border width时, 原生的getBoundingClientRect返回值是不符合预期的
  343 + //考虑到通常情况下 HTML和BODY的border只会设成0px,所以忽略该问题.
  344 + box = element.getBoundingClientRect();
  345 +
  346 + pos.left = Math.floor(box.left) + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft);
  347 + pos.top = Math.floor(box.top) + Math.max(doc.documentElement.scrollTop, doc.body.scrollTop);
  348 +
  349 + // IE会给HTML元素添加一个border,默认是medium(2px)
  350 + // 但是在IE 6 7 的怪异模式下,可以被html { border: 0; } 这条css规则覆盖
  351 + // 在IE7的标准模式下,border永远是2px,这个值通过clientLeft 和 clientTop取得
  352 + // 但是。。。在IE 6 7的怪异模式,如果用户使用css覆盖了默认的medium
  353 + // clientTop和clientLeft不会更新
  354 + pos.left -= doc.documentElement.clientLeft;
  355 + pos.top -= doc.documentElement.clientTop;
  356 +
  357 + var htmlDom = doc.body,
  358 + // 在这里,不使用element.style.borderLeftWidth,只有computedStyle是可信的
  359 + htmlBorderLeftWidth = parseInt(getStyle(htmlDom, 'borderLeftWidth')),
  360 + htmlBorderTopWidth = parseInt(getStyle(htmlDom, 'borderTopWidth'));
  361 + if(browser.ie && !browser.isStrict){
  362 + pos.left -= isNaN(htmlBorderLeftWidth) ? 2 : htmlBorderLeftWidth;
  363 + pos.top -= isNaN(htmlBorderTopWidth) ? 2 : htmlBorderTopWidth;
  364 + }
  365 + } else {
  366 + // safari/opera/firefox
  367 + parent = element;
  368 +
  369 + do {
  370 + pos.left += parent.offsetLeft;
  371 + pos.top += parent.offsetTop;
  372 +
  373 + // safari里面,如果遍历到了一个fixed的元素,后面的offset都不准了
  374 + if (browser.isWebkit > 0 && getStyle(parent, 'position') == 'fixed') {
  375 + pos.left += doc.body.scrollLeft;
  376 + pos.top += doc.body.scrollTop;
  377 + break;
  378 + }
  379 +
  380 + parent = parent.offsetParent;
  381 + } while (parent && parent != element);
  382 +
  383 + // 对body offsetTop的修正
  384 + if(browser.opera > 0 || (browser.isWebkit > 0 && getStyle(element, 'position') == 'absolute')){
  385 + pos.top -= doc.body.offsetTop;
  386 + }
  387 +
  388 + // 计算除了body的scroll
  389 + parent = element.offsetParent;
  390 + while (parent && parent != doc.body) {
  391 + pos.left -= parent.scrollLeft;
  392 + // see https://bugs.opera.com/show_bug.cgi?id=249965
  393 + if (!browser.opera || parent.tagName != 'TR') {
  394 + pos.top -= parent.scrollTop;
  395 + }
  396 + parent = parent.offsetParent;
  397 + }
  398 + }
  399 +
  400 + return pos;
  401 + };
  402 +
  403 + /**
  404 + * @ignore
  405 + * @namespace baidu.event 屏蔽浏览器差异性的事件封装。
  406 + * @property target 事件的触发元素
  407 + * @property pageX 鼠标事件的鼠标x坐标
  408 + * @property pageY 鼠标事件的鼠标y坐标
  409 + * @property keyCode 键盘事件的键值
  410 + */
  411 + baidu.event = baidu.event || {};
  412 +
  413 + /**
  414 + * 事件监听器的存储表
  415 + * @private
  416 + * @meta standard
  417 + */
  418 + baidu.event._listeners = baidu.event._listeners || [];
  419 +
  420 + /**
  421 + * 为目标元素添加事件监听器
  422 + * @name baidu.event.on
  423 + * @function
  424 + * @grammar baidu.event.on(element, type, listener)
  425 + * @param {HTMLElement|string|window} element 目标元素或目标元素id
  426 + * @param {string} type 事件类型
  427 + * @param {Function} listener 需要添加的监听器
  428 + * @remark
  429 + *
  430 + 1. 不支持跨浏览器的鼠标滚轮事件监听器添加<br>
  431 + 2. 改方法不为监听器灌入事件对象,以防止跨iframe事件挂载的事件对象获取失败
  432 +
  433 + * @shortcut on
  434 + * @meta standard
  435 + * @see baidu.event.un
  436 + *
  437 + * @returns {HTMLElement|window} 目标元素
  438 + */
  439 + baidu.event.on = function (element, type, listener) {
  440 + type = type.replace(/^on/i, '');
  441 + element = baidu.dom._g(element);
  442 +
  443 + var realListener = function (ev) {
  444 + // 1. 这里不支持EventArgument, 原因是跨frame的事件挂载
  445 + // 2. element是为了修正this
  446 + listener.call(element, ev);
  447 + },
  448 + lis = baidu.event._listeners,
  449 + filter = baidu.event._eventFilter,
  450 + afterFilter,
  451 + realType = type;
  452 + type = type.toLowerCase();
  453 + // filter过滤
  454 + if(filter && filter[type]){
  455 + afterFilter = filter[type](element, type, realListener);
  456 + realType = afterFilter.type;
  457 + realListener = afterFilter.listener;
  458 + }
  459 +
  460 + // 事件监听器挂载
  461 + if (element.addEventListener) {
  462 + element.addEventListener(realType, realListener, false);
  463 + } else if (element.attachEvent) {
  464 + element.attachEvent('on' + realType, realListener);
  465 + }
  466 +
  467 + // 将监听器存储到数组中
  468 + lis[lis.length] = [element, type, listener, realListener, realType];
  469 + return element;
  470 + };
  471 +
  472 + // 声明快捷方法
  473 + baidu.on = baidu.event.on;
  474 +
  475 + /**
  476 + * 返回一个当前页面的唯一标识字符串。
  477 + * @name baidu.lang.guid
  478 + * @function
  479 + * @grammar baidu.lang.guid()
  480 + * @version 1.1.1
  481 + * @meta standard
  482 + *
  483 + * @returns {String} 当前页面的唯一标识字符串
  484 + */
  485 +
  486 + (function(){
  487 + //不直接使用window,可以提高3倍左右性能
  488 + var guid = window[baidu.guid];
  489 +
  490 + baidu.lang.guid = function() {
  491 + return "TANGRAM__" + (guid._counter ++).toString(36);
  492 + };
  493 +
  494 + guid._counter = guid._counter || 1;
  495 + })();
  496 +
  497 + /**
  498 + * 所有类的实例的容器
  499 + * key为每个实例的guid
  500 + * @meta standard
  501 + */
  502 +
  503 + window[baidu.guid]._instances = window[baidu.guid]._instances || {};
  504 +
  505 + /**
  506 + * 判断目标参数是否为function或Function实例
  507 + * @name baidu.lang.isFunction
  508 + * @function
  509 + * @grammar baidu.lang.isFunction(source)
  510 + * @param {Any} source 目标参数
  511 + * @version 1.2
  512 + * @see baidu.lang.isString,baidu.lang.isObject,baidu.lang.isNumber,baidu.lang.isArray,baidu.lang.isElement,baidu.lang.isBoolean,baidu.lang.isDate
  513 + * @meta standard
  514 + * @returns {boolean} 类型判断结果
  515 + */
  516 + baidu.lang.isFunction = function (source) {
  517 + // chrome下,'function' == typeof /a/ 为true.
  518 + return '[object Function]' == Object.prototype.toString.call(source);
  519 + };
  520 +
  521 + /**
  522 + *
  523 + * @ignore
  524 + * @class Tangram继承机制提供的一个基类,用户可以通过继承baidu.lang.Class来获取它的属性及方法。
  525 + * @name baidu.lang.Class
  526 + * @grammar baidu.lang.Class(guid)
  527 + * @param {string} guid 对象的唯一标识
  528 + * @meta standard
  529 + * @remark baidu.lang.Class和它的子类的实例均包含一个全局唯一的标识guid。guid是在构造函数中生成的,因此,继承自baidu.lang.Class的类应该直接或者间接调用它的构造函数。<br>baidu.lang.Class的构造函数中产生guid的方式可以保证guid的唯一性,及每个实例都有一个全局唯一的guid。
  530 + * @meta standard
  531 + * @see baidu.lang.inherits,baidu.lang.Event
  532 + */
  533 + baidu.lang.Class = function(guid) {
  534 + this.guid = guid || baidu.lang.guid();
  535 + window[baidu.guid]._instances[this.guid] = this;
  536 + };
  537 + window[baidu.guid]._instances = window[baidu.guid]._instances || {};
  538 +
  539 + /**
  540 + * 释放对象所持有的资源,主要是自定义事件。
  541 + * @name dispose
  542 + * @grammar obj.dispose()
  543 + */
  544 + baidu.lang.Class.prototype.dispose = function(){
  545 + delete window[baidu.guid]._instances[this.guid];
  546 +
  547 + for(var property in this){
  548 + if (!baidu.lang.isFunction(this[property])) {
  549 + delete this[property];
  550 + }
  551 + }
  552 + this.disposed = true;
  553 + };
  554 +
  555 + /**
  556 + * 重载了默认的toString方法,使得返回信息更加准确一些。
  557 + * @return {string} 对象的String表示形式
  558 + */
  559 + baidu.lang.Class.prototype.toString = function(){
  560 + return "[object " + (this._className || "Object" ) + "]";
  561 + };
  562 +
  563 + /**
  564 + * @ignore
  565 + * @class 自定义的事件对象。
  566 + * @name baidu.lang.Event
  567 + * @grammar baidu.lang.Event(type[, target])
  568 + * @param {string} type 事件类型名称。为了方便区分事件和一个普通的方法,事件类型名称必须以"on"(小写)开头。
  569 + * @param {Object} [target]触发事件的对象
  570 + * @meta standard
  571 + * @remark 引入该模块,会自动为Class引入3个事件扩展方法:addEventListener、removeEventListener和dispatchEvent。
  572 + * @meta standard
  573 + * @see baidu.lang.Class
  574 + */
  575 + baidu.lang.Event = function (type, target) {
  576 + this.type = type;
  577 + this.returnValue = true;
  578 + this.target = target || null;
  579 + this.currentTarget = null;
  580 + };
  581 +
  582 + /**
  583 + * 注册对象的事件监听器。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
  584 + * @grammar obj.addEventListener(type, handlers[, key])
  585 + * @param {string} type 自定义事件的名称
  586 + * @param {Function} handler 自定义事件被触发时应该调用的回调函数
  587 + * @param {string} [key] 为事件监听函数指定的名称,可在移除时使用。如果不提供,方法会默认为它生成一个全局唯一的key。
  588 + * @remark 事件类型区分大小写。如果自定义事件名称不是以小写"on"开头,该方法会给它加上"on"再进行判断,即"click"和"onclick"会被认为是同一种事件。
  589 + */
  590 + baidu.lang.Class.prototype.addEventListener = function (type, handler, key) {
  591 + if (!baidu.lang.isFunction(handler)) {
  592 + return;
  593 + }
  594 +
  595 + !this.__listeners && (this.__listeners = {});
  596 +
  597 + var t = this.__listeners, id;
  598 + if (typeof key == "string" && key) {
  599 + if (/[^\w\-]/.test(key)) {
  600 + throw("nonstandard key:" + key);
  601 + } else {
  602 + handler.hashCode = key;
  603 + id = key;
  604 + }
  605 + }
  606 + type.indexOf("on") != 0 && (type = "on" + type);
  607 +
  608 + typeof t[type] != "object" && (t[type] = {});
  609 + id = id || baidu.lang.guid();
  610 + handler.hashCode = id;
  611 + t[type][id] = handler;
  612 + };
  613 +
  614 + /**
  615 + * 移除对象的事件监听器。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
  616 + * @grammar obj.removeEventListener(type, handlers)
  617 + * @param {string} type 事件类型
  618 + * @param {Function|string} handler 要移除的事件监听函数或者监听函数的key
  619 + * @remark 如果第二个参数handler没有被绑定到对应的自定义事件中,什么也不做。
  620 + */
  621 + baidu.lang.Class.prototype.removeEventListener = function (type, handler) {
  622 + if (typeof handler != "undefined") {
  623 + if ( (baidu.lang.isFunction(handler) && ! (handler = handler.hashCode))
  624 + || (! baidu.lang.isString(handler))
  625 + ){
  626 + return;
  627 + }
  628 + }
  629 +
  630 + !this.__listeners && (this.__listeners = {});
  631 +
  632 + type.indexOf("on") != 0 && (type = "on" + type);
  633 +
  634 + var t = this.__listeners;
  635 + if (!t[type]) {
  636 + return;
  637 + }
  638 + if (typeof handler != "undefined") {
  639 + t[type][handler] && delete t[type][handler];
  640 + } else {
  641 + for(var guid in t[type]){
  642 + delete t[type][guid];
  643 + }
  644 + }
  645 + };
  646 +
  647 + /**
  648 + * 派发自定义事件,使得绑定到自定义事件上面的函数都会被执行。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
  649 + * @grammar obj.dispatchEvent(event, options)
  650 + * @param {baidu.lang.Event|String} event Event对象,或事件名称(1.1.1起支持)
  651 + * @param {Object} options 扩展参数,所含属性键值会扩展到Event对象上(1.2起支持)
  652 + * @remark 处理会调用通过addEventListenr绑定的自定义事件回调函数之外,还会调用直接绑定到对象上面的自定义事件。例如:<br>
  653 + myobj.onMyEvent = function(){}<br>
  654 + myobj.addEventListener("onMyEvent", function(){});
  655 + */
  656 + baidu.lang.Class.prototype.dispatchEvent = function (event, options) {
  657 + if (baidu.lang.isString(event)) {
  658 + event = new baidu.lang.Event(event);
  659 + }
  660 + !this.__listeners && (this.__listeners = {});
  661 +
  662 + // 20100603 添加本方法的第二个参数,将 options extend到event中去传递
  663 + options = options || {};
  664 + for (var i in options) {
  665 + event[i] = options[i];
  666 + }
  667 +
  668 + var i, t = this.__listeners, p = event.type;
  669 + event.target = event.target || this;
  670 + event.currentTarget = this;
  671 +
  672 + p.indexOf("on") != 0 && (p = "on" + p);
  673 +
  674 + baidu.lang.isFunction(this[p]) && this[p].apply(this, arguments);
  675 +
  676 + if (typeof t[p] == "object") {
  677 + for (i in t[p]) {
  678 + t[p][i].apply(this, arguments);
  679 + }
  680 + }
  681 + return event.returnValue;
  682 + };
  683 +
  684 +
  685 + baidu.lang.inherits = function (subClass, superClass, className) {
  686 + var key, proto,
  687 + selfProps = subClass.prototype,
  688 + clazz = new Function();
  689 +
  690 + clazz.prototype = superClass.prototype;
  691 + proto = subClass.prototype = new clazz();
  692 + for (key in selfProps) {
  693 + proto[key] = selfProps[key];
  694 + }
  695 + subClass.prototype.constructor = subClass;
  696 + subClass.superClass = superClass.prototype;
  697 +
  698 + // 类名标识,兼容Class的toString,基本没用
  699 + if ("string" == typeof className) {
  700 + proto._className = className;
  701 + }
  702 + };
  703 + // 声明快捷方法
  704 + baidu.inherits = baidu.lang.inherits;
  705 + })();
  706 +
  707 +
  708 + /**
  709 +
  710 + * 图片的路径
  711 +
  712 + * @private
  713 + * @type {String}
  714 +
  715 + */
  716 + var _IMAGE_PATH = '//api.map.baidu.com/library/TextIconOverlay/1.2/src/images/m';
  717 +
  718 + /**
  719 +
  720 + * 图片的后缀名
  721 +
  722 + * @private
  723 + * @type {String}
  724 +
  725 + */
  726 + var _IMAGE_EXTENSION = 'png';
  727 +
  728 + /**
  729 + *@exports TextIconOverlay as BMapLib.TextIconOverlay
  730 + */
  731 + var TextIconOverlay =
  732 + /**
  733 + * TextIconOverlay
  734 + * @class 此类表示地图上的一个覆盖物,该覆盖物由文字和图标组成,从Overlay继承。文字通常是数字(0-9)或字母(A-Z ),而文字与图标之间有一定的映射关系。
  735 + *该覆盖物适用于以下类似的场景:需要在地图上添加一系列覆盖物,这些覆盖物之间用不同的图标和文字来区分,文字可能表示了该覆盖物的某一属性值,根据该文字和一定的映射关系,自动匹配相应颜色和大小的图标。
  736 + *
  737 + *@constructor
  738 + *@param {Point} position 表示一个经纬度坐标位置。
  739 + *@param {String} text 表示该覆盖物显示的文字信息。
  740 + *@param {Json Object} options 可选参数,可选项包括:<br />
  741 + *"<b>styles</b>":{Array<IconStyle>} 一组图标风格。单个图表风格包括以下几个属性:<br />
  742 + * url {String} 图片的url地址。(必选)<br />
  743 + * size {Size} 图片的大小。(必选)<br />
  744 + * anchor {Size} 图标定位在地图上的位置相对于图标左上角的偏移值,默认偏移值为图标的中心位置。(可选)<br />
  745 + * offset {Size} 图片相对于可视区域的偏移值,此功能的作用等同于CSS中的background-position属性。(可选)<br />
  746 + * textSize {Number} 文字的大小。(可选,默认10)<br />
  747 + * textColor {String} 文字的颜色。(可选,默认black)<br />
  748 + */
  749 + BMapLib.TextIconOverlay = function(position, text, options){
  750 + this._position = position;
  751 + this._text = text;
  752 + this._options = options || {};
  753 + this._styles = this._options['styles'] || [];
  754 + (!this._styles.length) && this._setupDefaultStyles();
  755 + };
  756 +
  757 + T.lang.inherits(TextIconOverlay, BMap.Overlay, "TextIconOverlay");
  758 +
  759 + TextIconOverlay.prototype._setupDefaultStyles = function(){
  760 + var sizes = [53, 56, 66, 78, 90];
  761 + for(var i = 0, size; size = sizes[i]; i++){
  762 + this._styles.push({
  763 + url:_IMAGE_PATH + i + '.' + _IMAGE_EXTENSION,
  764 + size: new BMap.Size(size, size)
  765 + });
  766 + }//for循环的简洁写法
  767 + };
  768 +
  769 + /**
  770 + *继承Overlay的intialize方法,自定义覆盖物时必须。
  771 + *@param {Map} map BMap.Map的实例化对象。
  772 + *@return {HTMLElement} 返回覆盖物对应的HTML元素。
  773 + */
  774 + TextIconOverlay.prototype.initialize = function(map){
  775 + this._map = map;
  776 +
  777 + this._domElement = document.createElement('div');
  778 + this._updateCss();
  779 + this._updateText();
  780 + this._updatePosition();
  781 +
  782 + this._bind();
  783 +
  784 + this._map.getPanes().markerMouseTarget.appendChild(this._domElement);
  785 + return this._domElement;
  786 + };
  787 +
  788 + /**
  789 + *继承Overlay的draw方法,自定义覆盖物时必须。
  790 + *@return 无返回值。
  791 + */
  792 + TextIconOverlay.prototype.draw = function(){
  793 + this._map && this._updatePosition();
  794 + };
  795 +
  796 + /**
  797 + *获取该覆盖物上的文字。
  798 + *@return {String} 该覆盖物上的文字。
  799 + */
  800 + TextIconOverlay.prototype.getText = function(){
  801 + return this._text;
  802 + };
  803 +
  804 + /**
  805 + *设置该覆盖物上的文字。
  806 + *@param {String} text 要设置的文字,通常是字母A-Z或数字0-9。
  807 + *@return 无返回值。
  808 + */
  809 + TextIconOverlay.prototype.setText = function(text){
  810 + if(text && (!this._text || (this._text.toString() != text.toString()))){
  811 + this._text = text;
  812 + this._updateText();
  813 + this._updateCss();
  814 + this._updatePosition();
  815 + }
  816 + };
  817 +
  818 + /**
  819 + *获取该覆盖物的位置。
  820 + *@return {Point} 该覆盖物的经纬度坐标。
  821 + */
  822 + TextIconOverlay.prototype.getPosition = function () {
  823 + return this._position;
  824 + };
  825 +
  826 + /**
  827 + *设置该覆盖物的位置。
  828 + *@param {Point} position 要设置的经纬度坐标。
  829 + *@return 无返回值。
  830 + */
  831 + TextIconOverlay.prototype.setPosition = function (position) {
  832 + if(position && (!this._position || !this._position.equals(position))){
  833 + this._position = position;
  834 + this._updatePosition();
  835 + }
  836 + };
  837 +
  838 + /**
  839 + *由文字信息获取风格数组的对应索引值。
  840 + *内部默认的对应函数为文字转换为数字除以10的结果,比如文字8返回索引0,文字25返回索引2.
  841 + *如果需要自定义映射关系,请覆盖该函数。
  842 + *@param {String} text 文字。
  843 + *@param {Array<IconStyle>} styles 一组图标风格。
  844 + *@return {Number} 对应的索引值。
  845 + */
  846 + TextIconOverlay.prototype.getStyleByText = function(text, styles){
  847 + var count = parseInt(text);
  848 + var index = parseInt(count / 10);
  849 + index = Math.max(0, index);
  850 + index = Math.min(index, styles.length - 1);
  851 + return styles[index];
  852 + }
  853 +
  854 + /**
  855 + *更新相应的CSS。
  856 + *@return 无返回值。
  857 + */
  858 + TextIconOverlay.prototype._updateCss = function(){
  859 + var style = this.getStyleByText(this._text, this._styles);
  860 + this._domElement.style.cssText = this._buildCssText(style);
  861 + };
  862 +
  863 + /**
  864 + *更新覆盖物的显示文字。
  865 + *@return 无返回值。
  866 + */
  867 + TextIconOverlay.prototype._updateText = function(){
  868 + if (this._domElement) {
  869 + this._domElement.innerHTML = this._text;
  870 + }
  871 + };
  872 +
  873 + /**
  874 + *调整覆盖物在地图上的位置更新覆盖物的显示文字。
  875 + *@return 无返回值。
  876 + */
  877 + TextIconOverlay.prototype._updatePosition = function(){
  878 + if (this._domElement && this._position) {
  879 + var style = this._domElement.style;
  880 + var pixelPosition= this._map.pointToOverlayPixel(this._position);
  881 + pixelPosition.x -= Math.ceil(parseInt(style.width) / 2);
  882 + pixelPosition.y -= Math.ceil(parseInt(style.height) / 2);
  883 + style.left = pixelPosition.x + "px";
  884 + style.top = pixelPosition.y + "px";
  885 + }
  886 + };
  887 +
  888 + /**
  889 + * 为该覆盖物的HTML元素构建CSS
  890 + * @param {IconStyle} 一个图标的风格。
  891 + * @return {String} 构建完成的CSSTEXT。
  892 + */
  893 + TextIconOverlay.prototype._buildCssText = function(style) {
  894 + //根据style来确定一些默认值
  895 + var url = style['url'];
  896 + var size = style['size'];
  897 + var anchor = style['anchor'];
  898 + var offset = style['offset'];
  899 + var textColor = style['textColor'] || 'black';
  900 + var textSize = style['textSize'] || 10;
  901 +
  902 + var csstext = [];
  903 + if (T.browser["ie"] < 7) {
  904 + csstext.push('filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(' +
  905 + 'sizingMethod=scale,src="' + url + '");');
  906 + } else {
  907 + csstext.push('background-image:url(' + url + ');');
  908 + var backgroundPosition = '0 0';
  909 + (offset instanceof BMap.Size) && (backgroundPosition = offset.width + 'px' + ' ' + offset.height + 'px');
  910 + csstext.push('background-position:' + backgroundPosition + ';');
  911 + }
  912 +
  913 + if (size instanceof BMap.Size){
  914 + if (anchor instanceof BMap.Size) {
  915 + if (anchor.height > 0 && anchor.height < size.height) {
  916 + csstext.push('height:' + (size.height - anchor.height) + 'px; padding-top:' + anchor.height + 'px;');
  917 + }
  918 + if(anchor.width > 0 && anchor.width < size.width){
  919 + csstext.push('width:' + (size.width - anchor.width) + 'px; padding-left:' + anchor.width + 'px;');
  920 + }
  921 + } else {
  922 + csstext.push('height:' + size.height + 'px; line-height:' + size.height + 'px;');
  923 + csstext.push('width:' + size.width + 'px; text-align:center;');
  924 + }
  925 + }
  926 +
  927 + csstext.push('cursor:pointer; color:' + textColor + '; position:absolute; font-size:' +
  928 + textSize + 'px; font-family:Arial,sans-serif; font-weight:bold');
  929 + return csstext.join('');
  930 + };
  931 +
  932 +
  933 + /**
  934 +
  935 + * 当鼠标点击该覆盖物时会触发该事件
  936 +
  937 + * @name TextIconOverlay#click
  938 +
  939 + * @event
  940 +
  941 + * @param {Event Object} e 回调函数会返回event参数,包括以下返回值:
  942 +
  943 + * <br />"<b>type</b> : {String} 事件类型
  944 +
  945 + * <br />"<b>target</b>:{BMapLib.TextIconOverlay} 事件目标
  946 +
  947 + *
  948 +
  949 + */
  950 +
  951 + /**
  952 +
  953 + * 当鼠标进入该覆盖物区域时会触发该事件
  954 +
  955 + * @name TextIconOverlay#mouseover
  956 +
  957 + * @event
  958 + * @param {Event Object} e 回调函数会返回event参数,包括以下返回值:
  959 +
  960 + * <br />"<b>type</b> : {String} 事件类型
  961 +
  962 + * <br />"<b>target</b>:{BMapLib.TextIconOverlay} 事件目标
  963 +
  964 + * <br />"<b>point</b> : {BMap.Point} 最新添加上的节点BMap.Point对象
  965 +
  966 + * <br />"<b>pixel</b>:{BMap.pixel} 最新添加上的节点BMap.Pixel对象
  967 +
  968 + *
  969 +
  970 + * @example <b>参考示例:</b><br />
  971 +
  972 + * myTextIconOverlay.addEventListener("mouseover", function(e) { alert(e.point); });
  973 +
  974 + */
  975 +
  976 + /**
  977 +
  978 + * 当鼠标离开该覆盖物区域时会触发该事件
  979 +
  980 + * @name TextIconOverlay#mouseout
  981 +
  982 + * @event
  983 +
  984 + * @param {Event Object} e 回调函数会返回event参数,包括以下返回值:
  985 +
  986 + * <br />"<b>type</b> : {String} 事件类型
  987 +
  988 + * <br />"<b>target</b>:{BMapLib.TextIconOverlay} 事件目标
  989 +
  990 + * <br />"<b>point</b> : {BMap.Point} 最新添加上的节点BMap.Point对象
  991 +
  992 + * <br />"<b>pixel</b>:{BMap.pixel} 最新添加上的节点BMap.Pixel对象
  993 +
  994 + *
  995 +
  996 + * @example <b>参考示例:</b><br />
  997 +
  998 + * myTextIconOverlay.addEventListener("mouseout", function(e) { alert(e.point); });
  999 +
  1000 + */
  1001 +
  1002 +
  1003 + /**
  1004 + * 为该覆盖物绑定一系列事件
  1005 + * 当前支持click mouseover mouseout
  1006 + * @return 无返回值。
  1007 + */
  1008 + TextIconOverlay.prototype._bind = function(){
  1009 + if (!this._domElement){
  1010 + return;
  1011 + }
  1012 +
  1013 + var me = this;
  1014 + var map = this._map;
  1015 +
  1016 + var BaseEvent = T.lang.Event;
  1017 + function eventExtend(e, be){
  1018 + var elem = e.srcElement || e.target;
  1019 + var x = e.clientX || e.pageX;
  1020 + var y = e.clientY || e.pageY;
  1021 + if (e && be && x && y && elem){
  1022 + var offset = T.dom.getPosition(map.getContainer());
  1023 + be.pixel = new BMap.Pixel(x - offset.left, y - offset.top);
  1024 + be.point = map.pixelToPoint(be.pixel);
  1025 + }
  1026 + return be;
  1027 + }//给事件参数增加pixel和point两个值
  1028 +
  1029 + T.event.on(this._domElement,"mouseover", function(e){
  1030 + me.dispatchEvent(eventExtend(e, new BaseEvent("onmouseover")));
  1031 + });
  1032 + T.event.on(this._domElement,"mouseout", function(e){
  1033 + me.dispatchEvent(eventExtend(e, new BaseEvent("onmouseout")));
  1034 + });
  1035 + T.event.on(this._domElement,"click", function(e){
  1036 + me.dispatchEvent(eventExtend(e, new BaseEvent("onclick")));
  1037 + });
  1038 + };
  1039 +
1040 1040 })();
1041 1041 \ No newline at end of file
... ...