|
|
@@ -1,74 +1,479 @@
|
|
|
<template>
|
|
|
- <div class="emergency">
|
|
|
- <!--顶部-->
|
|
|
- <div>
|
|
|
- <p></p>
|
|
|
+ <div class="emergency-dialog">
|
|
|
+ <!-- 头部 -->
|
|
|
+ <div class="evac-hdr">
|
|
|
+ <span class="evac-hdr-icon">🚪</span>
|
|
|
+ <span class="evac-hdr-title">应急疏散</span>
|
|
|
+ <div class="evac-hdr-close" @click="$emit('close')">✕</div>
|
|
|
</div>
|
|
|
- <!--地图/监控-->
|
|
|
- <div>
|
|
|
- <!--地图-->
|
|
|
- <div>
|
|
|
|
|
|
+ <!-- 主体 -->
|
|
|
+ <div class="evac-body">
|
|
|
+ <!-- 左侧:平面图 -->
|
|
|
+ <div class="evac-map-col">
|
|
|
+ <div class="evac-legend">
|
|
|
+ <div class="evac-legend-rect"></div>
|
|
|
+ <span class="evac-legend-text">应急疏散路线图</span>
|
|
|
+ </div>
|
|
|
+ <div class="evac-map-wrap">
|
|
|
+ <div></div>
|
|
|
+ <!-- 告警浮层气泡 -->
|
|
|
+ <div class="evac-popup">
|
|
|
+ <div class="evac-popup-hdr">
|
|
|
+ <span class="evac-popup-alarm">🚨</span>
|
|
|
+ <span class="evac-popup-time">{{ alarmData.eventStartTime || '—' }}</span>
|
|
|
+ <span class="evac-popup-x">✕</span>
|
|
|
+ </div>
|
|
|
+ <div class="evac-popup-badge">触发风险</div>
|
|
|
+ <div class="evac-popup-msg">发生风险:{{ alarmData.eventName || '—' }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <!--监控-->
|
|
|
- <div>
|
|
|
|
|
|
+ <!-- 右侧:监控画面 -->
|
|
|
+ <div class="evac-right-col">
|
|
|
+ <div class="evac-right-hdr">{{ alarmData.roomNum || '—' }} · {{ alarmData.subName || '实验室名称' }}</div>
|
|
|
+ <div class="evac-cam-slot">实时视频监控</div>
|
|
|
+ <div class="evac-cam-slot">实时视频监控</div>
|
|
|
+ <div class="evac-floor-lbl">楼道 {{ alarmData.floor || '1' }}层</div>
|
|
|
+ <div class="evac-cam-slot">实时视频监控</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <!--报警信息/喇叭/操作按钮-->
|
|
|
- <div>
|
|
|
- <!--报警信息-->
|
|
|
- <div>
|
|
|
|
|
|
+ <!-- 底部 -->
|
|
|
+ <div class="evac-footer">
|
|
|
+ <!-- 告警指标 -->
|
|
|
+ <div class="evac-metrics">
|
|
|
+ <div v-for="(item, idx) in metricRows" :key="idx" class="evac-metric-row">
|
|
|
+ <div class="evac-metric-col">
|
|
|
+ <div class="evac-ml">{{ item.label }}</div>
|
|
|
+ <div class="evac-mv">{{ item.value }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="evac-metric-rt">{{ item.extra }}</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <!--喇叭-->
|
|
|
- <div>
|
|
|
|
|
|
+ <!-- 语音广播 -->
|
|
|
+ <div class="evac-broadcast">
|
|
|
+ <div class="evac-bc-hdr">
|
|
|
+ <span class="evac-bc-icon">📢</span>
|
|
|
+ <span class="evac-bc-title">语音广播</span>
|
|
|
+ <span class="evac-bc-device">选择播放设备</span>
|
|
|
+ </div>
|
|
|
+ <div class="evac-speaker-row">
|
|
|
+ <button
|
|
|
+ v-for="(sp, idx) in speakers"
|
|
|
+ :key="idx"
|
|
|
+ class="evac-speaker-btn"
|
|
|
+ :class="{ on: sp.active }"
|
|
|
+ @click="sp.active = !sp.active"
|
|
|
+ >{{ sp.name }}</button>
|
|
|
+ </div>
|
|
|
+ <div class="evac-input-row">
|
|
|
+ <input
|
|
|
+ v-model="broadcastText"
|
|
|
+ type="text"
|
|
|
+ class="evac-text-input"
|
|
|
+ placeholder="请输入喊话内容"
|
|
|
+ />
|
|
|
+ <button class="evac-send-btn" @click="sendBroadcast">发送</button>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <!--操作按钮-->
|
|
|
- <div>
|
|
|
|
|
|
+ <!-- 操作按钮 -->
|
|
|
+ <div class="evac-actions">
|
|
|
+ <button class="evac-btn-later" @click="later">稍后处理</button>
|
|
|
+ <button class="evac-btn-exec" @click="execute">执行疏散</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-
|
|
|
export default {
|
|
|
- name: 'emergency',
|
|
|
+ name: 'Emergency',
|
|
|
props: {
|
|
|
alarmData: {
|
|
|
type: Object,
|
|
|
default: () => ({})
|
|
|
}
|
|
|
},
|
|
|
- data(){
|
|
|
- return{
|
|
|
- pageType:1,
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ broadcastText: '',
|
|
|
+ speakers: [
|
|
|
+ { name: 'NKL1FB1122 喇叭', active: true },
|
|
|
+ { name: 'NKL1FB1123 喇叭', active: true },
|
|
|
+ { name: 'NKL1FB1124 喇叭', active: true }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ metricRows() {
|
|
|
+ const d = this.alarmData
|
|
|
+ const sensor = d.triggerUploadData && d.triggerUploadData[0] ? d.triggerUploadData[0] : {}
|
|
|
+ return [
|
|
|
+ {
|
|
|
+ label: '告警指标',
|
|
|
+ value: d.eventName || sensor.sensorName || '—',
|
|
|
+ extra: sensor.deviceValue != null ? `${sensor.deviceValue} ${sensor.unit || ''}` : '—'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '当前值 / 安全阈值',
|
|
|
+ value: d.eventName || sensor.sensorName || '—',
|
|
|
+ extra: sensor.min != null ? `${sensor.min} - ${sensor.max} ${sensor.unit || ''}` : '—'
|
|
|
+ }
|
|
|
+ ]
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
- //切换疏散弹窗按钮
|
|
|
- emergency(){
|
|
|
- console.log('疏散切换');
|
|
|
- this.$parent.emergencyButton(1);
|
|
|
+ later() {
|
|
|
+ this.$parent.emergencyButton(1)
|
|
|
},
|
|
|
+ execute() {
|
|
|
+ this.$emit('execute', this.alarmData)
|
|
|
+ },
|
|
|
+ sendBroadcast() {
|
|
|
+ if (!this.broadcastText.trim()) return
|
|
|
+ this.$emit('broadcast', {
|
|
|
+ text: this.broadcastText,
|
|
|
+ speakers: this.speakers.filter(s => s.active).map(s => s.name)
|
|
|
+ })
|
|
|
+ this.broadcastText = ''
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
-.emergency {
|
|
|
+.emergency-dialog {
|
|
|
width: 2200px;
|
|
|
height: 1210px;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
- background: #0d0002;
|
|
|
- border: 1px solid rgba(255, 40, 40, 0.5);
|
|
|
- box-shadow: 0 0 60px rgba(255, 0, 0, 0.3), inset 0 0 40px rgba(100, 0, 0, 0.15);
|
|
|
- border-radius: 8px;
|
|
|
+ background: linear-gradient(135deg, rgba(2, 8, 28, 0.99), rgba(1, 5, 20, 0.99));
|
|
|
+ border: 2px solid rgba(30, 144, 255, 0.45);
|
|
|
+ box-shadow: 0 0 200px rgba(30, 144, 255, 0.22), inset 0 0 120px rgba(0, 50, 140, 0.05);
|
|
|
+ border-radius: 20px;
|
|
|
overflow: hidden;
|
|
|
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
|
|
}
|
|
|
+
|
|
|
+/* 头部 */
|
|
|
+.evac-hdr {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 28px;
|
|
|
+ padding: 28px 44px;
|
|
|
+ border-bottom: 1px solid rgba(30, 144, 255, 0.2);
|
|
|
+ background: linear-gradient(90deg, rgba(0, 55, 160, 0.12), transparent);
|
|
|
+ flex-shrink: 0;
|
|
|
+
|
|
|
+ .evac-hdr-icon { font-size: 50px; }
|
|
|
+
|
|
|
+ .evac-hdr-title {
|
|
|
+ font-size: 38px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #ddf0ff;
|
|
|
+ letter-spacing: 6px;
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ .evac-hdr-close {
|
|
|
+ font-size: 40px;
|
|
|
+ color: rgba(168, 204, 232, 0.5);
|
|
|
+ cursor: pointer;
|
|
|
+ padding: 8px 16px;
|
|
|
+ border-radius: 6px;
|
|
|
+ transition: background 0.2s, color 0.2s;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: rgba(30, 144, 255, 0.22);
|
|
|
+ color: #ddf0ff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 主体 */
|
|
|
+.evac-body {
|
|
|
+ display: flex;
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+/* 左侧平面图 */
|
|
|
+.evac-map-col {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ padding: 20px 22px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 10px;
|
|
|
+
|
|
|
+ .evac-legend {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
+ justify-content: flex-end;
|
|
|
+
|
|
|
+ .evac-legend-rect {
|
|
|
+ width: 36px;
|
|
|
+ height: 14px;
|
|
|
+ background: #1e90ff;
|
|
|
+ border-radius: 3px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .evac-legend-text {
|
|
|
+ font-size: 24px;
|
|
|
+ color: rgba(110, 165, 210, 0.55);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .evac-map-wrap {
|
|
|
+ flex: 1;
|
|
|
+ position: relative;
|
|
|
+ min-height: 0;
|
|
|
+
|
|
|
+ svg {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 告警浮层气泡 */
|
|
|
+.evac-popup {
|
|
|
+ position: absolute;
|
|
|
+ top: 52%;
|
|
|
+ left: 3%;
|
|
|
+ background: rgba(239, 68, 68, 0.15);
|
|
|
+ border: 1px solid rgba(239, 68, 68, 0.55);
|
|
|
+ border-radius: 10px;
|
|
|
+ padding: 16px 20px;
|
|
|
+ width: 320px;
|
|
|
+ backdrop-filter: blur(6px);
|
|
|
+
|
|
|
+ .evac-popup-hdr {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+
|
|
|
+ .evac-popup-alarm { font-size: 24px; }
|
|
|
+ .evac-popup-time { font-size: 18px; color: rgba(255, 255, 255, 0.65); flex: 1; }
|
|
|
+ .evac-popup-x { font-size: 18px; color: rgba(255, 255, 255, 0.4); cursor: pointer; }
|
|
|
+ }
|
|
|
+
|
|
|
+ .evac-popup-badge {
|
|
|
+ background: #ef4444;
|
|
|
+ color: #fff;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 700;
|
|
|
+ border-radius: 5px;
|
|
|
+ padding: 3px 12px;
|
|
|
+ display: inline-block;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ letter-spacing: 1px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .evac-popup-msg {
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #fff;
|
|
|
+ letter-spacing: 1px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 右侧监控 */
|
|
|
+.evac-right-col {
|
|
|
+ flex: 0 0 420px;
|
|
|
+ border-left: 1px solid rgba(30, 144, 255, 0.15);
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+
|
|
|
+ .evac-right-hdr {
|
|
|
+ padding: 16px 22px;
|
|
|
+ font-size: 22px;
|
|
|
+ color: rgba(110, 165, 210, 0.55);
|
|
|
+ letter-spacing: 3px;
|
|
|
+ border-bottom: 1px solid rgba(30, 144, 255, 0.12);
|
|
|
+ background: rgba(30, 144, 255, 0.04);
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .evac-cam-slot {
|
|
|
+ flex: 1;
|
|
|
+ border-bottom: 1px solid rgba(30, 144, 255, 0.1);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ background: rgba(12, 15, 26, 0.6);
|
|
|
+ color: rgba(255, 255, 255, 0.2);
|
|
|
+ font-size: 22px;
|
|
|
+ letter-spacing: 3px;
|
|
|
+ min-height: 130px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .evac-floor-lbl {
|
|
|
+ padding: 10px 22px;
|
|
|
+ font-size: 20px;
|
|
|
+ color: rgba(110, 165, 210, 0.55);
|
|
|
+ letter-spacing: 3px;
|
|
|
+ background: rgba(30, 144, 255, 0.06);
|
|
|
+ border-top: 1px solid rgba(30, 144, 255, 0.12);
|
|
|
+ border-bottom: 1px solid rgba(30, 144, 255, 0.12);
|
|
|
+ flex-shrink: 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 底部 */
|
|
|
+.evac-footer {
|
|
|
+ padding: 18px 38px;
|
|
|
+ display: flex;
|
|
|
+ gap: 22px;
|
|
|
+ align-items: stretch;
|
|
|
+ border-top: 1px solid rgba(30, 144, 255, 0.15);
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* 告警指标 */
|
|
|
+.evac-metrics {
|
|
|
+ flex: 0 0 380px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 10px;
|
|
|
+ justify-content: center;
|
|
|
+
|
|
|
+ .evac-metric-row {
|
|
|
+ background: rgba(239, 68, 68, 0.06);
|
|
|
+ border: 1px solid rgba(239, 68, 68, 0.2);
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 10px 16px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .evac-ml { font-size: 18px; color: rgba(110, 165, 210, 0.55); margin-bottom: 4px; }
|
|
|
+ .evac-mv { font-size: 22px; font-weight: 600; color: #ef4444; }
|
|
|
+ .evac-metric-rt { font-size: 20px; color: rgba(255, 255, 255, 0.75); }
|
|
|
+}
|
|
|
+
|
|
|
+/* 语音广播 */
|
|
|
+.evac-broadcast {
|
|
|
+ flex: 1;
|
|
|
+ border: 1px solid rgba(30, 144, 255, 0.22);
|
|
|
+ border-radius: 12px;
|
|
|
+ padding: 14px 20px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 10px;
|
|
|
+ background: rgba(30, 144, 255, 0.04);
|
|
|
+
|
|
|
+ .evac-bc-hdr {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
+
|
|
|
+ .evac-bc-icon { font-size: 24px; }
|
|
|
+ .evac-bc-title { font-size: 24px; font-weight: 600; color: #ddf0ff; flex: 1; }
|
|
|
+ .evac-bc-device { font-size: 20px; color: rgba(110, 165, 210, 0.55); }
|
|
|
+ }
|
|
|
+
|
|
|
+ .evac-speaker-row {
|
|
|
+ display: flex;
|
|
|
+ gap: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .evac-speaker-btn {
|
|
|
+ flex: 1;
|
|
|
+ padding: 10px 8px;
|
|
|
+ border-radius: 8px;
|
|
|
+ font-size: 18px;
|
|
|
+ border: 1px solid rgba(30, 144, 255, 0.35);
|
|
|
+ background: rgba(30, 144, 255, 0.1);
|
|
|
+ color: #00d8ff;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: background 0.2s;
|
|
|
+ white-space: nowrap;
|
|
|
+ font-family: inherit;
|
|
|
+
|
|
|
+ &:hover,
|
|
|
+ &.on {
|
|
|
+ background: rgba(30, 144, 255, 0.25);
|
|
|
+ border-color: #00d8ff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .evac-input-row {
|
|
|
+ display: flex;
|
|
|
+ gap: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .evac-text-input {
|
|
|
+ flex: 1;
|
|
|
+ padding: 10px 16px;
|
|
|
+ border-radius: 8px;
|
|
|
+ font-size: 20px;
|
|
|
+ border: 1px solid rgba(30, 144, 255, 0.25);
|
|
|
+ background: rgba(0, 8, 36, 0.7);
|
|
|
+ color: #ddf0ff;
|
|
|
+ outline: none;
|
|
|
+ font-family: inherit;
|
|
|
+
|
|
|
+ &::placeholder { color: rgba(255, 255, 255, 0.2); }
|
|
|
+ }
|
|
|
+
|
|
|
+ .evac-send-btn {
|
|
|
+ padding: 10px 32px;
|
|
|
+ border-radius: 8px;
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: 600;
|
|
|
+ border: 1px solid rgba(30, 144, 255, 0.4);
|
|
|
+ background: rgba(30, 144, 255, 0.14);
|
|
|
+ color: #00d8ff;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: background 0.2s;
|
|
|
+ font-family: inherit;
|
|
|
+
|
|
|
+ &:hover { background: rgba(30, 144, 255, 0.3); }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 操作按钮 */
|
|
|
+.evac-actions {
|
|
|
+ flex: 0 0 300px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 12px;
|
|
|
+ justify-content: center;
|
|
|
+
|
|
|
+ button {
|
|
|
+ padding: 18px;
|
|
|
+ border-radius: 10px;
|
|
|
+ font-size: 26px;
|
|
|
+ font-weight: 700;
|
|
|
+ cursor: pointer;
|
|
|
+ font-family: inherit;
|
|
|
+ transition: background 0.2s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .evac-btn-later {
|
|
|
+ border: 1px solid rgba(255, 255, 255, 0.2);
|
|
|
+ background: rgba(255, 255, 255, 0.05);
|
|
|
+ color: rgba(255, 255, 255, 0.55);
|
|
|
+
|
|
|
+ &:hover { background: rgba(255, 255, 255, 0.1); }
|
|
|
+ }
|
|
|
+
|
|
|
+ .evac-btn-exec {
|
|
|
+ border: 2px solid #ef4444;
|
|
|
+ background: rgba(239, 68, 68, 0.16);
|
|
|
+ color: #ef4444;
|
|
|
+
|
|
|
+ &:hover { background: rgba(239, 68, 68, 0.32); }
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|