2 커밋 041695ff29 ... be6fd28bc4

작성자 SHA1 메시지 날짜
  画安 be6fd28bc4 优化 CrossingDetailPanel 步进模式交互与多屏适配 2 주 전
  画安 16c24f793e 优化临时方案时间表单布局,适配多屏模式下的窄容器显示 2 주 전
1개의 변경된 파일105개의 추가작업 그리고 60개의 파일을 삭제
  1. 105 60
      src/components/ui/CrossingDetailPanel.vue

+ 105 - 60
src/components/ui/CrossingDetailPanel.vue

@@ -47,38 +47,41 @@
 
                                 <el-date-picker v-model="startDate" type="date" placeholder="选择日期"
                                     value-format="yyyy-MM-dd" size="small" :append-to-body="true"
-                                    :popper-options="{ boundariesPadding: 0, gpuAcceleration: false }"
-                                    class="form-item">
+                                    :popper-options="{ boundariesPadding: 0, gpuAcceleration: false }">
                                 </el-date-picker>
 
-                                <el-time-picker v-model="startTime" placeholder="选择时间" value-format="HH:mm:ss"
-                                    size="small" :append-to-body="true"
-                                    :popper-options="{ boundariesPadding: 0, gpuAcceleration: false }"
-                                    class="form-item">
+                                <el-time-picker v-model="startTime" placeholder="选择时间"
+                                    value-format="HH:mm:ss" size="small" :append-to-body="true"
+                                    :popper-options="{ boundariesPadding: 0, gpuAcceleration: false }">
                                 </el-time-picker>
 
                                 <el-date-picker v-model="endDate" type="date" placeholder="选择日期"
                                     value-format="yyyy-MM-dd" size="small" :append-to-body="true"
-                                    :popper-options="{ boundariesPadding: 0, gpuAcceleration: false }"
-                                    class="form-item">
+                                    :popper-options="{ boundariesPadding: 0, gpuAcceleration: false }">
                                 </el-date-picker>
 
-                                <el-time-picker v-model="endTime" placeholder="选择时间" value-format="HH:mm:ss"
-                                    size="small" :append-to-body="true"
-                                    :popper-options="{ boundariesPadding: 0, gpuAcceleration: false }"
-                                    class="form-item">
+                                <el-time-picker v-model="endTime" placeholder="选择时间"
+                                    value-format="HH:mm:ss" size="small" :append-to-body="true"
+                                    :popper-options="{ boundariesPadding: 0, gpuAcceleration: false }">
                                 </el-time-picker>
 
-                                <el-select v-model="duration" placeholder="请选择时长" size="small"
-                                    :popper-append-to-body="true" class="form-item">
-                                    <el-option v-for="d in durationOptions" :key="d" :label="d"
-                                        :value="d"></el-option>
-                                </el-select>
+                                <div class="form-item-labeled">
+                                    <span class="form-label">时长</span>
+                                    <el-select v-model="duration" placeholder="请选择时长" size="small"
+                                        :popper-append-to-body="true">
+                                        <el-option v-for="d in durationOptions" :key="d" :label="d"
+                                            :value="d"></el-option>
+                                    </el-select>
+                                </div>
 
-                                <el-select v-model="period" placeholder="请选择周期" size="small"
-                                    :popper-append-to-body="true" class="form-item">
-                                    <el-option v-for="p in 8" :key="p" :label="'周期' + p" :value="p"></el-option>
-                                </el-select>
+                                <div class="form-item-labeled">
+                                    <span class="form-label">周期</span>
+                                    <el-select v-model="period" placeholder="请选择周期" size="small"
+                                        :popper-append-to-body="true">
+                                        <el-option v-for="p in 8" :key="p" :label="'周期' + p"
+                                            :value="p"></el-option>
+                                    </el-select>
+                                </div>
 
                             </div>
 
@@ -88,7 +91,7 @@
                                     <div v-for="(item, index) in currentStageList" :key="index"
                                         class="stage-item-wrapper">
                                         <div class="phase-box" :class="{ 'is-active': item.value === currentStage }"
-                                            @click="currentStage = item.value">
+                                            @click="onStageClick(item.value)">
                                             <img :src="item.img" alt="stage" class="phase-image" />
                                         </div>
 
@@ -105,8 +108,8 @@
                                 </div>
                             </div>
 
-                            <!-- 方案圆饼图 -->
-                            <div class="donut-row" v-if="!showLockTime">
+                            <!-- 方案圆饼图:步进模式下不显示 -->
+                            <div class="donut-row" v-if="!showLockTime && currentMethod !== 'step'">
                                 <div class="donut-item">
                                     <div class="donut-title">实时方案(执行方案3)</div>
                                     <PlanDonutChart :chartData="realtimeDonutData"
@@ -141,12 +144,18 @@
                                             </label>
                                         </div>
                                     </div>
+                                    <div class="lock-time-actions" v-if="currentMethod === 'step'">
+                                        <button type="button" class="btn btn-cancel"
+                                            @click="onCancel()">取消</button>
+                                        <button type="button" class="btn btn-confirm"
+                                            @click="onConfirm()">确认</button>
+                                    </div>
                                 </div>
                             </transition>
                         </div>
                     </div>
 
-                    <div class="button-group" v-show="isManualMode">
+                    <div class="button-group" v-show="isManualMode && currentMethod !== 'step'">
                         <div>
                             <button type="button" class="btn btn-cancel" @click="onCancel()">取消</button>
                             <button type="button" class="btn btn-confirm" @click="onConfirm()">确认</button>
@@ -244,23 +253,14 @@ export default {
     watch: {
         // 监听控制方式切换
         currentMethod(newVal) {
-            // 需求4:切换步进方案策略时,出现锁定时间弹窗
+            // 切换到步进时不自动弹出锁定时间,等用户点击阶段再弹
+            this.showLockTime = false;
             if (newVal === 'step') {
-                this.showLockTime = true;
                 this.syncLocktimeByStage();
-            } else {
-                this.showLockTime = false;
             }
 
             // 模拟需求1:根据不同模式,切换对应的控制方案数据 (Mock 逻辑)
             this.updateSchemeDataByMethod(newVal);
-        },
-        // 步进模式下切换阶段时,更新锁定时间选项并重新显示面板
-        currentStage() {
-            if (this.currentMethod === 'step') {
-                this.showLockTime = true;
-                this.syncLocktimeByStage();
-            }
         }
     },
     mounted() {
@@ -275,6 +275,14 @@ export default {
         if (this._ro) this._ro.disconnect();
     },
     methods: {
+        // 点击阶段:切换选中,步进模式下同时弹出锁定时间
+        onStageClick(value) {
+            this.currentStage = value;
+            if (this.currentMethod === 'step') {
+                this.showLockTime = true;
+                this.syncLocktimeByStage();
+            }
+        },
         // 根据当前选中阶段同步锁定时间选项
         syncLocktimeByStage() {
             const stage = this.currentStageList.find(s => s.value === this.currentStage);
@@ -742,6 +750,14 @@ export default {
     color: #ffffff;
 }
 
+.lock-time-actions {
+    display: flex;
+    justify-content: flex-end;
+    gap: clamp(4px, calc(var(--s) * 8px), 8px);
+    padding: clamp(4px, calc(var(--s) * 8px), 8px) clamp(4px, calc(var(--s) * 10px), 10px);
+    border-top: 1px solid rgba(161, 190, 255, 0.15);
+}
+
 .lock-time-option {
     font-size: clamp(9px, calc(var(--s) * 14px), 14px);
 }
@@ -769,21 +785,21 @@ export default {
     width: 100%;
     display: flex;
     align-items: center;
-    justify-content: space-around;
-    flex-wrap: wrap;
-    gap: clamp(4px, calc(var(--s) * 8px), 10px);
-    padding: clamp(6px, calc(var(--s) * 12px), 32px);
+    flex-wrap: nowrap;
+    gap: clamp(8px, calc(var(--s) * 18px), 24px);
+    padding: clamp(4px, calc(var(--s) * 8px), 16px);
     color: #ffffff;
 }
 
 .current-stage-label {
     font-size: clamp(9px, calc(var(--s) * 14px), 14px);
-    width: auto;
     white-space: nowrap;
+    flex-shrink: 0;
 }
 
 .stage-input {
-    width: clamp(32px, calc(var(--s) * 65px), 65px);
+    width: 100%;
+    min-width: 0;
     border: 1px solid rgba(161, 190, 255, 0.7);
     background-color: transparent;
     padding: clamp(2px, calc(var(--s) * 5px), 5px);
@@ -793,8 +809,8 @@ export default {
 
 .phase-box {
     position: relative;
-    width: clamp(30px, calc(var(--s) * 90px), 90px);
-    height: clamp(30px, calc(var(--s) * 90px), 90px);
+    width: 100%;
+    aspect-ratio: 1 / 1;
     background: #E6F0FF;
     border-radius: 4px;
     display: flex;
@@ -907,6 +923,8 @@ export default {
 
 /* 当前阶段输入框微调 */
 .stage-item-wrapper {
+    flex: 1 1 0;
+    min-width: 0;
     display: flex;
     flex-direction: column;
     align-items: stretch;
@@ -929,7 +947,8 @@ export default {
 }
 
 .stage-input {
-    width: clamp(32px, calc(var(--s) * 65px), 65px);
+    width: 100%;
+    min-width: 0;
     border: 1px solid rgba(161, 190, 255, 0.7);
     background-color: transparent;
     padding: clamp(2px, calc(var(--s) * 5px), 5px);
@@ -959,13 +978,22 @@ export default {
 }
 
 .stage-input {
-    width: clamp(32px, calc(var(--s) * 65px), 65px);
+    width: 100%;
+    min-width: 0;
     border: 1px solid rgba(161, 190, 255, 0.7);
     background-color: transparent;
     padding: clamp(2px, calc(var(--s) * 5px), 5px);
+    font-size: clamp(9px, calc(var(--s) * 11px), 11px);
     color: #ffffff;
     text-align: center;
     border-radius: 4px;
+    -moz-appearance: textfield;
+}
+
+.stage-input::-webkit-outer-spin-button,
+.stage-input::-webkit-inner-spin-button {
+    -webkit-appearance: none;
+    margin: 0;
 }
 
 .stage-input:disabled {
@@ -1020,20 +1048,35 @@ export default {
 
 /* ===== 时间表单栏布局 ===== */
 .time-form-bar {
-    display: flex;
-    flex-wrap: wrap;
-    gap: clamp(4px, calc(var(--s) * 8px), 10px);
+    display: grid;
+    grid-template-columns: repeat(4, 1fr);
+    gap: clamp(3px, calc(var(--s) * 5px), 6px);
     margin-bottom: clamp(4px, calc(var(--s) * 10px), 20px);
 }
 
-.time-form-bar .form-item {
-    flex: 1 1 calc(30% - 8px);
-    min-width: clamp(80px, calc(var(--s) * 140px), 140px);
+/* 第二行:带标签的项各占 2 列(共 4 列,两项铺满一行) */
+.time-form-bar .form-item-labeled {
+    grid-column: span 2;
+    display: flex;
+    align-items: center;
+    gap: clamp(3px, calc(var(--s) * 6px), 8px);
+}
+
+.time-form-bar .form-label {
+    white-space: nowrap;
+    flex-shrink: 0;
+    color: rgba(200, 220, 255, 0.65);
+    font-size: clamp(9px, calc(var(--s) * 12px), 13px);
+}
+
+.time-form-bar .form-item-labeled .el-select {
+    flex: 1;
+    min-width: 0;
 }
 
 /* ===== ElementUI 深色主题适配 ===== */
 
-/* 覆盖 el-date-editor 固定宽度,让其跟随 flex 布局 */
+/* 覆盖 el-date-editor 固定宽度,让其跟随 grid 布局 */
 .time-form-bar>>>.el-date-editor.el-input,
 .time-form-bar>>>.el-date-editor.el-input__inner,
 .time-form-bar>>>.el-select {
@@ -1045,9 +1088,11 @@ export default {
     background-color: rgba(255, 255, 255, 0.06);
     border: 1px solid rgba(161, 190, 255, 0.35);
     color: #e0e6f1;
-    font-size: clamp(9px, calc(var(--s) * 13px), 13px);
-    height: clamp(22px, calc(var(--s) * 32px), 32px);
-    line-height: clamp(22px, calc(var(--s) * 32px), 32px);
+    font-size: clamp(9px, calc(var(--s) * 11px), 11px);
+    height: clamp(22px, calc(var(--s) * 28px), 28px);
+    line-height: clamp(22px, calc(var(--s) * 28px), 28px);
+    padding-left: clamp(22px, calc(var(--s) * 26px), 26px);
+    padding-right: clamp(4px, calc(var(--s) * 6px), 6px);
 }
 
 .time-form-bar>>>.el-input__inner::placeholder {
@@ -1062,15 +1107,15 @@ export default {
     border-color: #3b74ff;
 }
 
-/* 图标颜色与大小 */
+/* 图标颜色、尺寸跟随缩放 */
 .time-form-bar>>>.el-input__prefix,
 .time-form-bar>>>.el-input__suffix {
     color: rgba(255, 255, 255, 0.4);
-    font-size: clamp(9px, calc(var(--s) * 14px), 14px);
 }
 
 .time-form-bar>>>.el-input__icon {
-    line-height: clamp(22px, calc(var(--s) * 32px), 32px);
-    width: clamp(16px, calc(var(--s) * 25px), 25px);
+    font-size: clamp(9px, calc(var(--s) * 12px), 12px);
+    line-height: clamp(22px, calc(var(--s) * 28px), 28px);
+    width: clamp(18px, calc(var(--s) * 22px), 22px);
 }
 </style>