Merge branch 'dev' of http://222.212.85.86:8222/bdzl2/bxztApp into dev
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 534 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
@ -107,6 +107,47 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 自定义背景图按钮基类(用于使用背景图片的 button 元素)
|
||||||
|
.btn-custom-bg {
|
||||||
|
// 重置 button 默认样式
|
||||||
|
appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
background: transparent;
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
// 基础交互样式
|
||||||
|
cursor: pointer;
|
||||||
|
transition: opacity 0.3s, transform 0.2s;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
// 焦点样式(键盘导航时显示)
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 2px solid var(--primary-color);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 交互效果
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 禁用状态
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Flexbox 工具类
|
// Flexbox 工具类
|
||||||
.flex {
|
.flex {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@ -160,9 +160,11 @@ const handleStartDispatch = () => {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: vw(12);
|
gap: vw(12);
|
||||||
padding: vh(5) vw(16);
|
padding: vh(5) vw(16);
|
||||||
background: rgba(20, 53, 118, 0.6);
|
// background: rgba(20, 53, 118, 0.6);
|
||||||
border: 1px solid rgba(28, 161, 255, 0.3);
|
// border: 1px solid rgba(28, 161, 255, 0.3);
|
||||||
border-radius: vw(4);
|
// border-radius: vw(4);
|
||||||
|
background: url('../../assets/images/响应等级bg.png') no-repeat center center;
|
||||||
|
background-size: 100% 100%;
|
||||||
min-height: vh(40);
|
min-height: vh(40);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,9 +188,11 @@ const handleStartDispatch = () => {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: vw(8);
|
gap: vw(8);
|
||||||
padding: vh(10) vw(16);
|
padding: vh(10) vw(16);
|
||||||
background: linear-gradient(135deg, rgba(28, 161, 255, 0.3), rgba(28, 161, 255, 0.5));
|
// background: linear-gradient(135deg, rgba(28, 161, 255, 0.3), rgba(28, 161, 255, 0.5));
|
||||||
border: 1px solid rgba(28, 161, 255, 0.5);
|
// border: 1px solid rgba(28, 161, 255, 0.5);
|
||||||
border-radius: vw(4);
|
// border-radius: vw(4);
|
||||||
|
background: url('../../assets/images/文本按钮bg.png') no-repeat center center;
|
||||||
|
background-size: 100% 100%;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
min-height: vh(40);
|
min-height: vh(40);
|
||||||
@ -258,14 +262,14 @@ const handleStartDispatch = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.force-dispatch__stat-value {
|
.force-dispatch__stat-value {
|
||||||
font-size: fs(16);
|
font-size: fs(18);
|
||||||
font-family: SourceHanSansCN-Bold, sans-serif;
|
font-family: SourceHanSansCN-Bold, sans-serif;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--primary-color);
|
color: var(--text-white);
|
||||||
}
|
}
|
||||||
|
|
||||||
.force-dispatch__stat--action .force-dispatch__stat-value {
|
.force-dispatch__stat--action .force-dispatch__stat-value {
|
||||||
color: var(--warning-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.force-dispatch__stat-unit {
|
.force-dispatch__stat-unit {
|
||||||
@ -346,14 +350,14 @@ const handleStartDispatch = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.force-dispatch__circle-line1 {
|
.force-dispatch__circle-line1 {
|
||||||
font-size: fs(14);
|
font-size: fs(16);
|
||||||
font-family: SourceHanSansCN-Medium, sans-serif;
|
font-family: SourceHanSansCN-Medium, sans-serif;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--text-white);
|
color: var(--text-white);
|
||||||
}
|
}
|
||||||
|
|
||||||
.force-dispatch__circle-line2 {
|
.force-dispatch__circle-line2 {
|
||||||
font-size: fs(13);
|
font-size: fs(16);
|
||||||
font-family: SourceHanSansCN-Regular, sans-serif;
|
font-family: SourceHanSansCN-Regular, sans-serif;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: var(--text-white);
|
color: var(--text-white);
|
||||||
|
|||||||
@ -4,9 +4,14 @@
|
|||||||
<div class="custom-dropdown" v-click-outside="closeDropdown">
|
<div class="custom-dropdown" v-click-outside="closeDropdown">
|
||||||
<!-- 触发器 -->
|
<!-- 触发器 -->
|
||||||
<div class="dropdown-trigger" @click="toggleDropdown">
|
<div class="dropdown-trigger" @click="toggleDropdown">
|
||||||
<span class="trigger-text">距离灾害点{{ forcePreset.searchRadius }}km范围内</span>
|
<span class="trigger-text"
|
||||||
|
>距离灾害点{{ forcePreset.searchRadius }}km范围内</span
|
||||||
|
>
|
||||||
<div class="trigger-icon" :class="{ 'is-open': isDropdownOpen }">
|
<div class="trigger-icon" :class="{ 'is-open': isDropdownOpen }">
|
||||||
<img src="../../assets/images/SketchPng8063f445fba047c290a9620343b62ea51d767b8cdcd86769502b5b160998aacc.png" alt="dropdown" />
|
<img
|
||||||
|
src="../../assets/images/SketchPng8063f445fba047c290a9620343b62ea51d767b8cdcd86769502b5b160998aacc.png"
|
||||||
|
alt="dropdown"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -21,10 +26,29 @@
|
|||||||
@click="selectOption(option.value)"
|
@click="selectOption(option.value)"
|
||||||
>
|
>
|
||||||
<span class="item-text">{{ option.label }}</span>
|
<span class="item-text">{{ option.label }}</span>
|
||||||
<div v-if="forcePreset.searchRadius === option.value" class="item-icon">
|
<div
|
||||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
v-if="forcePreset.searchRadius === option.value"
|
||||||
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/>
|
class="item-icon"
|
||||||
<path d="M8 12L11 15L16 9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M8 12L11 15L16 9"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -37,6 +61,22 @@
|
|||||||
|
|
||||||
<div class="summary-stats">
|
<div class="summary-stats">
|
||||||
<div class="stat-group">
|
<div class="stat-group">
|
||||||
|
<div class="stat-card stat-card--base">
|
||||||
|
<span class="stat-label flexBox"
|
||||||
|
>应急基地
|
||||||
|
|
||||||
|
<img
|
||||||
|
src="../../assets/images/SketchPng157040b93d0288f48b67022319d8789e5ccded19d94fa14634044ed62a722b1c.png"
|
||||||
|
alt="base"
|
||||||
|
class="stat-icon"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div class="stat-value-wrapper">
|
||||||
|
<span class="stat-value">{{ forcePreset.bases }}</span>
|
||||||
|
<span class="stat-unit">处</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="stat-card stat-card--equipment">
|
<div class="stat-card stat-card--equipment">
|
||||||
<span class="stat-label">应急装备</span>
|
<span class="stat-label">应急装备</span>
|
||||||
<div class="stat-value-wrapper">
|
<div class="stat-value-wrapper">
|
||||||
@ -45,15 +85,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="stat-card stat-card--base">
|
|
||||||
<span class="stat-label">应急基地</span>
|
|
||||||
<div class="stat-value-wrapper">
|
|
||||||
<span class="stat-value">{{ forcePreset.bases }}</span>
|
|
||||||
<span class="stat-unit">处</span>
|
|
||||||
</div>
|
|
||||||
<!-- <img src="../../assets/images/SketchPng157040b93d0288f48b67022319d8789e5ccded19d94fa14634044ed62a722b1c.png" alt="base" class="stat-icon" /> -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="stat-card stat-card--personnel">
|
<div class="stat-card stat-card--personnel">
|
||||||
<span class="stat-label">应急人员</span>
|
<span class="stat-label">应急人员</span>
|
||||||
<div class="stat-value-wrapper">
|
<div class="stat-value-wrapper">
|
||||||
@ -69,10 +100,16 @@
|
|||||||
:key="station.id"
|
:key="station.id"
|
||||||
class="station-item"
|
class="station-item"
|
||||||
>
|
>
|
||||||
<img src="../../assets/images/路线icon.png" alt="station" class="station-icon" />
|
<img
|
||||||
|
src="../../assets/images/路线icon.png"
|
||||||
|
alt="station"
|
||||||
|
class="station-icon"
|
||||||
|
/>
|
||||||
<div class="station-info">
|
<div class="station-info">
|
||||||
<span class="station-name">{{ station.name }}</span>
|
<span class="station-name">{{ station.name }}</span>
|
||||||
<span class="station-distance">距离灾害点{{ station.distance }}公里</span>
|
<span class="station-distance"
|
||||||
|
>距离灾害点{{ station.distance }}公里</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -82,34 +119,34 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, inject } from 'vue'
|
import { ref, inject } from "vue";
|
||||||
|
|
||||||
const { forcePreset } = inject('disasterData')
|
const { forcePreset } = inject("disasterData");
|
||||||
const onDistanceChange = inject('onDistanceChange')
|
const onDistanceChange = inject("onDistanceChange");
|
||||||
|
|
||||||
// 下拉框状态
|
// 下拉框状态
|
||||||
const isDropdownOpen = ref(false)
|
const isDropdownOpen = ref(false);
|
||||||
|
|
||||||
// 距离选项
|
// 距离选项
|
||||||
const distanceOptions = [
|
const distanceOptions = [
|
||||||
{ value: 10, label: '距离灾害点10km范围内' },
|
// { value: 10, label: "距离灾害点10km范围内" },
|
||||||
{ value: 30, label: '距离灾害点30km范围内' },
|
{ value: 30, label: "距离灾害点30km范围内" },
|
||||||
{ value: 50, label: '距离灾害点50km范围内' }
|
{ value: 50, label: "距离灾害点50km范围内" },
|
||||||
]
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 切换下拉框显示/隐藏
|
* 切换下拉框显示/隐藏
|
||||||
*/
|
*/
|
||||||
const toggleDropdown = () => {
|
const toggleDropdown = () => {
|
||||||
isDropdownOpen.value = !isDropdownOpen.value
|
isDropdownOpen.value = !isDropdownOpen.value;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关闭下拉框
|
* 关闭下拉框
|
||||||
*/
|
*/
|
||||||
const closeDropdown = () => {
|
const closeDropdown = () => {
|
||||||
isDropdownOpen.value = false
|
isDropdownOpen.value = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 选择选项
|
* 选择选项
|
||||||
@ -117,30 +154,30 @@ const closeDropdown = () => {
|
|||||||
*/
|
*/
|
||||||
const selectOption = (value) => {
|
const selectOption = (value) => {
|
||||||
if (onDistanceChange) {
|
if (onDistanceChange) {
|
||||||
onDistanceChange(value)
|
onDistanceChange(value);
|
||||||
}
|
}
|
||||||
closeDropdown()
|
closeDropdown();
|
||||||
}
|
};
|
||||||
|
|
||||||
// 点击外部关闭下拉框的指令
|
// 点击外部关闭下拉框的指令
|
||||||
const vClickOutside = {
|
const vClickOutside = {
|
||||||
mounted(el, binding) {
|
mounted(el, binding) {
|
||||||
el.clickOutsideEvent = (event) => {
|
el.clickOutsideEvent = (event) => {
|
||||||
if (!(el === event.target || el.contains(event.target))) {
|
if (!(el === event.target || el.contains(event.target))) {
|
||||||
binding.value()
|
binding.value();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
document.addEventListener('click', el.clickOutsideEvent)
|
document.addEventListener("click", el.clickOutsideEvent);
|
||||||
},
|
},
|
||||||
unmounted(el) {
|
unmounted(el) {
|
||||||
document.removeEventListener('click', el.clickOutsideEvent)
|
document.removeEventListener("click", el.clickOutsideEvent);
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@use '@/styles/mixins.scss' as *;
|
@use "@/styles/mixins.scss" as *;
|
||||||
@use '../../assets/styles/common.scss' as *;
|
@use "../../assets/styles/common.scss" as *;
|
||||||
|
|
||||||
.force-preset {
|
.force-preset {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@ -286,7 +323,7 @@ const vClickOutside = {
|
|||||||
.stat-group {
|
.stat-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: vw(32);
|
gap: vw(22);
|
||||||
|
|
||||||
.stat-card {
|
.stat-card {
|
||||||
// flex: 1;
|
// flex: 1;
|
||||||
@ -298,9 +335,10 @@ const vClickOutside = {
|
|||||||
padding: vh(12) vw(12) vh(30);
|
padding: vh(12) vw(12) vh(30);
|
||||||
border-radius: vw(6);
|
border-radius: vw(6);
|
||||||
position: relative;
|
position: relative;
|
||||||
background: url('../../assets/images/完成里程.png') no-repeat center bottom;
|
background: url("../../assets/images/完成里程.png") no-repeat center
|
||||||
|
bottom;
|
||||||
// background-size: 100% 100%;
|
// background-size: 100% 100%;
|
||||||
width: vw(84);
|
width: vw(104);
|
||||||
|
|
||||||
.stat-label {
|
.stat-label {
|
||||||
color: var(--text-white);
|
color: var(--text-white);
|
||||||
@ -308,6 +346,11 @@ const vClickOutside = {
|
|||||||
font-family: SourceHanSansCN-Medium, sans-serif;
|
font-family: SourceHanSansCN-Medium, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flexBox{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.stat-value-wrapper {
|
.stat-value-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
@ -328,12 +371,12 @@ const vClickOutside = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.stat-icon {
|
.stat-icon {
|
||||||
position: absolute;
|
// position: absolute;
|
||||||
right: vw(8);
|
// right: vw(8);
|
||||||
bottom: vh(8);
|
// bottom: vh(8);
|
||||||
width: vw(24);
|
width: vw(12);
|
||||||
height: vh(24);
|
height: vw(10);
|
||||||
opacity: 0.5;
|
// opacity: 0.5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -361,7 +404,8 @@ const vClickOutside = {
|
|||||||
gap: vw(12);
|
gap: vw(12);
|
||||||
padding: vh(0) vw(12);
|
padding: vh(0) vw(12);
|
||||||
// background: rgba(20, 53, 118, 0.3);
|
// background: rgba(20, 53, 118, 0.3);
|
||||||
background: url('../../assets/images/文本线条框.png') no-repeat center center;
|
background: url("../../assets/images/文本线条框.png") no-repeat center
|
||||||
|
center;
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
border-radius: vw(6);
|
border-radius: vw(6);
|
||||||
|
|
||||||
|
|||||||
@ -114,7 +114,8 @@ const getColumnName = (type) => {
|
|||||||
grid-template-columns: vw(50) 1fr 1fr 1fr vw(80);
|
grid-template-columns: vw(50) 1fr 1fr 1fr vw(80);
|
||||||
gap: vw(8);
|
gap: vw(8);
|
||||||
padding: vh(12) vw(16);
|
padding: vh(12) vw(16);
|
||||||
background: rgba(20, 53, 118, 0.5);
|
// background: rgba(20, 53, 118, 0.5);
|
||||||
|
background: rgba(6, 38, 62, 0.8);
|
||||||
color: var(--text-white);
|
color: var(--text-white);
|
||||||
font-size: fs(13);
|
font-size: fs(13);
|
||||||
font-family: SourceHanSansCN-Medium, sans-serif;
|
font-family: SourceHanSansCN-Medium, sans-serif;
|
||||||
@ -127,8 +128,8 @@ const getColumnName = (type) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.table-body {
|
.table-body {
|
||||||
min-height: vh(205);
|
min-height: vh(170);
|
||||||
max-height: vh(205);
|
max-height: vh(170);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
@ -148,7 +149,8 @@ const getColumnName = (type) => {
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: vw(50) 1fr 1fr 1fr vw(80);
|
grid-template-columns: vw(50) 1fr 1fr 1fr vw(80);
|
||||||
gap: vw(8);
|
gap: vw(8);
|
||||||
padding: vh(12) vw(16);
|
padding: vh(6) vw(16);
|
||||||
|
background: linear-gradient(to right, #163b60, #133147);
|
||||||
color: var(--text-white);
|
color: var(--text-white);
|
||||||
font-size: fs(12);
|
font-size: fs(12);
|
||||||
font-family: SourceHanSansCN-Regular, sans-serif;
|
font-family: SourceHanSansCN-Regular, sans-serif;
|
||||||
@ -156,7 +158,7 @@ const getColumnName = (type) => {
|
|||||||
border-bottom: 1px solid rgba(28, 161, 255, 0.1);
|
border-bottom: 1px solid rgba(28, 161, 255, 0.1);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: rgba(28, 161, 255, 0.1);
|
background: rgba(28, 161, 255, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.col-index {
|
.col-index {
|
||||||
|
|||||||
@ -12,18 +12,12 @@
|
|||||||
|
|
||||||
<transition name="collapse">
|
<transition name="collapse">
|
||||||
<div v-show="!isCollapsed" class="video-monitor-item__content">
|
<div v-show="!isCollapsed" class="video-monitor-item__content">
|
||||||
<div class="video-placeholder">
|
<div class="video-placeholder">
|
||||||
<!-- 视频播放器 -->
|
<!-- 视频播放器 -->
|
||||||
<video
|
<video :src="monitor.videoSrc" autoplay loop muted playsinline />
|
||||||
:src="monitor.videoSrc"
|
|
||||||
autoplay
|
|
||||||
loop
|
|
||||||
muted
|
|
||||||
playsinline
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div class="video-time">{{ currentTime }}</div>
|
|
||||||
|
|
||||||
|
<div class="video-time">{{ currentTime }}</div>
|
||||||
|
</div>
|
||||||
<!-- 控制条:叠加在视频底部 -->
|
<!-- 控制条:叠加在视频底部 -->
|
||||||
<div class="video-controls">
|
<div class="video-controls">
|
||||||
<div
|
<div
|
||||||
@ -78,69 +72,71 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, onUnmounted } from 'vue'
|
import { ref, onMounted, onUnmounted } from "vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
monitor: {
|
monitor: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
defineEmits(['megaphone', 'audio', 'zoom'])
|
defineEmits(["megaphone", "audio", "zoom"]);
|
||||||
|
|
||||||
// 收起/展开状态
|
// 收起/展开状态
|
||||||
const isCollapsed = ref(false)
|
const isCollapsed = ref(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 切换收起/展开状态
|
* 切换收起/展开状态
|
||||||
*/
|
*/
|
||||||
const toggleCollapse = () => {
|
const toggleCollapse = () => {
|
||||||
isCollapsed.value = !isCollapsed.value
|
isCollapsed.value = !isCollapsed.value;
|
||||||
}
|
};
|
||||||
|
|
||||||
const currentTime = ref('')
|
const currentTime = ref("");
|
||||||
|
|
||||||
const updateTime = () => {
|
const updateTime = () => {
|
||||||
const now = new Date()
|
const now = new Date();
|
||||||
currentTime.value = now.toLocaleString('zh-CN', {
|
currentTime.value = now
|
||||||
year: 'numeric',
|
.toLocaleString("zh-CN", {
|
||||||
month: '2-digit',
|
year: "numeric",
|
||||||
day: '2-digit',
|
month: "2-digit",
|
||||||
hour: '2-digit',
|
day: "2-digit",
|
||||||
minute: '2-digit',
|
hour: "2-digit",
|
||||||
second: '2-digit',
|
minute: "2-digit",
|
||||||
hour12: false
|
second: "2-digit",
|
||||||
}).replace(/\//g, '/').replace(',', '')
|
hour12: false,
|
||||||
}
|
})
|
||||||
|
.replace(/\//g, "/")
|
||||||
|
.replace(",", "");
|
||||||
|
};
|
||||||
|
|
||||||
let timer = null
|
let timer = null;
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
updateTime()
|
updateTime();
|
||||||
timer = setInterval(updateTime, 1000)
|
timer = setInterval(updateTime, 1000);
|
||||||
})
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
if (timer) {
|
if (timer) {
|
||||||
clearInterval(timer)
|
clearInterval(timer);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@use '@/styles/mixins.scss' as *;
|
@use "@/styles/mixins.scss" as *;
|
||||||
@use '../../assets/styles/common.scss' as *;
|
@use "../../assets/styles/common.scss" as *;
|
||||||
|
|
||||||
.video-monitor-item {
|
.video-monitor-item {
|
||||||
// background: rgba(20, 53, 118, 0.3);
|
// background: rgba(20, 53, 118, 0.3);
|
||||||
background: url('../../assets/images/视频面板bg.png') no-repeat center center;
|
background: url("../../assets/images/视频面板bg.png") no-repeat center center;
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
// border-radius: vw(8);
|
// border-radius: vw(8);
|
||||||
@ -158,7 +154,8 @@ onUnmounted(() => {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: vh(10) vw(16);
|
padding: vh(10) vw(16);
|
||||||
background: rgba(20, 53, 118, 0.5);
|
// background: rgba(20, 53, 118, 0.5);
|
||||||
|
background: rgba(6, 38, 62, 0.8);
|
||||||
border-bottom: 1px solid var(--border-color);
|
border-bottom: 1px solid var(--border-color);
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
@ -230,7 +227,8 @@ onUnmounted(() => {
|
|||||||
z-index: 2;
|
z-index: 2;
|
||||||
width: clamp(140px, 10.1vw, 194px);
|
width: clamp(140px, 10.1vw, 194px);
|
||||||
height: clamp(28px, vh(32), 36px);
|
height: clamp(28px, vh(32), 36px);
|
||||||
background: url('../../assets/images/video-time-bg.png') no-repeat center center;
|
background: url("../../assets/images/video-time-bg.png") no-repeat
|
||||||
|
center center;
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
color: var(--text-white);
|
color: var(--text-white);
|
||||||
font-size: clamp(10px, fs(12), 12px);
|
font-size: clamp(10px, fs(12), 12px);
|
||||||
@ -242,65 +240,66 @@ onUnmounted(() => {
|
|||||||
padding: 0 clamp(4px, 1vw, 8px);
|
padding: 0 clamp(4px, 1vw, 8px);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
// 控制条:叠加在视频底部
|
}
|
||||||
.video-controls {
|
// 控制条:叠加在视频底部
|
||||||
position: absolute;
|
.video-controls {
|
||||||
left: 0;
|
// position: absolute;
|
||||||
right: 0;
|
left: 0;
|
||||||
bottom: 0;
|
right: 0;
|
||||||
z-index: 1;
|
bottom: 0;
|
||||||
// height: clamp(40px, 8vh, 60px);
|
z-index: 1;
|
||||||
background: rgba(10, 31, 57, 0.84);
|
// height: clamp(40px, 8vh, 60px);
|
||||||
display: flex;
|
background: rgba(10, 31, 57, 0.84);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0 clamp(10px, 2vw, 20px);
|
||||||
|
// gap: clamp(12px, 1.5vw, 20px);
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.video-control-item {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: row; // 保持左图标右文字布局
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 0 clamp(10px, 2vw, 20px);
|
padding: clamp(2px, vh(6), 8px) clamp(3px, vw(6), 6px);
|
||||||
// gap: clamp(12px, 1.5vw, 20px);
|
background: transparent;
|
||||||
box-sizing: border-box;
|
// border: 1px solid rgba(135, 206, 250, 0.3);
|
||||||
|
// border-radius: vw(4);
|
||||||
|
color: var(--text-white);
|
||||||
|
font-size: clamp(10px, fs(10), 11px);
|
||||||
|
// font-family: SourceHanSansCN-Regular, sans-serif;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.15s ease-out, background 0.2s ease,
|
||||||
|
border-color 0.2s ease;
|
||||||
|
transform-origin: center;
|
||||||
|
|
||||||
.video-control-item {
|
&__icon {
|
||||||
display: inline-flex;
|
width: clamp(12px, vw(14), 18px);
|
||||||
flex-direction: row; // 保持左图标右文字布局
|
height: clamp(12px, vh(14), 18px);
|
||||||
align-items: center;
|
margin-right: clamp(4px, vw(6), 8px);
|
||||||
justify-content: center;
|
flex-shrink: 0;
|
||||||
padding: clamp(2px, vh(6), 8px) clamp(3px, vw(6), 6px);
|
object-fit: contain;
|
||||||
background: transparent;
|
}
|
||||||
// border: 1px solid rgba(135, 206, 250, 0.3);
|
|
||||||
// border-radius: vw(4);
|
|
||||||
color: var(--text-white);
|
|
||||||
font-size: clamp(10px, fs(10), 11px);
|
|
||||||
// font-family: SourceHanSansCN-Regular, sans-serif;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: transform 0.15s ease-out, background 0.2s ease, border-color 0.2s ease;
|
|
||||||
transform-origin: center;
|
|
||||||
|
|
||||||
&__icon {
|
&__label {
|
||||||
width: clamp(12px, vw(14), 18px);
|
white-space: nowrap;
|
||||||
height: clamp(12px, vh(14), 18px);
|
line-height: 1.2;
|
||||||
margin-right: clamp(4px, vw(6), 8px);
|
}
|
||||||
flex-shrink: 0;
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__label {
|
&:hover {
|
||||||
white-space: nowrap;
|
transform: scale(1.05);
|
||||||
line-height: 1.2;
|
background: rgba(135, 206, 250, 0.1);
|
||||||
}
|
border-color: rgba(135, 206, 250, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:active {
|
||||||
transform: scale(1.05);
|
transform: scale(0.95);
|
||||||
background: rgba(135, 206, 250, 0.1);
|
}
|
||||||
border-color: rgba(135, 206, 250, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
&:focus-visible {
|
||||||
transform: scale(0.95);
|
outline: 2px solid rgba(135, 206, 250, 0.6);
|
||||||
}
|
outline-offset: 2px;
|
||||||
|
|
||||||
&:focus-visible {
|
|
||||||
outline: 2px solid rgba(135, 206, 250, 0.6);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="scene-label" :class="labelClass">
|
<div class="scene-label" :class="labelClass">
|
||||||
<div class="scene-label__content">
|
<div class="scene-label__content">
|
||||||
<img :src="iconSrc" alt="scene" class="scene-label__icon" />
|
<!-- <img :src="iconSrc" alt="scene" class="scene-label__icon" /> -->
|
||||||
<span class="scene-label__text">{{ text }}</span>
|
<span class="scene-label__text">{{ text }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -46,6 +46,8 @@ const iconSrc = sceneIcon
|
|||||||
top: calc(var(--sa-header-height));
|
top: calc(var(--sa-header-height));
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
background: url('../assets/images/灾害现场实景.png') no-repeat center center;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
|
||||||
// 中间分割线左侧(灾前现场实景)
|
// 中间分割线左侧(灾前现场实景)
|
||||||
&--center-left {
|
&--center-left {
|
||||||
@ -63,10 +65,10 @@ const iconSrc = sceneIcon
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: vw(6);
|
gap: vw(6);
|
||||||
padding: vw(5) vw(10);
|
padding: vw(8) vw(10);
|
||||||
background: rgba(20, 53, 118, 1);
|
// background: rgba(20, 53, 118, 1);
|
||||||
border: 1px solid var(--border-color);
|
// border: 1px solid var(--border-color);
|
||||||
border-radius: vw(8);
|
// border-radius: vw(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
&__icon {
|
&__icon {
|
||||||
@ -80,6 +82,7 @@ const iconSrc = sceneIcon
|
|||||||
font-family: SourceHanSansCN-Medium, sans-serif;
|
font-family: SourceHanSansCN-Medium, sans-serif;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
margin-left: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -48,26 +48,16 @@ const handleClick = () => {
|
|||||||
@use '../../assets/styles/common.scss' as *;
|
@use '../../assets/styles/common.scss' as *;
|
||||||
|
|
||||||
.action-button {
|
.action-button {
|
||||||
|
@extend .btn-custom-bg; // 继承自定义背景按钮基类
|
||||||
|
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: vw(6);
|
gap: vw(6);
|
||||||
border: none;
|
|
||||||
border-radius: vw(4);
|
|
||||||
cursor: pointer;
|
|
||||||
font-family: SourceHanSansCN-Medium, sans-serif;
|
font-family: SourceHanSansCN-Medium, sans-serif;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
transition: opacity 0.3s, transform 0.2s;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
&:hover {
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
transform: scale(0.98);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__icon {
|
&__icon {
|
||||||
width: vw(16);
|
width: vw(16);
|
||||||
height: vh(16);
|
height: vh(16);
|
||||||
@ -79,7 +69,10 @@ const handleClick = () => {
|
|||||||
|
|
||||||
// 类型样式
|
// 类型样式
|
||||||
&--primary {
|
&--primary {
|
||||||
background: var(--primary-color);
|
background-image: url('../../assets/images/文本按钮bg.png');
|
||||||
|
background-size: 100% 100%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
color: var(--text-white);
|
color: var(--text-white);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ export function useDisasterData() {
|
|||||||
equipment: 23,
|
equipment: 23,
|
||||||
bases: 2,
|
bases: 2,
|
||||||
personnel: 2124,
|
personnel: 2124,
|
||||||
searchRadius: 10, // km
|
searchRadius: 30, // km
|
||||||
stations: [
|
stations: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
|
|||||||
@ -20,7 +20,8 @@ export const BEFORE_3DTILES_CONFIG = {
|
|||||||
|
|
||||||
// 3D Tiles 服务 URL
|
// 3D Tiles 服务 URL
|
||||||
// TODO: 替换为实际的灾前模型 URL
|
// TODO: 替换为实际的灾前模型 URL
|
||||||
url: 'http://222.212.85.86:9000/300bdf2b-a150-406e-be63-d28bd29b409f/model/S107/terra_b3dms/tileset.json',
|
// url: 'http://222.212.85.86:9000/300bdf2b-a150-406e-be63-d28bd29b409f/model/S107/terra_b3dms/tileset.json',
|
||||||
|
url: 'http://222.212.85.86:9000/300bdf2b-a150-406e-be63-d28bd29b409f/model/ylzg/zxyj1119/terra_b3dms/tileset.json',
|
||||||
|
|
||||||
// 默认可见性
|
// 默认可见性
|
||||||
visible: false,
|
visible: false,
|
||||||
@ -69,8 +70,7 @@ export const BEFORE_IMAGERY_CONFIG = {
|
|||||||
// 影像服务URL
|
// 影像服务URL
|
||||||
// 格式:支持标准瓦片服务的URL模板,{z}/{x}/{y} 为瓦片坐标占位符
|
// 格式:支持标准瓦片服务的URL模板,{z}/{x}/{y} 为瓦片坐标占位符
|
||||||
// url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
// url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||||
// url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
|
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
|
||||||
url: 'http://222.212.85.86:9000/300bdf2b-a150-406e-be63-d28bd29b409f/model/ylzg/zxyj1119/terra_b3dms/tileset.json',
|
|
||||||
|
|
||||||
// 图层类型
|
// 图层类型
|
||||||
type: 'UrlTemplate',
|
type: 'UrlTemplate',
|
||||||
|
|||||||