|
|
@@ -41,13 +41,13 @@
|
|
|
|
|
|
<div class="form-interactive-area" :class="{ 'is-disabled': !isManualMode }">
|
|
|
<div class="control-method-content">
|
|
|
- <SegmentedRadio v-model="currentMethod" :options="controlMethodOptions" />
|
|
|
+ <SegmentedRadio v-model="currentMethod" :options="controlMethodOptions" size="auto" />
|
|
|
</div>
|
|
|
|
|
|
<div class="control-scheme">
|
|
|
<div class="control-label-wrap">
|
|
|
<span class="control-label">控制方案</span>
|
|
|
- <DropdownSelect v-model="currentScheme" :options="schemeOptions" />
|
|
|
+ <DropdownSelect v-model="currentScheme" :options="schemeOptions" size="auto" />
|
|
|
</div>
|
|
|
|
|
|
<div class="current-stage">
|
|
|
@@ -89,7 +89,7 @@
|
|
|
<div class="lock-time-option">
|
|
|
<label>
|
|
|
<input type="radio" v-model="lockTimeType" value="timer" /> 放行
|
|
|
- <DropdownSelect placeholder="锁定时间" v-model="currentLocktime" :options="locktimeOptions"
|
|
|
+ <DropdownSelect placeholder="锁定时间" v-model="currentLocktime" :options="locktimeOptions" size="auto"
|
|
|
@click.native.prevent />
|
|
|
秒解锁
|
|
|
</label>
|
|
|
@@ -171,26 +171,42 @@ export default {
|
|
|
this.updateSchemeDataByMethod(newVal);
|
|
|
}
|
|
|
},
|
|
|
- async mounted() {
|
|
|
- const nodeId = this.$attrs.id || this.id;
|
|
|
- const data = await apiGetCrossingDetailData(nodeId);
|
|
|
- if (data) {
|
|
|
- this.currentRoute = data.currentRoute || {};
|
|
|
- this.intersectionData = data.intersectionData || {};
|
|
|
- this.mockPhaseData = data.phaseData || [];
|
|
|
- this.cycleLength = data.cycleLength || 140;
|
|
|
- this.currentSec = data.currentTime || 0;
|
|
|
- this.phaseDiff = data.phaseDiff || 0;
|
|
|
- this.coordTime = data.coordTime || 0;
|
|
|
- this.currentStageList = data.stageList || [];
|
|
|
- this.schemeOptions = data.schemeOptions || [];
|
|
|
- if (data.currentScheme) this.currentScheme = data.currentScheme;
|
|
|
- if (data.controlMethodOptions) this.controlMethodOptions = data.controlMethodOptions;
|
|
|
- if (data.currentMethod) this.currentMethod = data.currentMethod;
|
|
|
- if (data.locktimeOptions) this.locktimeOptions = data.locktimeOptions;
|
|
|
- }
|
|
|
+ mounted() {
|
|
|
+ this.initScaleObserver();
|
|
|
+ this.loadData();
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ if (this._ro) this._ro.disconnect();
|
|
|
},
|
|
|
methods: {
|
|
|
+ initScaleObserver() {
|
|
|
+ const ro = new ResizeObserver(entries => {
|
|
|
+ const { width } = entries[0].contentRect;
|
|
|
+ const s = Math.min(width / 1315, 1);
|
|
|
+ this.$el.style.setProperty('--s', s);
|
|
|
+ });
|
|
|
+ ro.observe(this.$el);
|
|
|
+ this._ro = ro;
|
|
|
+ },
|
|
|
+ async loadData() {
|
|
|
+ const nodeId = this.$attrs.id || this.id;
|
|
|
+ const data = await apiGetCrossingDetailData(nodeId);
|
|
|
+ if (data) {
|
|
|
+ this.currentRoute = data.currentRoute || {};
|
|
|
+ this.intersectionData = data.intersectionData || {};
|
|
|
+ this.mockPhaseData = data.phaseData || [];
|
|
|
+ this.cycleLength = data.cycleLength || 140;
|
|
|
+ this.currentSec = data.currentTime || 0;
|
|
|
+ this.phaseDiff = data.phaseDiff || 0;
|
|
|
+ this.coordTime = data.coordTime || 0;
|
|
|
+ this.currentStageList = data.stageList || [];
|
|
|
+ this.schemeOptions = data.schemeOptions || [];
|
|
|
+ if (data.currentScheme) this.currentScheme = data.currentScheme;
|
|
|
+ if (data.controlMethodOptions) this.controlMethodOptions = data.controlMethodOptions;
|
|
|
+ if (data.currentMethod) this.currentMethod = data.currentMethod;
|
|
|
+ if (data.locktimeOptions) this.locktimeOptions = data.locktimeOptions;
|
|
|
+ }
|
|
|
+ },
|
|
|
// 切换手动控制模式
|
|
|
toggleManualMode() {
|
|
|
this.isManualMode = !this.isManualMode;
|
|
|
@@ -266,28 +282,35 @@ export default {
|
|
|
|
|
|
<style scoped>
|
|
|
.crossing-detail-panel {
|
|
|
+ --s: 1;
|
|
|
display: flex;
|
|
|
flex-direction: row;
|
|
|
- gap: 20px;
|
|
|
- /* padding: 20px; */
|
|
|
+ gap: clamp(4px, calc(var(--s) * 12px), 12px);
|
|
|
height: 100%;
|
|
|
min-height: 0;
|
|
|
+ overflow: hidden;
|
|
|
}
|
|
|
|
|
|
+/* ===== 左侧:还原原始固定 55% 占比 ===== */
|
|
|
.detail-panel-left {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
flex: 0 0 55%;
|
|
|
min-height: 0;
|
|
|
+ min-width: 0;
|
|
|
}
|
|
|
|
|
|
+/* ===== 右侧:flex 列容器 + 滚动兜底 ===== */
|
|
|
.detail-panel-right {
|
|
|
flex: 1;
|
|
|
min-width: 0;
|
|
|
min-height: 0;
|
|
|
+ overflow-y: auto;
|
|
|
+ overflow-x: hidden;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
.intersection-video-wrap {
|
|
|
width: 100%;
|
|
|
min-height: 0;
|
|
|
@@ -299,7 +322,6 @@ export default {
|
|
|
min-height: 0;
|
|
|
height: 120px;
|
|
|
flex-shrink: 0;
|
|
|
- --s: 1;
|
|
|
width: 100%;
|
|
|
min-width: 0;
|
|
|
background-color: transparent;
|
|
|
@@ -308,35 +330,35 @@ export default {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
overflow: hidden;
|
|
|
- padding: calc(var(--s) * 10px);
|
|
|
+ padding: clamp(3px, calc(var(--s) * 10px), 10px);
|
|
|
}
|
|
|
|
|
|
.header {
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
|
- margin-bottom: calc(var(--s) * 15px);
|
|
|
+ margin-bottom: clamp(2px, calc(var(--s) * 6px), 15px);
|
|
|
color: #e0e6f1;
|
|
|
flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
.title-area {
|
|
|
- font-size: calc(var(--s) * 16px);
|
|
|
+ font-size: clamp(9px, calc(var(--s) * 16px), 16px);
|
|
|
}
|
|
|
|
|
|
.main-title {
|
|
|
- font-size: calc(var(--s) * 18px);
|
|
|
+ font-size: clamp(10px, calc(var(--s) * 18px), 18px);
|
|
|
font-weight: bold;
|
|
|
- margin-right: calc(var(--s) * 10px);
|
|
|
+ margin-right: clamp(4px, calc(var(--s) * 10px), 10px);
|
|
|
}
|
|
|
|
|
|
.sub-info {
|
|
|
- font-size: calc(var(--s) * 12px);
|
|
|
+ font-size: clamp(8px, calc(var(--s) * 12px), 12px);
|
|
|
opacity: 0.8;
|
|
|
}
|
|
|
|
|
|
.checkbox-area {
|
|
|
- font-size: calc(var(--s) * 12px);
|
|
|
+ font-size: clamp(8px, calc(var(--s) * 12px), 12px);
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
cursor: pointer;
|
|
|
@@ -349,10 +371,10 @@ export default {
|
|
|
}
|
|
|
|
|
|
.checkbox-mock {
|
|
|
- width: calc(var(--s) * 14px);
|
|
|
- height: calc(var(--s) * 14px);
|
|
|
+ width: clamp(10px, calc(var(--s) * 14px), 14px);
|
|
|
+ height: clamp(10px, calc(var(--s) * 14px), 14px);
|
|
|
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
|
- margin-right: calc(var(--s) * 6px);
|
|
|
+ margin-right: clamp(3px, calc(var(--s) * 6px), 6px);
|
|
|
border-radius: 2px;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
@@ -368,7 +390,7 @@ export default {
|
|
|
width: 100%;
|
|
|
min-width: 0;
|
|
|
flex: 1;
|
|
|
- min-height: 80px;
|
|
|
+ min-height: 50px;
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
|
|
|
@@ -381,21 +403,38 @@ export default {
|
|
|
font-size: 14px;
|
|
|
}
|
|
|
|
|
|
+/* ===== 右侧表单内层容器 ===== */
|
|
|
+.detail-right-form {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+
|
|
|
+.form-group {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+
|
|
|
/** 控制方法 */
|
|
|
.control-method {
|
|
|
color: #ffffff;
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
.control-label-wrap {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
- margin-bottom: 20px;
|
|
|
- column-gap: 20px;
|
|
|
+ margin-bottom: clamp(4px, calc(var(--s) * 10px), 20px);
|
|
|
+ column-gap: clamp(4px, calc(var(--s) * 10px), 20px);
|
|
|
}
|
|
|
|
|
|
.control-label {
|
|
|
- font-size: 28px;
|
|
|
+ font-size: clamp(12px, calc(var(--s) * 22px), 28px);
|
|
|
color: #ffffff;
|
|
|
+ white-space: nowrap;
|
|
|
}
|
|
|
|
|
|
.control-label-wrap span {
|
|
|
@@ -403,7 +442,7 @@ export default {
|
|
|
}
|
|
|
|
|
|
.operation-btn {
|
|
|
- font-size: 14px;
|
|
|
+ font-size: clamp(9px, calc(var(--s) * 14px), 14px);
|
|
|
cursor: pointer;
|
|
|
user-select: none;
|
|
|
}
|
|
|
@@ -418,44 +457,51 @@ export default {
|
|
|
justify-content: space-between;
|
|
|
}
|
|
|
|
|
|
-.control-scheme {
|
|
|
- margin-top: 20px;
|
|
|
+/* 控制方式按钮组:设置 font-size 供 SegmentedRadio size="auto" 继承 */
|
|
|
+.control-method-content {
|
|
|
+ font-size: clamp(9px, calc(var(--s) * 14px), 14px);
|
|
|
+}
|
|
|
|
|
|
+.control-scheme {
|
|
|
+ margin-top: clamp(4px, calc(var(--s) * 10px), 20px);
|
|
|
+ /* 设置 font-size 供 DropdownSelect size="auto" 继承 */
|
|
|
+ font-size: clamp(9px, calc(var(--s) * 14px), 14px);
|
|
|
}
|
|
|
|
|
|
.lock-time {
|
|
|
- width: 40%;
|
|
|
+ width: 80%;
|
|
|
border-radius: 8px;
|
|
|
box-shadow:
|
|
|
inset 0px 0px 10px 0px rgba(88, 146, 255, 0.4),
|
|
|
inset 20px 0px 30px -10px rgba(88, 146, 255, 0.15);
|
|
|
-
|
|
|
}
|
|
|
|
|
|
.lock-time-label-wrap {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
- padding: 10px;
|
|
|
+ padding: clamp(4px, calc(var(--s) * 8px), 10px);
|
|
|
border-radius: 8px 8px 0 0;
|
|
|
color: #ffffff;
|
|
|
}
|
|
|
|
|
|
.lock-time-label {
|
|
|
- font-size: 16px;
|
|
|
+ font-size: clamp(10px, calc(var(--s) * 16px), 16px);
|
|
|
color: #ffffff;
|
|
|
}
|
|
|
|
|
|
.lock-time-options {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
- row-gap: 10px;
|
|
|
- font-size: 14px;
|
|
|
- padding: 10px;
|
|
|
+ row-gap: clamp(4px, calc(var(--s) * 10px), 10px);
|
|
|
+ font-size: clamp(9px, calc(var(--s) * 14px), 14px);
|
|
|
+ padding: clamp(4px, calc(var(--s) * 10px), 10px);
|
|
|
color: #ffffff;
|
|
|
}
|
|
|
|
|
|
-.lock-time-option {}
|
|
|
+.lock-time-option {
|
|
|
+ font-size: clamp(9px, calc(var(--s) * 14px), 14px);
|
|
|
+}
|
|
|
|
|
|
.lock-time-close {
|
|
|
cursor: pointer;
|
|
|
@@ -465,14 +511,13 @@ export default {
|
|
|
background: linear-gradient(180deg,
|
|
|
rgba(65, 115, 205, 0.6) 0%,
|
|
|
rgba(40, 70, 130, 0.1) 100%);
|
|
|
-
|
|
|
backdrop-filter: blur(10px);
|
|
|
}
|
|
|
|
|
|
.current-stage {
|
|
|
background-color: rgba(65, 115, 205, 0.2);
|
|
|
border: 1px solid #3660a5;
|
|
|
- margin-bottom: 20px;
|
|
|
+ margin-bottom: clamp(4px, calc(var(--s) * 10px), 20px);
|
|
|
display: flex;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
@@ -481,29 +526,31 @@ export default {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
- gap: 10px;
|
|
|
- padding: 32px;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: clamp(4px, calc(var(--s) * 8px), 10px);
|
|
|
+ padding: clamp(6px, calc(var(--s) * 12px), 32px);
|
|
|
color: #ffffff;
|
|
|
}
|
|
|
.current-stage-label {
|
|
|
- font-size: 14px;
|
|
|
- width: 100px;
|
|
|
+ font-size: clamp(9px, calc(var(--s) * 14px), 14px);
|
|
|
+ width: auto;
|
|
|
+ white-space: nowrap;
|
|
|
}
|
|
|
|
|
|
.stage-input {
|
|
|
- width: 65px;
|
|
|
+ width: clamp(32px, calc(var(--s) * 65px), 65px);
|
|
|
border: 1px solid rgba(161,190,255,0.7);
|
|
|
background-color: transparent;
|
|
|
- padding: 5px;
|
|
|
+ padding: clamp(2px, calc(var(--s) * 5px), 5px);
|
|
|
color: #ffffff;
|
|
|
text-align: center;
|
|
|
}
|
|
|
|
|
|
.phase-box {
|
|
|
position: relative;
|
|
|
- width: 65px; /* 保持原有的固定尺寸 */
|
|
|
- height: 65px;
|
|
|
- background: #E6F0FF;
|
|
|
+ width: clamp(30px, calc(var(--s) * 65px), 65px);
|
|
|
+ height: clamp(30px, calc(var(--s) * 65px), 65px);
|
|
|
+ background: #E6F0FF;
|
|
|
border-radius: 4px;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
@@ -528,25 +575,24 @@ export default {
|
|
|
left: 0;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
- background: rgba(30, 106, 255, 0.5); /* 激活时的蒙层颜色 */
|
|
|
- opacity: 0;
|
|
|
+ background: rgba(30, 106, 255, 0.5);
|
|
|
+ opacity: 0;
|
|
|
transition: opacity 0.3s ease;
|
|
|
- pointer-events: none; /* 防止阻挡点击事件 */
|
|
|
+ pointer-events: none;
|
|
|
}
|
|
|
|
|
|
.phase-box.is-active::after {
|
|
|
- opacity: 1;
|
|
|
+ opacity: 1;
|
|
|
}
|
|
|
|
|
|
/** 按钮 */
|
|
|
-/* 按钮基础通用样式 */
|
|
|
.btn {
|
|
|
display: inline-flex;
|
|
|
justify-content: center;
|
|
|
align-items: center;
|
|
|
- height: 36px;
|
|
|
- padding: 0 32px;
|
|
|
- font-size: 14px;
|
|
|
+ height: clamp(22px, calc(var(--s) * 36px), 36px);
|
|
|
+ padding: 0 clamp(10px, calc(var(--s) * 32px), 32px);
|
|
|
+ font-size: clamp(9px, calc(var(--s) * 14px), 14px);
|
|
|
border-radius: 4px;
|
|
|
cursor: pointer;
|
|
|
user-select: none;
|
|
|
@@ -554,36 +600,30 @@ export default {
|
|
|
box-sizing: border-box;
|
|
|
}
|
|
|
|
|
|
-/* --- 取消按钮 (幽灵按钮) --- */
|
|
|
.btn-cancel {
|
|
|
background-color: transparent;
|
|
|
color: #d1d5db;
|
|
|
border: 1px solid rgba(130, 150, 190, 0.4);
|
|
|
}
|
|
|
-
|
|
|
.btn-cancel:hover {
|
|
|
color: #ffffff;
|
|
|
border-color: rgba(130, 150, 190, 0.8);
|
|
|
background-color: rgba(255, 255, 255, 0.05);
|
|
|
}
|
|
|
-
|
|
|
.btn-cancel:active {
|
|
|
background-color: rgba(255, 255, 255, 0.1);
|
|
|
}
|
|
|
|
|
|
-/* --- 确认按钮 (实心主按钮) --- */
|
|
|
.btn-confirm {
|
|
|
background-color: #3b74ff;
|
|
|
color: #ffffff;
|
|
|
border: 1px solid #3b74ff;
|
|
|
}
|
|
|
-
|
|
|
.btn-confirm:hover {
|
|
|
background-color: #5a8bff;
|
|
|
border-color: #5a8bff;
|
|
|
box-shadow: 0 2px 8px rgba(59, 116, 255, 0.3);
|
|
|
}
|
|
|
-
|
|
|
.btn-confirm:active {
|
|
|
background-color: #265bed;
|
|
|
border-color: #265bed;
|
|
|
@@ -593,22 +633,27 @@ export default {
|
|
|
.button-group {
|
|
|
display: flex;
|
|
|
justify-content: flex-end;
|
|
|
- margin-top: 20px;
|
|
|
+ margin-top: clamp(4px, calc(var(--s) * 10px), 20px);
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
.button-group>div {
|
|
|
display: flex;
|
|
|
- gap: 12px;
|
|
|
+ gap: clamp(4px, calc(var(--s) * 8px), 12px);
|
|
|
}
|
|
|
|
|
|
-/* 禁用状态:未点击手动控制时,使表单只读 */
|
|
|
+/* 禁用状态 */
|
|
|
.form-interactive-area {
|
|
|
transition: opacity 0.3s;
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ overflow-y: auto;
|
|
|
+ overflow-x: hidden;
|
|
|
}
|
|
|
|
|
|
.form-interactive-area.is-disabled {
|
|
|
opacity: 0.6;
|
|
|
- pointer-events: none; /* 核心:禁止鼠标事件,无法点击下拉框、单选和输入框 */
|
|
|
+ pointer-events: none;
|
|
|
}
|
|
|
|
|
|
/* 当前阶段输入框微调 */
|
|
|
@@ -616,15 +661,15 @@ export default {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
align-items: center;
|
|
|
- gap: 6px;
|
|
|
+ gap: clamp(2px, calc(var(--s) * 4px), 6px);
|
|
|
position: relative;
|
|
|
}
|
|
|
|
|
|
.stage-input {
|
|
|
- width: 65px;
|
|
|
+ width: clamp(32px, calc(var(--s) * 65px), 65px);
|
|
|
border: 1px solid rgba(161,190,255,0.7);
|
|
|
background-color: transparent;
|
|
|
- padding: 5px;
|
|
|
+ padding: clamp(2px, calc(var(--s) * 5px), 5px);
|
|
|
color: #ffffff;
|
|
|
text-align: center;
|
|
|
border-radius: 4px;
|
|
|
@@ -638,10 +683,10 @@ export default {
|
|
|
|
|
|
.stage-item-wrapper .unit {
|
|
|
position: absolute;
|
|
|
- bottom: 6px;
|
|
|
- right: 8px;
|
|
|
+ bottom: clamp(2px, calc(var(--s) * 6px), 6px);
|
|
|
+ right: clamp(3px, calc(var(--s) * 6px), 8px);
|
|
|
color: #77A1FF;
|
|
|
- font-size: 12px;
|
|
|
+ font-size: clamp(8px, calc(var(--s) * 12px), 12px);
|
|
|
pointer-events: none;
|
|
|
}
|
|
|
|
|
|
@@ -654,22 +699,17 @@ export default {
|
|
|
transform: translateY(-10px);
|
|
|
}
|
|
|
|
|
|
-/* 原有 lock-time 样式调整使其能绝对定位,类似弹窗 */
|
|
|
+/* lock-time 弹窗补充样式 */
|
|
|
.lock-time {
|
|
|
- margin-top: 15px;
|
|
|
- width: 60%;
|
|
|
- border-radius: 8px;
|
|
|
- box-shadow:
|
|
|
- inset 0px 0px 10px 0px rgba(88, 146, 255, 0.4),
|
|
|
- inset 20px 0px 30px -10px rgba(88, 146, 255, 0.15);
|
|
|
- background-color: rgba(20, 30, 50, 0.9); /* 增加背景色防止透明穿透 */
|
|
|
+ margin-top: clamp(4px, calc(var(--s) * 10px), 15px);
|
|
|
+ background-color: rgba(20, 30, 50, 0.9);
|
|
|
}
|
|
|
|
|
|
/* 单选框基础对齐 */
|
|
|
.lock-time-option label {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
- gap: 8px;
|
|
|
+ gap: clamp(3px, calc(var(--s) * 6px), 8px);
|
|
|
cursor: pointer;
|
|
|
}
|
|
|
</style>
|