| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- <template>
- <div class="crossing-panel">
- <div class="intersection-video-wrap">
- <IntersectionMapVideos :mapData="intersectionData" :videoUrls="currentRoute.cornerVideos" />
- </div>
- <div class="signal-timing-wrap">
- <div class="header" v-if="false">
- <div class="title-area">
- <span class="main-title">方案状态</span>
- <span class="sub-info">(周期: {{ cycleLength }} 相位差: 0 协调时间: 0)</span>
- </div>
- <div class="checkbox-area" v-if="false">
- <div class="checkbox-mock" :class="{ 'is-checked': followPhase }"
- @click="followPhase = !followPhase">
- <span v-if="followPhase" style="color: #fff; font-size: 12px; margin-left: 1px;">✓</span>
- </div>
- <span>跟随相位</span>
- </div>
- </div>
- <SignalTimingChart :cycleLength="cycleLength" :currentTime="currentSec" :phaseData="mockPhaseData" />
- </div>
- </div>
- </template>
- <script>
- import SignalTimingChart from '@/components/ui/SignalTimingChart.vue';
- import IntersectionMapVideos from '@/components/ui/IntersectionMapVideos.vue';
- import { getIntersectionData } from '@/mock/data';
- export default {
- name: 'CrossingPanel',
- components: {
- SignalTimingChart,
- IntersectionMapVideos
- },
- props: {
- },
- data() {
- return {
- followPhase: false,
- intersectionData: {},
- currentRoute: {
- id: 1, name: '靖远路与北公路交叉口 1', level: '一级', mode: '快进', time: '30s',
- mainVideo: require('@/assets/videos/video1.mp4'),
- cornerVideos: { nw: require('@/assets/videos/video1.mp4'), ne: require('@/assets/videos/video2.mp4'), sw: require('@/assets/videos/video2.mp4'), se: require('@/assets/videos/video1.mp4') }
- },
- cycleLength: 140,
- currentSec: 15,
- mockPhaseData: [
- // ================= 上轨道 (Track 0) =================
- // S1阶段 (0-30s): P1 直行
- [0, 0, 23, 'P1', 30, 'green', 'UP'],
- [0, 23, 26, '', 3, 'stripe', ''],
- [0, 26, 29, '', 3, 'yellow', ''],
- [0, 29, 30, '', 1, 'red', ''],
- // S2阶段 (30-60s): P2 左转
- [0, 30, 53, 'P2', 30, 'green', 'TURN_LEFT'],
- [0, 53, 56, '', 3, 'stripe', ''],
- [0, 56, 59, '', 3, 'yellow', ''],
- [0, 59, 60, '', 1, 'red', ''],
- // S3阶段 (60-110s): P3 侧向左转 (使用向左箭头)
- [0, 60, 103, 'P3', 50, 'green', 'TURN_LEFT'],
- [0, 103, 106, '', 3, 'stripe', ''],
- [0, 106, 109, '', 3, 'yellow', ''],
- [0, 109, 110, '', 1, 'red', ''],
- // S4阶段 (110-140s): P4 掉头
- [0, 110, 133, 'P4', 30, 'green', 'UTURN'],
- [0, 133, 136, '', 3, 'stripe', ''],
- [0, 136, 139, '', 3, 'yellow', ''],
- [0, 139, 140, '', 1, 'red', ''],
- // ================= 下轨道 (Track 1) =================
- // S1阶段 (0-30s): P5 直行
- [1, 0, 23, 'P5', 30, 'green', 'UP'],
- [1, 23, 26, '', 3, 'stripe', ''],
- [1, 26, 29, '', 3, 'yellow', ''],
- [1, 29, 30, '', 1, 'red', ''],
- // S2阶段 (30-60s): P6 左转
- [1, 30, 53, 'P6', 30, 'green', 'TURN_LEFT'],
- [1, 53, 56, '', 3, 'stripe', ''],
- [1, 56, 59, '', 3, 'yellow', ''],
- [1, 59, 60, '', 1, 'red', ''],
- // S3阶段 (60-110s): P7 侧向右转 (使用向右箭头)
- [1, 60, 103, 'P7', 50, 'green', 'TURN_RIGHT'],
- [1, 103, 106, '', 3, 'stripe', ''],
- [1, 106, 109, '', 3, 'yellow', ''],
- [1, 109, 110, '', 1, 'red', ''],
- // S4阶段 (110-140s): P8 左转
- [1, 110, 133, 'P8', 30, 'green', 'TURN_LEFT'],
- [1, 133, 136, '', 3, 'stripe', ''],
- [1, 136, 139, '', 3, 'yellow', ''],
- [1, 139, 140, '', 1, 'red', '']
- ]
- }
- },
- async mounted() {
- this.intersectionData = await getIntersectionData();
- },
- }
- </script>
- <style scoped>
- .crossing-panel {
- display: flex;
- flex-direction: column;
- }
- .intersection-video-wrap {
- width: 100%;
- height: 100px;
- flex: auto;
- }
- .signal-timing-wrap {
- flex: 1;
- --s: 1;
- width: 100%;
- height: 80px;
- min-width: 0;
- background-color: transparent;
- box-sizing: border-box;
- position: relative;
- display: flex;
- flex-direction: column;
- overflow: hidden;
- padding: calc(var(--s) * 10px);
- }
- .header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: calc(var(--s) * 15px);
- color: #e0e6f1;
- flex-shrink: 0;
- }
- .title-area {
- font-size: calc(var(--s) * 16px);
- }
- .main-title {
- font-size: calc(var(--s) * 18px);
- font-weight: bold;
- margin-right: calc(var(--s) * 10px);
- }
- .sub-info {
- font-size: calc(var(--s) * 12px);
- opacity: 0.8;
- }
- .checkbox-area {
- font-size: calc(var(--s) * 12px);
- display: flex;
- align-items: center;
- cursor: pointer;
- opacity: 0.7;
- user-select: none;
- }
- .checkbox-area:hover {
- opacity: 1;
- }
- .checkbox-mock {
- width: calc(var(--s) * 14px);
- height: calc(var(--s) * 14px);
- border: 1px solid rgba(255, 255, 255, 0.5);
- margin-right: calc(var(--s) * 6px);
- border-radius: 2px;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .checkbox-mock.is-checked {
- background-color: #4da8ff;
- border-color: #4da8ff;
- }
- .chart-container {
- width: 100%;
- min-width: 0;
- flex: 1;
- min-height: 80px;
- overflow: hidden;
- }
- .loading-overlay {
- flex: 1;
- display: flex;
- align-items: center;
- justify-content: center;
- color: #758599;
- font-size: 14px;
- }
- </style>
|