Commit 26a1b1437a90468e84db6e711c6108f6e70cd28f
1 parent
3def45f6
时刻表地铁接轨
Showing
8 changed files
with
1507 additions
and
0 deletions
src/main/java/com/bsth/controller/ttinfo/DtController.java
0 → 100644
| 1 | +package com.bsth.controller.ttinfo; | ||
| 2 | + | ||
| 3 | +import com.bsth.controller.BaseController; | ||
| 4 | +import com.bsth.entity.ttinfo.ScheduleDt; | ||
| 5 | +import com.bsth.service.ttinfo.DtService; | ||
| 6 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 7 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 8 | +import org.springframework.web.bind.annotation.RestController; | ||
| 9 | + | ||
| 10 | +import java.util.Map; | ||
| 11 | + | ||
| 12 | +@RestController | ||
| 13 | +@RequestMapping("dt") | ||
| 14 | +public class DtController extends BaseController<ScheduleDt, Integer> { | ||
| 15 | + | ||
| 16 | + @Autowired | ||
| 17 | + private DtService dtService; | ||
| 18 | + //分组查询地铁线路及站点 | ||
| 19 | + @RequestMapping("list_group") | ||
| 20 | + public Map<String, Object> listGroup(){ | ||
| 21 | + return dtService.listGroup(); | ||
| 22 | + } | ||
| 23 | +} |
src/main/java/com/bsth/entity/ttinfo/ScheduleDt.java
0 → 100644
| 1 | +package com.bsth.entity.ttinfo; | ||
| 2 | + | ||
| 3 | +import javax.persistence.*; | ||
| 4 | + | ||
| 5 | +@Entity | ||
| 6 | +@Table(name = "bsth_c_schedule_dt") | ||
| 7 | +public class ScheduleDt { | ||
| 8 | + @Id | ||
| 9 | + @GeneratedValue(strategy = GenerationType.IDENTITY) | ||
| 10 | + private Integer id; | ||
| 11 | + private String line; | ||
| 12 | + private String direction; | ||
| 13 | + private String station; | ||
| 14 | + private String trainNumber; | ||
| 15 | + private String arrivalTime; | ||
| 16 | + | ||
| 17 | + public Integer getId() { | ||
| 18 | + return id; | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + public void setId(Integer id) { | ||
| 22 | + this.id = id; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + public String getLine() { | ||
| 26 | + return line; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + public void setLine(String line) { | ||
| 30 | + this.line = line; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + public String getDirection() { | ||
| 34 | + return direction; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + public void setDirection(String direction) { | ||
| 38 | + this.direction = direction; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + public String getStation() { | ||
| 42 | + return station; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + public void setStation(String station) { | ||
| 46 | + this.station = station; | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + public String getTrainNumber() { | ||
| 50 | + return trainNumber; | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + public void setTrainNumber(String trainNumber) { | ||
| 54 | + this.trainNumber = trainNumber; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + public String getArrivalTime() { | ||
| 58 | + return arrivalTime; | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + public void setArrivalTime(String arrivalTime) { | ||
| 62 | + this.arrivalTime = arrivalTime; | ||
| 63 | + } | ||
| 64 | +} |
src/main/java/com/bsth/repository/ttinfo/DtRepository.java
0 → 100644
| 1 | +package com.bsth.repository.ttinfo; | ||
| 2 | + | ||
| 3 | +import com.bsth.entity.ttinfo.ScheduleDt; | ||
| 4 | +import com.bsth.repository.BaseRepository; | ||
| 5 | +import org.springframework.data.jpa.repository.Query; | ||
| 6 | +import org.springframework.stereotype.Repository; | ||
| 7 | + | ||
| 8 | +import java.util.List; | ||
| 9 | +import java.util.Map; | ||
| 10 | + | ||
| 11 | +@Repository | ||
| 12 | +public interface DtRepository extends BaseRepository<ScheduleDt, Integer> { | ||
| 13 | + | ||
| 14 | + @Query(value = "SELECT line,direction,station from bsth_c_schedule_dt GROUP BY line,direction,station,order_station",nativeQuery=true) | ||
| 15 | + List<Map> listGroup(); | ||
| 16 | + | ||
| 17 | +} |
src/main/java/com/bsth/service/ttinfo/DtService.java
0 → 100644
src/main/java/com/bsth/service/ttinfo/impl/DtServiceImpl.java
0 → 100644
| 1 | +package com.bsth.service.ttinfo.impl; | ||
| 2 | + | ||
| 3 | +import com.bsth.entity.ttinfo.ScheduleDt; | ||
| 4 | +import com.bsth.repository.ttinfo.DtRepository; | ||
| 5 | +import com.bsth.service.impl.BaseServiceImpl; | ||
| 6 | +import com.bsth.service.ttinfo.DtService; | ||
| 7 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 8 | +import org.springframework.stereotype.Service; | ||
| 9 | + | ||
| 10 | +import java.util.ArrayList; | ||
| 11 | +import java.util.HashMap; | ||
| 12 | +import java.util.List; | ||
| 13 | +import java.util.Map; | ||
| 14 | + | ||
| 15 | +@Service | ||
| 16 | +public class DtServiceImpl extends BaseServiceImpl<ScheduleDt, Integer> implements DtService { | ||
| 17 | + | ||
| 18 | + @Autowired | ||
| 19 | + private DtRepository dtRepository; | ||
| 20 | + @Override | ||
| 21 | + public Map<String, Object> listGroup() { | ||
| 22 | + //防止后期加入新的地铁线路 | ||
| 23 | + List<Map> list = dtRepository.listGroup(); | ||
| 24 | + // 需将读取到的数据按照 "线路 - 上下行 - 站点" 的结构进行保存 | ||
| 25 | + Map<String, Object> lineMap = new HashMap<>(); // 储存线路 | ||
| 26 | + List<Map> directionList = new ArrayList<>();// 储存方向 | ||
| 27 | + | ||
| 28 | + if (list != null) { | ||
| 29 | + String currentLine = null; | ||
| 30 | + for (Map item : list) { | ||
| 31 | + String lineKey = item.get("line").toString(); | ||
| 32 | + String directionKey = item.get("direction").toString(); | ||
| 33 | + | ||
| 34 | + if (lineKey != null && !lineKey.isEmpty()) { | ||
| 35 | + // 如果线路发生变化,先将 directionList 保存到 lineMap 中,然后清空 directionList | ||
| 36 | + if (currentLine != null && !currentLine.equals(lineKey)) { | ||
| 37 | + lineMap.put(currentLine, directionList); | ||
| 38 | + directionList = new ArrayList<>(); | ||
| 39 | + } | ||
| 40 | + currentLine = lineKey; | ||
| 41 | + | ||
| 42 | + // 将当前方向数据放入 directionList | ||
| 43 | + if (directionKey != null && !directionKey.isEmpty()) { | ||
| 44 | + directionList.add(item); | ||
| 45 | + } | ||
| 46 | + } | ||
| 47 | + } | ||
| 48 | + // 循环结束后,将最后一组数据存入 lineMap | ||
| 49 | + if (currentLine != null) { | ||
| 50 | + lineMap.put(currentLine, directionList); | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + return lineMap; | ||
| 55 | + } | ||
| 56 | +} |
src/main/resources/static/pages/base/timesmodel/dt/dt.html
0 → 100644
| 1 | +<style> | ||
| 2 | + /* Tailwind CSS 基础样式 */ | ||
| 3 | + *, ::before, ::after { | ||
| 4 | + box-sizing: border-box; | ||
| 5 | + border-width: 0; | ||
| 6 | + border-style: solid; | ||
| 7 | + border-color: #e5e7eb; | ||
| 8 | + } | ||
| 9 | + | ||
| 10 | + html { | ||
| 11 | + line-height: 1.5; | ||
| 12 | + -webkit-text-size-adjust: 100%; | ||
| 13 | + -moz-tab-size: 4; | ||
| 14 | + tab-size: 4; | ||
| 15 | + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + body { | ||
| 19 | + margin: 0; | ||
| 20 | + line-height: inherit; | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + hr { | ||
| 24 | + height: 0; | ||
| 25 | + color: inherit; | ||
| 26 | + border-top-width: 1px; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + abbr:where([title]) { | ||
| 30 | + text-decoration: underline dotted; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + h1, h2, h3, h4, h5, h6 { | ||
| 34 | + font-size: inherit; | ||
| 35 | + font-weight: inherit; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + a { | ||
| 39 | + color: inherit; | ||
| 40 | + text-decoration: inherit; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + b, strong { | ||
| 44 | + font-weight: bolder; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + code, kbd, samp, pre { | ||
| 48 | + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; | ||
| 49 | + font-size: 1em; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + small { | ||
| 53 | + font-size: 80%; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + sub, sup { | ||
| 57 | + font-size: 75%; | ||
| 58 | + line-height: 0; | ||
| 59 | + position: relative; | ||
| 60 | + vertical-align: baseline; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + sub { | ||
| 64 | + bottom: -0.25em; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + sup { | ||
| 68 | + top: -0.5em; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + table { | ||
| 72 | + text-indent: 0; | ||
| 73 | + border-color: inherit; | ||
| 74 | + border-collapse: collapse; | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + button, input, optgroup, select, textarea { | ||
| 78 | + font-family: inherit; | ||
| 79 | + font-size: 100%; | ||
| 80 | + line-height: inherit; | ||
| 81 | + color: inherit; | ||
| 82 | + margin: 0; | ||
| 83 | + padding: 0; | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + button, select { | ||
| 87 | + text-transform: none; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + button, [type='button'], [type='reset'], [type='submit'] { | ||
| 91 | + -webkit-appearance: button; | ||
| 92 | + background-color: transparent; | ||
| 93 | + background-image: none; | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + :-moz-focusring { | ||
| 97 | + outline: auto; | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + :-moz-ui-invalid { | ||
| 101 | + box-shadow: none; | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + progress { | ||
| 105 | + vertical-align: baseline; | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + ::-webkit-inner-spin-button, ::-webkit-outer-spin-button { | ||
| 109 | + height: auto; | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + [type='search'] { | ||
| 113 | + -webkit-appearance: textfield; | ||
| 114 | + outline-offset: -2px; | ||
| 115 | + } | ||
| 116 | + | ||
| 117 | + ::-webkit-search-decoration { | ||
| 118 | + -webkit-appearance: none; | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + ::-webkit-file-upload-button { | ||
| 122 | + -webkit-appearance: button; | ||
| 123 | + font: inherit; | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + summary { | ||
| 127 | + display: list-item; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + blockquote, dl, dd, h1, h2, h3, h4, h5, h6, hr, figure, p, pre { | ||
| 131 | + margin: 0; | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + fieldset { | ||
| 135 | + margin: 0; | ||
| 136 | + padding: 0; | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + legend { | ||
| 140 | + padding: 0; | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + ol, ul, menu { | ||
| 144 | + list-style: none; | ||
| 145 | + margin: 0; | ||
| 146 | + padding: 0; | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + textarea { | ||
| 150 | + resize: vertical; | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + input::placeholder, textarea::placeholder { | ||
| 154 | + opacity: 1; | ||
| 155 | + color: #9ca3af; | ||
| 156 | + } | ||
| 157 | + | ||
| 158 | + button, [role="button"] { | ||
| 159 | + cursor: pointer; | ||
| 160 | + } | ||
| 161 | + | ||
| 162 | + :disabled { | ||
| 163 | + cursor: default; | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + img, svg, video, canvas, audio, iframe, embed, object { | ||
| 167 | + display: block; | ||
| 168 | + vertical-align: middle; | ||
| 169 | + } | ||
| 170 | + | ||
| 171 | + img, video { | ||
| 172 | + max-width: 100%; | ||
| 173 | + height: auto; | ||
| 174 | + } | ||
| 175 | + | ||
| 176 | + [hidden] { | ||
| 177 | + display: none; | ||
| 178 | + } | ||
| 179 | + | ||
| 180 | + /* Tailwind 预检样式结束 */ | ||
| 181 | + | ||
| 182 | + /* 容器类 */ | ||
| 183 | + .container { | ||
| 184 | + width: 100%; | ||
| 185 | + } | ||
| 186 | + | ||
| 187 | + @media (min-width: 640px) { | ||
| 188 | + .container { | ||
| 189 | + max-width: 640px; | ||
| 190 | + } | ||
| 191 | + } | ||
| 192 | + | ||
| 193 | + @media (min-width: 768px) { | ||
| 194 | + .container { | ||
| 195 | + max-width: 768px; | ||
| 196 | + } | ||
| 197 | + } | ||
| 198 | + | ||
| 199 | + @media (min-width: 1024px) { | ||
| 200 | + .container { | ||
| 201 | + max-width: 1024px; | ||
| 202 | + } | ||
| 203 | + } | ||
| 204 | + | ||
| 205 | + @media (min-width: 1280px) { | ||
| 206 | + .container { | ||
| 207 | + max-width: 1280px; | ||
| 208 | + } | ||
| 209 | + } | ||
| 210 | + | ||
| 211 | + @media (min-width: 1536px) { | ||
| 212 | + .container { | ||
| 213 | + max-width: 1536px; | ||
| 214 | + } | ||
| 215 | + } | ||
| 216 | + | ||
| 217 | + /* 布局类 */ | ||
| 218 | + .mx-auto { | ||
| 219 | + margin-left: auto; | ||
| 220 | + margin-right: auto; | ||
| 221 | + } | ||
| 222 | + | ||
| 223 | + .flex { | ||
| 224 | + display: flex; | ||
| 225 | + } | ||
| 226 | + | ||
| 227 | + .grid { | ||
| 228 | + display: grid; | ||
| 229 | + } | ||
| 230 | + | ||
| 231 | + .hidden { | ||
| 232 | + display: none; | ||
| 233 | + } | ||
| 234 | + | ||
| 235 | + .items-center { | ||
| 236 | + align-items: center; | ||
| 237 | + } | ||
| 238 | + | ||
| 239 | + .justify-center { | ||
| 240 | + justify-content: center; | ||
| 241 | + } | ||
| 242 | + | ||
| 243 | + .justify-between { | ||
| 244 | + justify-content: space-between; | ||
| 245 | + } | ||
| 246 | + | ||
| 247 | + .space-y-2 > :not([hidden]) ~ :not([hidden]) { | ||
| 248 | + margin-top: 0.5rem; | ||
| 249 | + } | ||
| 250 | + | ||
| 251 | + .space-y-4 > :not([hidden]) ~ :not([hidden]) { | ||
| 252 | + margin-top: 1rem; | ||
| 253 | + } | ||
| 254 | + | ||
| 255 | + .space-y-6 > :not([hidden]) ~ :not([hidden]) { | ||
| 256 | + margin-top: 1.5rem; | ||
| 257 | + } | ||
| 258 | + | ||
| 259 | + .text-center { | ||
| 260 | + text-align: center; | ||
| 261 | + } | ||
| 262 | + | ||
| 263 | + .overflow-y-auto { | ||
| 264 | + overflow-y: auto; | ||
| 265 | + } | ||
| 266 | + | ||
| 267 | + .scrollbar-thin::-webkit-scrollbar { | ||
| 268 | + width: 6px; | ||
| 269 | + } | ||
| 270 | + | ||
| 271 | + .scrollbar-thumb-gray-300::-webkit-scrollbar-thumb { | ||
| 272 | + background-color: #d1d5db; | ||
| 273 | + border-radius: 3px; | ||
| 274 | + } | ||
| 275 | + | ||
| 276 | + .scrollbar-track-gray-100::-webkit-scrollbar-track { | ||
| 277 | + background-color: #f3f4f6; | ||
| 278 | + } | ||
| 279 | + | ||
| 280 | + /* 网格布局 */ | ||
| 281 | + .grid-cols-1 { | ||
| 282 | + grid-template-columns: repeat(1, minmax(0, 1fr)); | ||
| 283 | + } | ||
| 284 | + | ||
| 285 | + @media (min-width: 768px) { | ||
| 286 | + .md\:grid-cols-2 { | ||
| 287 | + grid-template-columns: repeat(2, minmax(0, 1fr)); | ||
| 288 | + } | ||
| 289 | + } | ||
| 290 | + | ||
| 291 | + @media (min-width: 1024px) { | ||
| 292 | + .lg\:grid-cols-2 { | ||
| 293 | + grid-template-columns: repeat(2, minmax(0, 1fr)); | ||
| 294 | + } | ||
| 295 | + .lg\:grid-cols-3 { | ||
| 296 | + grid-template-columns: repeat(3, minmax(0, 1fr)); | ||
| 297 | + } | ||
| 298 | + } | ||
| 299 | + | ||
| 300 | + .gap-4 { | ||
| 301 | + gap: 1rem; | ||
| 302 | + } | ||
| 303 | + | ||
| 304 | + .gap-6 { | ||
| 305 | + gap: 1.5rem; | ||
| 306 | + } | ||
| 307 | + | ||
| 308 | + /* 间距 */ | ||
| 309 | + .p-4 { | ||
| 310 | + padding: 1rem; | ||
| 311 | + } | ||
| 312 | + | ||
| 313 | + .p-6 { | ||
| 314 | + padding: 1.5rem; | ||
| 315 | + } | ||
| 316 | + | ||
| 317 | + .px-3 { | ||
| 318 | + padding-left: 0.75rem; | ||
| 319 | + padding-right: 0.75rem; | ||
| 320 | + } | ||
| 321 | + | ||
| 322 | + .px-6 { | ||
| 323 | + padding-left: 1.5rem; | ||
| 324 | + padding-right: 1.5rem; | ||
| 325 | + } | ||
| 326 | + | ||
| 327 | + .py-2 { | ||
| 328 | + padding-top: 0.5rem; | ||
| 329 | + padding-bottom: 0.5rem; | ||
| 330 | + } | ||
| 331 | + | ||
| 332 | + .py-3 { | ||
| 333 | + padding-top: 0.75rem; | ||
| 334 | + padding-bottom: 0.75rem; | ||
| 335 | + } | ||
| 336 | + | ||
| 337 | + .py-8 { | ||
| 338 | + padding-top: 2rem; | ||
| 339 | + padding-bottom: 2rem; | ||
| 340 | + } | ||
| 341 | + | ||
| 342 | + .py-12 { | ||
| 343 | + padding-top: 3rem; | ||
| 344 | + padding-bottom: 3rem; | ||
| 345 | + } | ||
| 346 | + | ||
| 347 | + .mb-4 { | ||
| 348 | + margin-bottom: 1rem; | ||
| 349 | + } | ||
| 350 | + | ||
| 351 | + .mb-8 { | ||
| 352 | + margin-bottom: 2rem; | ||
| 353 | + } | ||
| 354 | + | ||
| 355 | + .ml-3 { | ||
| 356 | + margin-left: 0.75rem; | ||
| 357 | + } | ||
| 358 | + | ||
| 359 | + .mr-2 { | ||
| 360 | + margin-right: 0.5rem; | ||
| 361 | + } | ||
| 362 | + | ||
| 363 | + .mr-3 { | ||
| 364 | + margin-right: 0.75rem; | ||
| 365 | + } | ||
| 366 | + | ||
| 367 | + .mt-2 { | ||
| 368 | + margin-top: 0.5rem; | ||
| 369 | + } | ||
| 370 | + | ||
| 371 | + .mt-8 { | ||
| 372 | + margin-top: 2rem; | ||
| 373 | + } | ||
| 374 | + | ||
| 375 | + /* 尺寸 */ | ||
| 376 | + .h-4 { | ||
| 377 | + height: 1rem; | ||
| 378 | + } | ||
| 379 | + | ||
| 380 | + .h-5 { | ||
| 381 | + height: 1.25rem; | ||
| 382 | + } | ||
| 383 | + | ||
| 384 | + .h-8 { | ||
| 385 | + height: 2rem; | ||
| 386 | + } | ||
| 387 | + | ||
| 388 | + .h-12 { | ||
| 389 | + height: 3rem; | ||
| 390 | + } | ||
| 391 | + | ||
| 392 | + .w-4 { | ||
| 393 | + width: 1rem; | ||
| 394 | + } | ||
| 395 | + | ||
| 396 | + .w-5 { | ||
| 397 | + width: 1.25rem; | ||
| 398 | + } | ||
| 399 | + | ||
| 400 | + .w-8 { | ||
| 401 | + width: 2rem; | ||
| 402 | + } | ||
| 403 | + | ||
| 404 | + .w-12 { | ||
| 405 | + width: 3rem; | ||
| 406 | + } | ||
| 407 | + | ||
| 408 | + .w-full { | ||
| 409 | + width: 100%; | ||
| 410 | + } | ||
| 411 | + | ||
| 412 | + .max-w-7xl { | ||
| 413 | + max-width: 80rem; | ||
| 414 | + } | ||
| 415 | + | ||
| 416 | + .max-h-96 { | ||
| 417 | + max-height: 24rem; | ||
| 418 | + } | ||
| 419 | + | ||
| 420 | + /* 边框 */ | ||
| 421 | + .border { | ||
| 422 | + border-width: 1px; | ||
| 423 | + } | ||
| 424 | + | ||
| 425 | + .border-b-2 { | ||
| 426 | + border-bottom-width: 2px; | ||
| 427 | + } | ||
| 428 | + | ||
| 429 | + .border-gray-200 { | ||
| 430 | + border-color: #e5e7eb; | ||
| 431 | + } | ||
| 432 | + | ||
| 433 | + .border-gray-300 { | ||
| 434 | + border-color: #d1d5db; | ||
| 435 | + } | ||
| 436 | + | ||
| 437 | + .border-blue-500 { | ||
| 438 | + border-color: #3b82f6; | ||
| 439 | + } | ||
| 440 | + | ||
| 441 | + .border-green-500 { | ||
| 442 | + border-color: #22c55e; | ||
| 443 | + } | ||
| 444 | + | ||
| 445 | + .rounded-lg { | ||
| 446 | + border-radius: 0.5rem; | ||
| 447 | + } | ||
| 448 | + | ||
| 449 | + .rounded-md { | ||
| 450 | + border-radius: 0.375rem; | ||
| 451 | + } | ||
| 452 | + | ||
| 453 | + .rounded-full { | ||
| 454 | + border-radius: 9999px; | ||
| 455 | + } | ||
| 456 | + | ||
| 457 | + /* 背景 */ | ||
| 458 | + .bg-white { | ||
| 459 | + background-color: #ffffff; | ||
| 460 | + } | ||
| 461 | + | ||
| 462 | + .bg-gray-50 { | ||
| 463 | + background-color: #f9fafb; | ||
| 464 | + } | ||
| 465 | + | ||
| 466 | + .bg-blue-50 { | ||
| 467 | + background-color: #eff6ff; | ||
| 468 | + } | ||
| 469 | + | ||
| 470 | + .bg-indigo-100 { | ||
| 471 | + background-color: #e0e7ff; | ||
| 472 | + } | ||
| 473 | + | ||
| 474 | + .bg-blue-100 { | ||
| 475 | + background-color: #dbeafe; | ||
| 476 | + } | ||
| 477 | + | ||
| 478 | + .bg-green-100 { | ||
| 479 | + background-color: #dcfce7; | ||
| 480 | + } | ||
| 481 | + | ||
| 482 | + .bg-blue-600 { | ||
| 483 | + background-color: #2563eb; | ||
| 484 | + } | ||
| 485 | + | ||
| 486 | + .bg-gradient-to-br { | ||
| 487 | + background-image: linear-gradient(to bottom right, var(--tw-gradient-stops)); | ||
| 488 | + } | ||
| 489 | + | ||
| 490 | + .from-blue-50 { | ||
| 491 | + --tw-gradient-from: #eff6ff; | ||
| 492 | + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to, rgb(239 246 255 / 0)); | ||
| 493 | + } | ||
| 494 | + | ||
| 495 | + .to-indigo-100 { | ||
| 496 | + --tw-gradient-to: #e0e7ff; | ||
| 497 | + } | ||
| 498 | + | ||
| 499 | + /* 文本 */ | ||
| 500 | + .text-2xl { | ||
| 501 | + font-size: 1.5rem; | ||
| 502 | + line-height: 2rem; | ||
| 503 | + } | ||
| 504 | + | ||
| 505 | + .text-3xl { | ||
| 506 | + font-size: 1.875rem; | ||
| 507 | + line-height: 2.25rem; | ||
| 508 | + } | ||
| 509 | + | ||
| 510 | + .text-sm { | ||
| 511 | + font-size: 0.875rem; | ||
| 512 | + line-height: 1.25rem; | ||
| 513 | + } | ||
| 514 | + | ||
| 515 | + .text-lg { | ||
| 516 | + font-size: 1.125rem; | ||
| 517 | + line-height: 1.75rem; | ||
| 518 | + } | ||
| 519 | + | ||
| 520 | + .text-xl { | ||
| 521 | + font-size: 1.25rem; | ||
| 522 | + line-height: 1.75rem; | ||
| 523 | + } | ||
| 524 | + | ||
| 525 | + .text-xs { | ||
| 526 | + font-size: 0.75rem; | ||
| 527 | + line-height: 1rem; | ||
| 528 | + } | ||
| 529 | + | ||
| 530 | + .font-bold { | ||
| 531 | + font-weight: 700; | ||
| 532 | + } | ||
| 533 | + | ||
| 534 | + .font-medium { | ||
| 535 | + font-weight: 500; | ||
| 536 | + } | ||
| 537 | + | ||
| 538 | + .font-semibold { | ||
| 539 | + font-weight: 600; | ||
| 540 | + } | ||
| 541 | + | ||
| 542 | + .text-gray-500 { | ||
| 543 | + color: #6b7280; | ||
| 544 | + } | ||
| 545 | + | ||
| 546 | + .text-gray-600 { | ||
| 547 | + color: #4b5563; | ||
| 548 | + } | ||
| 549 | + | ||
| 550 | + .text-gray-700 { | ||
| 551 | + color: #374151; | ||
| 552 | + } | ||
| 553 | + | ||
| 554 | + .text-gray-800 { | ||
| 555 | + color: #1f2937; | ||
| 556 | + } | ||
| 557 | + | ||
| 558 | + .text-blue-600 { | ||
| 559 | + color: #2563eb; | ||
| 560 | + } | ||
| 561 | + | ||
| 562 | + .text-blue-800 { | ||
| 563 | + color: #1e40af; | ||
| 564 | + } | ||
| 565 | + | ||
| 566 | + .text-green-600 { | ||
| 567 | + color: #16a34a; | ||
| 568 | + } | ||
| 569 | + | ||
| 570 | + .text-green-800 { | ||
| 571 | + color: #15803d; | ||
| 572 | + } | ||
| 573 | + | ||
| 574 | + .text-white { | ||
| 575 | + color: #ffffff; | ||
| 576 | + } | ||
| 577 | + | ||
| 578 | + .text-orange-600 { | ||
| 579 | + color: #ea580c; | ||
| 580 | + } | ||
| 581 | + | ||
| 582 | + /* 透明度 */ | ||
| 583 | + .opacity-75 { | ||
| 584 | + opacity: 0.75; | ||
| 585 | + } | ||
| 586 | + | ||
| 587 | + /* 阴影 */ | ||
| 588 | + .shadow-lg { | ||
| 589 | + box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); | ||
| 590 | + } | ||
| 591 | + | ||
| 592 | + /* 过渡 */ | ||
| 593 | + .transition-all { | ||
| 594 | + transition-property: all; | ||
| 595 | + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); | ||
| 596 | + transition-duration: 150ms; | ||
| 597 | + } | ||
| 598 | + | ||
| 599 | + .transition-colors { | ||
| 600 | + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; | ||
| 601 | + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); | ||
| 602 | + transition-duration: 150ms; | ||
| 603 | + } | ||
| 604 | + | ||
| 605 | + .duration-200 { | ||
| 606 | + transition-duration: 200ms; | ||
| 607 | + } | ||
| 608 | + | ||
| 609 | + /* 悬停效果 */ | ||
| 610 | + .hover\:bg-blue-700:hover { | ||
| 611 | + background-color: #1d4ed8; | ||
| 612 | + } | ||
| 613 | + | ||
| 614 | + .hover\:bg-gray-50:hover { | ||
| 615 | + background-color: #f9fafb; | ||
| 616 | + } | ||
| 617 | + | ||
| 618 | + /* 焦点效果 */ | ||
| 619 | + .focus\:outline-none:focus { | ||
| 620 | + outline: 2px solid transparent; | ||
| 621 | + outline-offset: 2px; | ||
| 622 | + } | ||
| 623 | + | ||
| 624 | + .focus\:ring-2:focus { | ||
| 625 | + box-shadow: 0 0 0 2px rgb(59 130 246 / 0.5); | ||
| 626 | + } | ||
| 627 | + | ||
| 628 | + .focus\:ring-blue-500:focus { | ||
| 629 | + --tw-ring-color: #3b82f6; | ||
| 630 | + } | ||
| 631 | + | ||
| 632 | + .focus\:border-transparent:focus { | ||
| 633 | + border-color: transparent; | ||
| 634 | + } | ||
| 635 | + | ||
| 636 | + /* 动画 */ | ||
| 637 | + .animate-spin { | ||
| 638 | + animation: spin 1s linear infinite; | ||
| 639 | + } | ||
| 640 | + | ||
| 641 | + @keyframes spin { | ||
| 642 | + from { | ||
| 643 | + transform: rotate(0deg); | ||
| 644 | + } | ||
| 645 | + to { | ||
| 646 | + transform: rotate(360deg); | ||
| 647 | + } | ||
| 648 | + } | ||
| 649 | + | ||
| 650 | + /* 自定义样式 */ | ||
| 651 | + .min-h-screen { | ||
| 652 | + min-height: 100vh; | ||
| 653 | + } | ||
| 654 | + #dt_mobal{ | ||
| 655 | + margin-top: 120px; | ||
| 656 | + max-width: 1200px; | ||
| 657 | + | ||
| 658 | + } | ||
| 659 | + #dt_mobal .close{ | ||
| 660 | + width: 18px; | ||
| 661 | + height: 18px; | ||
| 662 | + margin-top: 5px; | ||
| 663 | + } | ||
| 664 | + .dt_bt{ | ||
| 665 | + background-color: #ffffff; | ||
| 666 | + height: 60px; | ||
| 667 | + } | ||
| 668 | + </style> | ||
| 669 | +<div class="dt max-w-7xl mx-auto modal fade" id="dt_mobal"> | ||
| 670 | + | ||
| 671 | + <button type="button" class="close" data-dismiss="modal" aria-hidden="true"></button> | ||
| 672 | + <!-- 标题区域 --> | ||
| 673 | + <div class="text-center shadow-lg dt_bt"> | ||
| 674 | + <div class="flex items-center justify-center mb-4 dt_bt"> | ||
| 675 | + <i class="fa fa-subway text-blue-600 text-2xl mr-3"></i> | ||
| 676 | + <h1 class="text-3xl font-bold text-gray-800">地铁公交接轨查询</h1> | ||
| 677 | + <i class="fa fa-bus text-green-600 text-2xl ml-3"></i> | ||
| 678 | + </div> | ||
| 679 | + </div> | ||
| 680 | + <!-- 搜索表单 --> | ||
| 681 | + <div class="bg-white rounded-lg shadow-lg p-6 "> | ||
| 682 | + <form id="searchForm" class="space-y-6"> | ||
| 683 | + <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> | ||
| 684 | + <!-- 公交线路搜索 --> | ||
| 685 | + <div class="space-y-2"> | ||
| 686 | + <label class="flex items-center text-sm font-medium text-gray-700"> | ||
| 687 | + <i class="fa fa-bus text-green-600 mr-2"></i> | ||
| 688 | + 公交线路 | ||
| 689 | + </label> | ||
| 690 | + <input id="busLine" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"> | ||
| 691 | + </div> | ||
| 692 | + | ||
| 693 | + <!-- 公交方向 --> | ||
| 694 | + <div class="space-y-2"> | ||
| 695 | + <label class="flex items-center text-sm font-medium text-gray-700"> | ||
| 696 | + <i class="fa fa-exchange-alt text-green-600 mr-2"></i> | ||
| 697 | + 公交方向 | ||
| 698 | + </label> | ||
| 699 | + <select id="busDirection" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"> | ||
| 700 | + <option value="">选择方向</option> | ||
| 701 | + <option value="上行">上行</option> | ||
| 702 | + <option value="下行">下行</option> | ||
| 703 | + </select> | ||
| 704 | + </div> | ||
| 705 | + | ||
| 706 | + <!-- 公交站点 --> | ||
| 707 | + <div class="space-y-2"> | ||
| 708 | + <label class="flex items-center text-sm font-medium text-gray-700"> | ||
| 709 | + <i class="fa fa-bus text-green-600 mr-2"></i> | ||
| 710 | + 公交站点 | ||
| 711 | + </label> | ||
| 712 | + <select id="busStation" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"> | ||
| 713 | + | ||
| 714 | + </select> | ||
| 715 | + </div> | ||
| 716 | + | ||
| 717 | + <!-- 地铁线路 --> | ||
| 718 | + <div class="space-y-2"> | ||
| 719 | + <label class="flex items-center text-sm font-medium text-gray-700"> | ||
| 720 | + <i class="fa fa-subway text-blue-600 mr-2"></i> | ||
| 721 | + 地铁线路 | ||
| 722 | + </label> | ||
| 723 | + <select id="metroLine" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"> | ||
| 724 | + | ||
| 725 | + </select> | ||
| 726 | + </div> | ||
| 727 | + | ||
| 728 | + <!-- 地铁方向 --> | ||
| 729 | + <div class="space-y-2"> | ||
| 730 | + <label class="flex items-center text-sm font-medium text-gray-700"> | ||
| 731 | + <i class="fa fa-exchange-alt text-blue-600 mr-2"></i> | ||
| 732 | + 地铁方向 | ||
| 733 | + </label> | ||
| 734 | + <select id="metroDirection" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"> | ||
| 735 | + | ||
| 736 | + </select> | ||
| 737 | + </div> | ||
| 738 | + | ||
| 739 | + <!-- 地铁站点 --> | ||
| 740 | + <div class="space-y-2"> | ||
| 741 | + <label class="flex items-center text-sm font-medium text-gray-700"> | ||
| 742 | + <i class="fa fa-subway text-blue-600 mr-2"></i> | ||
| 743 | + 地铁站点 | ||
| 744 | + </label> | ||
| 745 | + <select id="metroStation" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"> | ||
| 746 | + | ||
| 747 | + </select> | ||
| 748 | + </div> | ||
| 749 | + </div> | ||
| 750 | + | ||
| 751 | + <!-- 搜索按钮 --> | ||
| 752 | + <div class="flex justify-center"> | ||
| 753 | + <button type="submit" class="flex items-center px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors duration-200 font-medium"> | ||
| 754 | + <i class="fa fa-search mr-2"></i> | ||
| 755 | + 查询接轨时刻表 | ||
| 756 | + </button> | ||
| 757 | + </div> | ||
| 758 | + </form> | ||
| 759 | + </div> | ||
| 760 | + | ||
| 761 | + <!-- 时刻表区域 --> | ||
| 762 | + <div id="scheduleContainer" class="hidden grid grid-cols-1 lg:grid-cols-2 "> | ||
| 763 | + <!-- 左侧时刻表 --> | ||
| 764 | + <div class="bg-white rounded-lg shadow-lg p-6"> | ||
| 765 | + <div class="flex items-center mb-4"> | ||
| 766 | + <i class="fa fa-clock text-blue-600 mr-2"></i> | ||
| 767 | + <h2 id="leftTitle" class="text-xl font-semibold text-gray-800"></h2> | ||
| 768 | + </div> | ||
| 769 | + <div id="leftSchedule" class="space-y-4"> | ||
| 770 | + <!-- 时刻表内容将通过JavaScript动态生成 --> | ||
| 771 | + </div> | ||
| 772 | + </div> | ||
| 773 | + | ||
| 774 | + <!-- 右侧时刻表 --> | ||
| 775 | + <div class="bg-white rounded-lg shadow-lg p-6"> | ||
| 776 | + <div class="flex items-center mb-4"> | ||
| 777 | + <i class="fa fa-clock text-green-600 mr-2"></i> | ||
| 778 | + <h2 id="rightTitle" class="text-xl font-semibold text-gray-800"></h2> | ||
| 779 | + </div> | ||
| 780 | + <div id="rightSchedule" class="space-y-4"> | ||
| 781 | + <!-- 时刻表内容将通过JavaScript动态生成 --> | ||
| 782 | + </div> | ||
| 783 | + </div> | ||
| 784 | + </div> | ||
| 785 | + | ||
| 786 | + <!-- 加载状态 --> | ||
| 787 | + <div id="loading" class="hidden flex items-center justify-center py-12"> | ||
| 788 | + <div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div> | ||
| 789 | + <span class="ml-3 text-gray-600">正在加载时刻表...</span> | ||
| 790 | + </div> | ||
| 791 | + | ||
| 792 | +</div> | ||
| 793 | +<script> | ||
| 794 | + var ListDatal; | ||
| 795 | + var DtDatal; | ||
| 796 | + $('#dt_mobal').on('dtAddMobal.show', function(e,ListData){ | ||
| 797 | + // 加载延迟200毫秒显示mobal | ||
| 798 | + ListDatal = ListData; | ||
| 799 | + var line = ListData.line; | ||
| 800 | + $("#busLine").val(line.name); | ||
| 801 | + setTimeout(function(){$('#dt_mobal').modal({show : true,backdrop: 'static', keyboard: false});},200); | ||
| 802 | + $get("/dt/list_group",null,function (data){ | ||
| 803 | + debugger | ||
| 804 | + DtDatal = data; | ||
| 805 | + var lineNames = Object.keys(data); | ||
| 806 | + console.log('所有线路:', lineNames); | ||
| 807 | + // 用于存储每个线路的方向(去重) | ||
| 808 | + var lineDirectionsMap = {}; | ||
| 809 | + // 遍历所有线路 | ||
| 810 | + for (var i = 0; i < lineNames.length; i++) { | ||
| 811 | + var lineName = lineNames[i]; // 例如:"16 号线" | ||
| 812 | + var lineData = data[lineName]; // 这是该线路的数组 Array(26) | ||
| 813 | + | ||
| 814 | + console.log('线路名称:', lineName); | ||
| 815 | + console.log('该线路数据数量:', lineData.length); | ||
| 816 | + | ||
| 817 | + // 初始化该线路的方向数组 | ||
| 818 | + lineDirectionsMap[lineName] = []; | ||
| 819 | + | ||
| 820 | + // 遍历该线路的所有数据,提取方向(去重) | ||
| 821 | + var directionSet = new Set(); // 使用 Set 自动去重 | ||
| 822 | + for (var j = 0; j < lineData.length; j++) { | ||
| 823 | + var item = lineData[j]; | ||
| 824 | + | ||
| 825 | + if (item.direction && !directionSet.has(item.direction)) { | ||
| 826 | + directionSet.add(item.direction); | ||
| 827 | + lineDirectionsMap[lineName].push(item.direction); | ||
| 828 | + | ||
| 829 | + console.log('发现新方向 "' + item.direction + '" 在 ' + lineName); | ||
| 830 | + } | ||
| 831 | + } | ||
| 832 | + | ||
| 833 | + console.log(lineName + ' 的所有方向:', lineDirectionsMap[lineName]); | ||
| 834 | + | ||
| 835 | + // 添加线路到下拉框 | ||
| 836 | + $("#metroLine").append('<option value="' + lineName + '">' + lineName + '</option>'); | ||
| 837 | + } | ||
| 838 | + | ||
| 839 | + // 将方向和线路数据都保存到全局变量供后续使用 | ||
| 840 | + window.metroDataMap = data; | ||
| 841 | + window.metroDirectionsMap = lineDirectionsMap; | ||
| 842 | + | ||
| 843 | + // 默认选中第一条线路时,自动加载其方向 | ||
| 844 | + if (lineNames.length > 0) { | ||
| 845 | + var firstLineName = lineNames[0]; | ||
| 846 | + var directions = lineDirectionsMap[firstLineName]; | ||
| 847 | + $("#metroDirection").empty().append('<option value="">选择方向</option>'); | ||
| 848 | + for (var n in directions){ | ||
| 849 | + var direction = directions[n]; | ||
| 850 | + $("#metroDirection").append('<option value="' + direction + '">' + direction + '</option>'); | ||
| 851 | + } | ||
| 852 | + } | ||
| 853 | + }) | ||
| 854 | + }); | ||
| 855 | + | ||
| 856 | + // 地铁线路改变事件 | ||
| 857 | + document.getElementById('metroLine').addEventListener('change', function() { | ||
| 858 | + var metroLine = this.value; | ||
| 859 | + // 清空后续选择 | ||
| 860 | + $("#metroDirection").empty().append('<option value="">选择方向</option>'); | ||
| 861 | + $("#metroStation").empty().append('<option value="">选择站点</option>'); | ||
| 862 | + | ||
| 863 | + // 加载地铁方向 | ||
| 864 | + if (metroLine && window.metroDirectionsMap) { | ||
| 865 | + var directions = window.metroDirectionsMap[metroLine] || []; | ||
| 866 | + | ||
| 867 | + if (directions.length > 0) { | ||
| 868 | + var options = '<option value="">选择方向</option>'; | ||
| 869 | + directions.forEach(function(dir) { | ||
| 870 | + options += '<option value="' + dir + '">' + dir + '</option>'; | ||
| 871 | + }); | ||
| 872 | + $("#metroDirection").empty().append(options); | ||
| 873 | + } | ||
| 874 | + } | ||
| 875 | + }); | ||
| 876 | + // 地铁方向改变事件 | ||
| 877 | + document.getElementById('metroDirection').addEventListener('change', function() { | ||
| 878 | + var metroLine = document.getElementById('metroLine').value; | ||
| 879 | + var direction = this.value; | ||
| 880 | + // 清空站点 | ||
| 881 | + $("#metroStation").empty().append('<option value="">选择站点</option>'); | ||
| 882 | + | ||
| 883 | + // 加载地铁站点 | ||
| 884 | + if (metroLine && direction) { | ||
| 885 | + loadMetroStations(metroLine, direction); | ||
| 886 | + } | ||
| 887 | + }); | ||
| 888 | + | ||
| 889 | + // 公交方向改变事件 | ||
| 890 | + document.getElementById('busDirection').addEventListener('change', function() { | ||
| 891 | + var lineName = document.getElementById('busLine').value; | ||
| 892 | + var direction = this.value; | ||
| 893 | + // 清空站点 | ||
| 894 | + $("#busStation").empty().append('<option value="">选择站点</option>'); | ||
| 895 | + | ||
| 896 | + // 加载公交站点 | ||
| 897 | + if (lineName && direction) { | ||
| 898 | + loadBusStations(lineName, direction); | ||
| 899 | + } | ||
| 900 | + }); | ||
| 901 | + | ||
| 902 | + | ||
| 903 | + // 加载公交站点(根据方向显示不同的站点列表) | ||
| 904 | + function loadBusStations(lineName, direction) { | ||
| 905 | + if (!lineName || !direction) { | ||
| 906 | + $("#busStation").empty().append('<option value="">请先选择线路和方向</option>'); | ||
| 907 | + return; | ||
| 908 | + } | ||
| 909 | + // 从 ListDatal 中获取线路信息 | ||
| 910 | + if (ListDatal && ListDatal.line) { | ||
| 911 | + var line = ListDatal.line; | ||
| 912 | + var startStationName = line.startStationName; // 起点站 | ||
| 913 | + var endStationName = line.endStationName; // 终点站 | ||
| 914 | + | ||
| 915 | + var options = ''; | ||
| 916 | + | ||
| 917 | + if (direction === '上行') { | ||
| 918 | + // 上行:只显示起点站(上行方向的站点) | ||
| 919 | + options += '<option value="' + startStationName + '">' + startStationName + '</option>'; | ||
| 920 | + } else if (direction === '下行') { | ||
| 921 | + // 下行:只显示终点站(下行方向的站点) | ||
| 922 | + options += '<option value="' + endStationName + '">' + endStationName + '</option>'; | ||
| 923 | + } | ||
| 924 | + | ||
| 925 | + $("#busStation").empty().append(options); | ||
| 926 | + } else { | ||
| 927 | + // 如果没有线路数据,显示默认选项 | ||
| 928 | + $("#busStation").empty().append('<option value="">暂无站点数据</option>'); | ||
| 929 | + } | ||
| 930 | + } | ||
| 931 | + | ||
| 932 | + function loadMetroStations(metroLine, direction) { | ||
| 933 | + if (!metroLine || !direction) { | ||
| 934 | + $("#metroStation").empty().append('<option value="">请先选择线路和方向</option>'); | ||
| 935 | + return; | ||
| 936 | + } | ||
| 937 | + | ||
| 938 | + // 从已加载的数据中提取站点 | ||
| 939 | + var allData = window.metroDataMap; | ||
| 940 | + if (!allData || !allData[metroLine]) { | ||
| 941 | + $("#metroStation").empty().append('<option value="">暂无该线路数据</option>'); | ||
| 942 | + return; | ||
| 943 | + } | ||
| 944 | + | ||
| 945 | + var lineData = allData[metroLine]; // 该线路的所有数据 | ||
| 946 | + var stationSet = new Set(); // 去重 | ||
| 947 | + var stations = []; | ||
| 948 | + | ||
| 949 | + // 筛选指定方向的数据并提取站点 | ||
| 950 | + for (var i = 0; i < lineData.length; i++) { | ||
| 951 | + var item = lineData[i]; | ||
| 952 | + if (item.direction === direction && item.station && !stationSet.has(item.station)) { | ||
| 953 | + stationSet.add(item.station); | ||
| 954 | + stations.push(item.station); | ||
| 955 | + } | ||
| 956 | + } | ||
| 957 | + | ||
| 958 | + console.log(metroLine + ' - ' + direction + ' 的站点:', stations); | ||
| 959 | + | ||
| 960 | + var options = ''; | ||
| 961 | + if (stations.length > 0) { | ||
| 962 | + stations.forEach(function(station) { | ||
| 963 | + options += '<option value="' + station + '">' + station + '</option>'; | ||
| 964 | + }); | ||
| 965 | + } else { | ||
| 966 | + options += '<option value="">该方向暂无站点</option>'; | ||
| 967 | + } | ||
| 968 | + | ||
| 969 | + $("#metroStation").empty().append(options); | ||
| 970 | + } | ||
| 971 | + | ||
| 972 | + // 转换时间为分钟数 | ||
| 973 | + function convertTimeToMinutes(timeStr) { | ||
| 974 | + if (typeof timeStr !== 'string') { | ||
| 975 | + console.error('convertTimeToMinutes 接收到非字符串参数:', timeStr); | ||
| 976 | + timeStr = String(timeStr); | ||
| 977 | + } | ||
| 978 | + | ||
| 979 | + if (!/^\d{1,2}:\d{2}$/.test(timeStr)) { | ||
| 980 | + console.error('时间格式不正确:', timeStr); | ||
| 981 | + return 0; | ||
| 982 | + } | ||
| 983 | + | ||
| 984 | + const [hours, minutes] = timeStr.split(':').map(Number); | ||
| 985 | + return hours * 60 + minutes; | ||
| 986 | + } | ||
| 987 | + | ||
| 988 | + // 找到最接近的时间 | ||
| 989 | + function findNearestTime(targetTime, timeArray) { | ||
| 990 | + if (!timeArray.length) return null; | ||
| 991 | + | ||
| 992 | + const targetTimeStr = typeof targetTime === 'string' ? targetTime : targetTime.time; | ||
| 993 | + const targetMinutes = convertTimeToMinutes(targetTimeStr); | ||
| 994 | + | ||
| 995 | + let nearest = timeArray[0]; | ||
| 996 | + let minDiff = Math.abs(convertTimeToMinutes(nearest.time) - targetMinutes); | ||
| 997 | + | ||
| 998 | + timeArray.forEach(item => { | ||
| 999 | + const diff = Math.abs(convertTimeToMinutes(item.time) - targetMinutes); | ||
| 1000 | + if (diff < minDiff) { | ||
| 1001 | + minDiff = diff; | ||
| 1002 | + nearest = item; | ||
| 1003 | + } | ||
| 1004 | + }); | ||
| 1005 | + | ||
| 1006 | + return nearest; | ||
| 1007 | + } | ||
| 1008 | + | ||
| 1009 | + // 渲染时刻表 | ||
| 1010 | + function renderSchedule(schedule, containerId, selectedTime, side) { | ||
| 1011 | + const container = document.getElementById(containerId); | ||
| 1012 | + container.innerHTML = ''; | ||
| 1013 | + | ||
| 1014 | + if (!schedule || schedule.length === 0) { | ||
| 1015 | + container.innerHTML = ` | ||
| 1016 | + <div class="text-center py-8 text-gray-500"> | ||
| 1017 | + <i class="fa fa-clock text-gray-300 text-4xl mb-4"></i> | ||
| 1018 | + <p>暂无时刻表数据</p> | ||
| 1019 | + <p class="text-sm">请选择搜索条件</p> | ||
| 1020 | + </div> | ||
| 1021 | + `; | ||
| 1022 | + return; | ||
| 1023 | + } | ||
| 1024 | + | ||
| 1025 | + // 添加时刻表头部信息 | ||
| 1026 | + const header = document.createElement('div'); | ||
| 1027 | + header.className = 'bg-gray-50 rounded-lg p-4 mb-4'; | ||
| 1028 | + header.innerHTML = ` | ||
| 1029 | + <div class="flex items-center justify-between"> | ||
| 1030 | + <div class="flex items-center"> | ||
| 1031 | + <i class="fa fa-map-marker-alt text-gray-500 mr-2"></i> | ||
| 1032 | + <span class="text-sm text-gray-600"> | ||
| 1033 | + 共 ${schedule.length} 班次 | ||
| 1034 | + </span> | ||
| 1035 | + </div> | ||
| 1036 | + <div class="text-sm text-gray-500"> | ||
| 1037 | + 运营时间: ${schedule[0].time} - ${schedule[schedule.length - 1].time} | ||
| 1038 | + </div> | ||
| 1039 | + </div> | ||
| 1040 | + `; | ||
| 1041 | + container.appendChild(header); | ||
| 1042 | + | ||
| 1043 | + // 创建滚动容器 | ||
| 1044 | + const scrollContainer = document.createElement('div'); | ||
| 1045 | + scrollContainer.className = 'max-h-96 overflow-y-auto space-y-2 scrollbar-thin scrollbar-thumb-gray-300 scrollbar-track-gray-100'; | ||
| 1046 | + | ||
| 1047 | + // 添加时刻表项 | ||
| 1048 | + schedule.forEach((timeItem, index) => { | ||
| 1049 | + const timeElement = document.createElement('div'); | ||
| 1050 | + timeElement.className = `border rounded-lg p-4 cursor-pointer transition-all duration-200 ${ | ||
| 1051 | + selectedTime && selectedTime.time === timeItem.time | ||
| 1052 | + ? side === 'left' | ||
| 1053 | + ? 'bg-blue-100 border-blue-500 text-blue-800' | ||
| 1054 | + : 'bg-green-100 border-green-500 text-green-800' | ||
| 1055 | + : 'bg-white border-gray-200 text-gray-700 hover:bg-gray-50' | ||
| 1056 | + }`; | ||
| 1057 | + timeElement.dataset.time = timeItem.time; | ||
| 1058 | + timeElement.dataset.index = index; | ||
| 1059 | + | ||
| 1060 | + timeElement.innerHTML = ` | ||
| 1061 | + <div class="flex items-center justify-between"> | ||
| 1062 | + <div class="flex items-center"> | ||
| 1063 | + <i class="fa fa-clock mr-3"></i> | ||
| 1064 | + <div> | ||
| 1065 | + <div class="font-semibold text-lg"> | ||
| 1066 | + ${timeItem.time} | ||
| 1067 | + </div> | ||
| 1068 | + <div class="text-sm opacity-75"> | ||
| 1069 | + ${timeItem.station} | ||
| 1070 | + </div> | ||
| 1071 | + </div> | ||
| 1072 | + </div> | ||
| 1073 | + | ||
| 1074 | + <div class="flex items-center text-sm"> | ||
| 1075 | + <span class="mr-2">${timeItem.type}</span> | ||
| 1076 | + <i class="fa fa-arrow-right"></i> | ||
| 1077 | + </div> | ||
| 1078 | + </div> | ||
| 1079 | + | ||
| 1080 | + <!-- 额外信息 --> | ||
| 1081 | + ${timeItem.platform ? `<div class="mt-2 text-xs opacity-75">站台: ${timeItem.platform}</div>` : ''} | ||
| 1082 | + ${timeItem.note ? `<div class="mt-1 text-xs text-orange-600">备注: ${timeItem.note}</div>` : ''} | ||
| 1083 | + `; | ||
| 1084 | + | ||
| 1085 | + // 添加点击事件 | ||
| 1086 | + timeElement.addEventListener('click', () => { | ||
| 1087 | + handleTimeSelect(side, timeItem); | ||
| 1088 | + }); | ||
| 1089 | + | ||
| 1090 | + scrollContainer.appendChild(timeElement); | ||
| 1091 | + }); | ||
| 1092 | + | ||
| 1093 | + container.appendChild(scrollContainer); | ||
| 1094 | + | ||
| 1095 | + // 添加底部提示 | ||
| 1096 | + const footer = document.createElement('div'); | ||
| 1097 | + footer.className = 'text-xs text-gray-500 text-center py-2'; | ||
| 1098 | + footer.textContent = `点击时间可${side === 'left' ? '联动选择右侧' : '联动选择左侧'}最接近时刻`; | ||
| 1099 | + container.appendChild(footer); | ||
| 1100 | + } | ||
| 1101 | + | ||
| 1102 | + // 处理时间选择 | ||
| 1103 | + function handleTimeSelect(side, time) { | ||
| 1104 | + if (side === 'left') { | ||
| 1105 | + selectedTime.left = time; | ||
| 1106 | + selectedTime.right = findNearestTime(time, scheduleData.rightSchedule || []); | ||
| 1107 | + } else { | ||
| 1108 | + selectedTime.right = time; | ||
| 1109 | + selectedTime.left = findNearestTime(time, scheduleData.leftSchedule || []); | ||
| 1110 | + } | ||
| 1111 | + | ||
| 1112 | + // 重新渲染时刻表 | ||
| 1113 | + renderSchedule(scheduleData.leftSchedule, 'leftSchedule', selectedTime.left, 'left'); | ||
| 1114 | + renderSchedule(scheduleData.rightSchedule, 'rightSchedule', selectedTime.right, 'right'); | ||
| 1115 | + | ||
| 1116 | + // 滚动到选中项 | ||
| 1117 | + setTimeout(() => { | ||
| 1118 | + scrollToSelectedItem('left'); | ||
| 1119 | + scrollToSelectedItem('right'); | ||
| 1120 | + }, 100); | ||
| 1121 | + } | ||
| 1122 | + | ||
| 1123 | + // 滚动到选中项 | ||
| 1124 | + function scrollToSelectedItem(side) { | ||
| 1125 | + const container = document.querySelector(`#${side}Schedule .overflow-y-auto`); | ||
| 1126 | + const selectedItem = document.querySelector(`#${side}Schedule [data-time="${side === 'left' ? selectedTime.left?.time : selectedTime.right?.time}"]`); | ||
| 1127 | + | ||
| 1128 | + if (container && selectedItem) { | ||
| 1129 | + const containerRect = container.getBoundingClientRect(); | ||
| 1130 | + const itemRect = selectedItem.getBoundingClientRect(); | ||
| 1131 | + | ||
| 1132 | + const scrollTop = selectedItem.offsetTop - container.offsetTop - (container.clientHeight / 2) + (selectedItem.clientHeight / 2); | ||
| 1133 | + | ||
| 1134 | + container.scrollTo({ | ||
| 1135 | + top: scrollTop, | ||
| 1136 | + behavior: 'smooth' | ||
| 1137 | + }); | ||
| 1138 | + } | ||
| 1139 | + } | ||
| 1140 | + | ||
| 1141 | + // 获取表单数据 | ||
| 1142 | + function getFormData() { | ||
| 1143 | + return { | ||
| 1144 | + busLine: document.getElementById('busLine').value, | ||
| 1145 | + busDirection: document.getElementById('busDirection').value, | ||
| 1146 | + busStation: document.getElementById('busStation').value, | ||
| 1147 | + metroLine: document.getElementById('metroLine').value, | ||
| 1148 | + metroDirection: document.getElementById('metroDirection').value, | ||
| 1149 | + metroStation: document.getElementById('metroStation').value | ||
| 1150 | + }; | ||
| 1151 | + } | ||
| 1152 | + | ||
| 1153 | + // 显示加载状态 | ||
| 1154 | + function showLoading() { | ||
| 1155 | + document.getElementById('loading').classList.remove('hidden'); | ||
| 1156 | + document.getElementById('scheduleContainer').classList.add('hidden'); | ||
| 1157 | + } | ||
| 1158 | + | ||
| 1159 | + // 隐藏加载状态 | ||
| 1160 | + function hideLoading() { | ||
| 1161 | + document.getElementById('loading').classList.add('hidden'); | ||
| 1162 | + } | ||
| 1163 | + | ||
| 1164 | + // 显示时刻表 | ||
| 1165 | + function showSchedule() { | ||
| 1166 | + document.getElementById('scheduleContainer').classList.remove('hidden'); | ||
| 1167 | + } | ||
| 1168 | + | ||
| 1169 | + // 模拟API调用 | ||
| 1170 | + function fetchScheduleData(searchParams) { | ||
| 1171 | + return new Promise((resolve) => { | ||
| 1172 | + const { busLine, busDirection, busStation, metroLine, metroDirection, metroStation } = searchParams; | ||
| 1173 | + | ||
| 1174 | + const busSchedule =[]; | ||
| 1175 | + const metroSchedule = []; | ||
| 1176 | + | ||
| 1177 | + $.get("/dt/all",{line_eq:metroLine,direction_eq:metroDirection,station_eq:metroStation},function(rs){ | ||
| 1178 | + for (var i in rs){ | ||
| 1179 | + var item = rs[i]; | ||
| 1180 | + metroSchedule.push({ | ||
| 1181 | + time: item.arrivalTime, | ||
| 1182 | + station: item.station, | ||
| 1183 | + type: '地铁', | ||
| 1184 | + direction: metroDirection | ||
| 1185 | + }); | ||
| 1186 | + } | ||
| 1187 | + // 获取公交数据 - 从 ListDatal 读取 | ||
| 1188 | + var busDataList = []; | ||
| 1189 | + if (busDirection === '上行') { | ||
| 1190 | + busDataList = ListDatal.ListUpData || []; | ||
| 1191 | + } else if (busDirection === '下行') { | ||
| 1192 | + busDataList = ListDatal.ListDoData || []; | ||
| 1193 | + } | ||
| 1194 | + debugger; | ||
| 1195 | + var line = ListDatal.line; | ||
| 1196 | + // 筛选指定站点的数据 | ||
| 1197 | + for (var i = 0; i < busDataList.length; i++) { | ||
| 1198 | + var item = busDataList[i]; | ||
| 1199 | + busSchedule.push({ | ||
| 1200 | + time: item.time, | ||
| 1201 | + station: busStation, | ||
| 1202 | + type: '公交', | ||
| 1203 | + direction: busDirection | ||
| 1204 | + }); | ||
| 1205 | + | ||
| 1206 | + } | ||
| 1207 | + | ||
| 1208 | + resolve({ | ||
| 1209 | + leftTitle: `${busLine}路公交 ${busDirection}方向${busStation ? ` - ${busStation}` : ''}`, | ||
| 1210 | + rightTitle: `${metroLine} ${metroDirection}方向${metroStation ? ` - ${metroStation}` : ''}`, | ||
| 1211 | + leftSchedule: busSchedule, | ||
| 1212 | + rightSchedule: metroSchedule | ||
| 1213 | + }); | ||
| 1214 | + }) | ||
| 1215 | + | ||
| 1216 | + }); | ||
| 1217 | + } | ||
| 1218 | + | ||
| 1219 | + // 初始化 | ||
| 1220 | + let scheduleData = null; | ||
| 1221 | + let selectedTime = { | ||
| 1222 | + left: null, | ||
| 1223 | + right: null | ||
| 1224 | + }; | ||
| 1225 | + | ||
| 1226 | + // 表单提交事件 | ||
| 1227 | + document.getElementById('searchForm').addEventListener('submit', async function(e) { | ||
| 1228 | + e.preventDefault(); | ||
| 1229 | + | ||
| 1230 | + const formData = getFormData(); | ||
| 1231 | + | ||
| 1232 | + // 验证必填字段 | ||
| 1233 | + if (!formData.busLine || !formData.busDirection || !formData.metroDirection) { | ||
| 1234 | + alert('请填写公交线路、公交方向和地铁方向'); | ||
| 1235 | + return; | ||
| 1236 | + } | ||
| 1237 | + | ||
| 1238 | + // 重置选中时间 | ||
| 1239 | + selectedTime = { | ||
| 1240 | + left: null, | ||
| 1241 | + right: null | ||
| 1242 | + }; | ||
| 1243 | + | ||
| 1244 | + // 显示加载状态 | ||
| 1245 | + showLoading(); | ||
| 1246 | + | ||
| 1247 | + try { | ||
| 1248 | + // 获取数据 | ||
| 1249 | + scheduleData = await fetchScheduleData(formData); | ||
| 1250 | + | ||
| 1251 | + if (scheduleData) { | ||
| 1252 | + // 更新标题 | ||
| 1253 | + document.getElementById('leftTitle').textContent = scheduleData.leftTitle; | ||
| 1254 | + document.getElementById('rightTitle').textContent = scheduleData.rightTitle; | ||
| 1255 | + | ||
| 1256 | + // 渲染时刻表 | ||
| 1257 | + renderSchedule(scheduleData.leftSchedule, 'leftSchedule', selectedTime.left, 'left'); | ||
| 1258 | + renderSchedule(scheduleData.rightSchedule, 'rightSchedule', selectedTime.right, 'right'); | ||
| 1259 | + | ||
| 1260 | + // 显示时刻表 | ||
| 1261 | + showSchedule(); | ||
| 1262 | + } else { | ||
| 1263 | + alert('未找到相关时刻表数据'); | ||
| 1264 | + } | ||
| 1265 | + } catch (error) { | ||
| 1266 | + console.error('获取时刻表数据失败:', error); | ||
| 1267 | + alert('获取时刻表数据失败,请稍后重试'); | ||
| 1268 | + } finally { | ||
| 1269 | + // 隐藏加载状态 | ||
| 1270 | + hideLoading(); | ||
| 1271 | + } | ||
| 1272 | + }); | ||
| 1273 | +</script> | ||
| 0 | \ No newline at end of file | 1274 | \ No newline at end of file |
src/main/resources/static/pages/base/timesmodel/gantt.html
| @@ -52,6 +52,10 @@ | @@ -52,6 +52,10 @@ | ||
| 52 | <div class="btn-group btn-group-devided " data-toggle="buttons"> | 52 | <div class="btn-group btn-group-devided " data-toggle="buttons"> |
| 53 | <a class="btn btn-circle blue parambtns" href="javascript:;" data-pjax><i class="fa fa-list-ol" aria-hidden="true"></i> 只看实际</a> | 53 | <a class="btn btn-circle blue parambtns" href="javascript:;" data-pjax><i class="fa fa-list-ol" aria-hidden="true"></i> 只看实际</a> |
| 54 | </div> | 54 | </div> |
| 55 | + | ||
| 56 | + <div class="btn-group btn-group-devided " data-toggle="buttons"> | ||
| 57 | + <a class="btn btn-circle blue dt_param" href="javascript:;" data-pjax><i class="fa fa-list-ol" aria-hidden="true"></i> 地铁接轨</a> | ||
| 58 | + </div> | ||
| 55 | <!-- <div class="btn-group btn-group-devided countbtn" data-toggle="buttons"> | 59 | <!-- <div class="btn-group btn-group-devided countbtn" data-toggle="buttons"> |
| 56 | <a class="btn btn-circle blue jhpbonsjpb" href="javascript:;" data-pjax><i class="fa fa-database"></i> 计划排班与实际班次</a> | 60 | <a class="btn btn-circle blue jhpbonsjpb" href="javascript:;" data-pjax><i class="fa fa-database"></i> 计划排班与实际班次</a> |
| 57 | </div>--> | 61 | </div>--> |
src/main/resources/static/pages/base/timesmodel/js/systemTools.js
| @@ -595,6 +595,65 @@ $('.parambtns').on('click',function (){ | @@ -595,6 +595,65 @@ $('.parambtns').on('click',function (){ | ||
| 595 | }) | 595 | }) |
| 596 | }) | 596 | }) |
| 597 | 597 | ||
| 598 | + | ||
| 599 | +$('.dt_param').on('click',function (){ | ||
| 600 | + var historyData = echartsDrawGTT.getHistoryData(), | ||
| 601 | + list = historyData[0]; | ||
| 602 | + var ListData ={}; | ||
| 603 | + var ListUpData =[]; | ||
| 604 | + var ListDoData =[]; | ||
| 605 | + //区分上下行班次 --线路 上下行 站点名称 时间 | ||
| 606 | + for(var i = 0;i<list.length;i++) { | ||
| 607 | + var bcObj = list[i].value; | ||
| 608 | + if (bcObj[6]=='normal') { | ||
| 609 | + if (bcObj[8] == "1") { //上下行 | ||
| 610 | + ListUpData.push({time: getHoursAndMinutes(bcObj[1])}) | ||
| 611 | + } else { | ||
| 612 | + ListDoData.push({time: getHoursAndMinutes(bcObj[1])}) | ||
| 613 | + } | ||
| 614 | + } | ||
| 615 | + } | ||
| 616 | + var lineid = list[0].value[12]; | ||
| 617 | + ListUpData.sort(function(a,b){ | ||
| 618 | + return a.time.localeCompare(b.time); | ||
| 619 | + }); | ||
| 620 | + ListDoData.sort(function(a,b){ | ||
| 621 | + return a.time.localeCompare(b.time); | ||
| 622 | + }); | ||
| 623 | + // 查询线路编码的顺延号 | ||
| 624 | + $get('/line/' + lineid ,null,function(line){ | ||
| 625 | + ListData = { | ||
| 626 | + "line":line, | ||
| 627 | + "ListUpData":ListUpData, | ||
| 628 | + "ListDoData":ListDoData | ||
| 629 | + } | ||
| 630 | + // 弹出层mobal页面 | ||
| 631 | + $.get('/pages/base/timesmodel/dt/dt.html', function(m){ | ||
| 632 | + $(pjaxContainer).append(m); | ||
| 633 | + /* // 关闭左侧栏 | ||
| 634 | + if (!$('body').hasClass('page-sidebar-closed')) | ||
| 635 | + $('.menu-toggler.sidebar-toggler').click();*/ | ||
| 636 | + // 规定被选元素要触发的事件。可以使自定义事件(使用 bind() 函数来附加),或者任何标准事件。 | ||
| 637 | + $('#dt_mobal').trigger('dtAddMobal.show',[ListData]); | ||
| 638 | + }); | ||
| 639 | + }); | ||
| 640 | + | ||
| 641 | + | ||
| 642 | + | ||
| 643 | + | ||
| 644 | +}); | ||
| 645 | +// 时间戳转时间(时间:分钟) | ||
| 646 | +var getHoursAndMinutes = function (timestamp) { | ||
| 647 | + var date = new Date(timestamp); | ||
| 648 | + var Hours = swallowTow(date.getHours()); | ||
| 649 | + var Minutes = swallowTow(date.getMinutes()); | ||
| 650 | + return Hours+":"+Minutes; | ||
| 651 | +}; | ||
| 652 | +// 补齐两位 | ||
| 653 | +var swallowTow = function (date) { | ||
| 654 | + return date>=10?date:(date="0"+date); | ||
| 655 | +}; | ||
| 656 | + | ||
| 598 | /** | 657 | /** |
| 599 | * @description : (TODO) 监听保存数据事件. | 658 | * @description : (TODO) 监听保存数据事件. |
| 600 | * | 659 | * |