feat(web/route): 适配移动端响应式布局 + 统一站点拖拽逻辑
1. 线路规划页面(/route)移动端适配:
- 新增 980px / 768px / 480px 三档响应式CSS
- 侧边栏改为抽屉式叠加层,主容器垂直流式布局
- 顶部导航、工具栏、编辑器堆叠式排列
- SVG线路容器开启横向惯性滚动,最小宽度720px
- 票价地图、表格、模态框均针对小屏优化
- 按钮/输入框统一最小高度44px,满足可访问性
2. 重构站点拖拽逻辑(修复电脑端拖拽失效):
- 原实现:mousemove绑定单站点<g>,鼠标离开即丢失拖拽
- 新实现:mousedown/touchstart仅记录起点,
window级别监听 mousemove/mouseup/touchmove/touchend
- 通过 SVG createSVGPoint + getScreenCTM().inverse()
统一将屏幕坐标转换为SVG逻辑坐标再换算站点索引
- 共用 swapStationByIndex() / saveDragResult() 核心函数
3. 静态资源版本号升级: style.css v16, ticket-route.js v5
This commit is contained in:
+292
@@ -4647,6 +4647,298 @@ body.jr-admin-login-page {
|
||||
}
|
||||
}
|
||||
|
||||
/* ========== Route 页面移动端专项适配 ========== */
|
||||
@media (max-width: 980px) {
|
||||
body.jr-admin-route-page {
|
||||
overflow: auto;
|
||||
}
|
||||
body.jr-admin-route-page #app {
|
||||
min-height: auto;
|
||||
height: auto;
|
||||
}
|
||||
.jr-admin-route-page .jr-admin-app {
|
||||
min-height: auto;
|
||||
border-radius: 0;
|
||||
}
|
||||
.jr-admin-route-page .jr-admin-main-shell {
|
||||
width: min(100%, calc(100% - 24px));
|
||||
padding: 12px 0 24px;
|
||||
}
|
||||
.jr-admin-route-page .jr-admin-app {
|
||||
flex-direction: column;
|
||||
}
|
||||
.jr-admin-route-page .sidebar {
|
||||
width: 86%;
|
||||
max-width: 340px;
|
||||
}
|
||||
.jr-admin-route-page .jr-admin-header-side {
|
||||
width: auto;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
body.jr-admin-route-page .jr-topbar-inner {
|
||||
min-height: 52px;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
padding: 8px 0;
|
||||
gap: 6px;
|
||||
}
|
||||
body.jr-admin-route-page .jr-top-status {
|
||||
font-size: 0.8rem;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
body.jr-admin-route-page .jr-brandbar-inner {
|
||||
min-height: auto;
|
||||
padding: 14px 0;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
}
|
||||
body.jr-admin-route-page .jr-nav {
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
body.jr-admin-route-page .jr-nav a {
|
||||
min-width: 88px;
|
||||
padding: 8px 12px;
|
||||
font-size: 0.85rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.jr-admin-route-page .jr-admin-page .header,
|
||||
.jr-admin-route-page .jr-admin-page .content {
|
||||
padding-left: 14px;
|
||||
padding-right: 14px;
|
||||
}
|
||||
.jr-admin-route-page .content {
|
||||
padding: 14px;
|
||||
}
|
||||
.jr-admin-route-page .header {
|
||||
padding: 12px 14px;
|
||||
min-height: 60px;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.jr-admin-route-page .jr-page-intro {
|
||||
padding: 18px 16px;
|
||||
}
|
||||
.jr-admin-route-page .jr-page-intro h1 {
|
||||
font-size: clamp(1.4rem, 6vw, 2rem);
|
||||
}
|
||||
.jr-admin-route-page .jr-page-intro p {
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.jr-admin-route-page .card {
|
||||
padding: 14px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.jr-admin-route-page .management-container {
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
height: auto;
|
||||
overflow: visible;
|
||||
}
|
||||
.jr-admin-route-page .management-sidebar {
|
||||
width: 100%;
|
||||
max-height: 380px;
|
||||
}
|
||||
.jr-admin-route-page .management-main {
|
||||
overflow: visible;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.jr-admin-route-page .editor-toolbar {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 12px;
|
||||
}
|
||||
.jr-admin-route-page .editor-toolbar > .flex:first-child {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
.jr-admin-route-page .switch-label {
|
||||
width: 100%;
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
.jr-admin-route-page .hint-text {
|
||||
margin-left: 0;
|
||||
width: 100%;
|
||||
word-break: break-word;
|
||||
}
|
||||
.jr-admin-route-page .editor-toolbar > .flex:last-child {
|
||||
background: transparent !important;
|
||||
padding: 0 !important;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
.jr-admin-route-page .editor-toolbar > .flex:last-child input,
|
||||
.jr-admin-route-page .editor-toolbar > .flex:last-child button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.jr-admin-route-page .visual-line-container {
|
||||
padding: 16px 10px;
|
||||
min-height: 280px;
|
||||
cursor: default;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.jr-admin-route-page .visual-line-container svg {
|
||||
min-width: 720px;
|
||||
height: 220px;
|
||||
}
|
||||
|
||||
.jr-admin-route-page .faremap-card .flex.between {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
}
|
||||
.jr-admin-route-page .faremap-card .flex.between > .flex:last-child {
|
||||
width: 100%;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.jr-admin-route-page .faremap-card .flex.between > .flex:last-child button {
|
||||
flex: 1;
|
||||
min-width: 52px;
|
||||
}
|
||||
.jr-admin-route-page .faremap-viewport {
|
||||
max-height: 60vh;
|
||||
}
|
||||
.jr-admin-route-page .faremap-canvas {
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.jr-admin-route-page .ticket-table,
|
||||
.jr-admin-route-page table {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.jr-admin-route-page .ticket-table th,
|
||||
.jr-admin-route-page .ticket-table td,
|
||||
.jr-admin-route-page table th,
|
||||
.jr-admin-route-page table td {
|
||||
padding: 10px 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.jr-admin-route-page .modal-card {
|
||||
width: 96%;
|
||||
max-width: 96%;
|
||||
padding: 18px 16px;
|
||||
max-height: 92vh;
|
||||
border-radius: 0;
|
||||
}
|
||||
.jr-admin-route-page .modal-title {
|
||||
font-size: 1.05rem;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.jr-admin-route-page .modal-actions {
|
||||
flex-direction: column-reverse;
|
||||
margin-top: 20px;
|
||||
gap: 8px;
|
||||
}
|
||||
.jr-admin-route-page .modal-actions button {
|
||||
width: 100%;
|
||||
min-height: 48px;
|
||||
}
|
||||
.jr-admin-route-page select[multiple] {
|
||||
height: 160px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.jr-admin-route-page button,
|
||||
.jr-admin-route-page .btn {
|
||||
min-height: 44px;
|
||||
padding: 0 14px;
|
||||
}
|
||||
.jr-admin-route-page button.sm,
|
||||
.jr-admin-route-page .btn.sm {
|
||||
min-height: 36px;
|
||||
min-width: 36px;
|
||||
}
|
||||
.jr-admin-route-page .icon-btn {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
.jr-admin-route-page input,
|
||||
.jr-admin-route-page select {
|
||||
min-height: 44px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.jr-admin-route-page .line-item {
|
||||
padding: 14px 12px;
|
||||
min-height: 56px;
|
||||
}
|
||||
.jr-admin-route-page .line-item .line-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
.jr-admin-route-page .line-item .line-actions button {
|
||||
min-height: 36px;
|
||||
min-width: 36px;
|
||||
}
|
||||
|
||||
.jr-admin-route-page .site-footer {
|
||||
margin-top: 20px;
|
||||
padding-top: 12px;
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.jr-admin-route-page .header h3 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
.jr-admin-route-page .jr-admin-header-pill {
|
||||
font-size: 11px;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
.jr-admin-route-page .badge {
|
||||
font-size: 0.7rem;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
.jr-admin-route-page h4 {
|
||||
font-size: 0.95rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
.jr-admin-route-page h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
.jr-admin-route-page .jr-brand-copy strong {
|
||||
font-size: 1rem;
|
||||
}
|
||||
.jr-admin-route-page .jr-brand-copy span {
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
.jr-admin-route-page .jr-brand-logo {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
.jr-admin-route-page .faremap-viewport {
|
||||
max-height: 50vh;
|
||||
}
|
||||
.jr-admin-route-page .visual-line-container svg {
|
||||
min-width: 640px;
|
||||
}
|
||||
.jr-admin-route-page #app .ticket-header .flex.between:last-of-type {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
| ||||