<template>
|
<div class="scene-deployment">
|
<div class="category-container">
|
<div class="category-item" v-for="(item, ind) in categoryList" :key="ind">
|
<div class="category-item-logo">
|
<img :src="item.logo" alt="">
|
</div>
|
|
<div class="category-item-content">
|
<span class="name">{{ item.name }}</span>
|
<span class="val">{{ item.val }}</span>
|
</div>
|
</div>
|
</div>
|
|
<div class="content" v-loading="loading" element-loading-background="rgba(5, 5, 15, 0.6)"
|
element-loading-text="加载中...">
|
<EmptyState v-if="!sceneList.length && !loading" />
|
<div class="scene-card" v-else v-for="(item, index) in sceneList" :key="index" @click="emit('click', item)">
|
<div class="card-header">
|
<el-tooltip class="title-tooltip" :content="item.sceneName || '-'" placement="top" effect="dark"
|
:show-after="200">
|
<span class="name">
|
{{ item.sceneName }}
|
</span>
|
</el-tooltip>
|
</div>
|
|
<div class="card-body">
|
<div class="row">
|
<span class="label">指挥点</span>
|
<span class="value">{{ formatPoint(item.longitude, item.latitude) }}</span>
|
</div>
|
<div class="rows">
|
<div class="col">
|
<span class="label">负责人</span>
|
<span class="value">{{ item.defenseLeader || '-' }}</span>
|
</div>
|
<div class="col">
|
<span class="label">电话</span>
|
<span class="value">{{ item.leaderPhone || '-' }}</span>
|
</div>
|
</div>
|
|
<div class="rows">
|
<div class="col">
|
<span class="label">区域数量</span>
|
<span class="value">{{ item.areaCount || 0 }}</span>
|
</div>
|
<div class="col">
|
<span class="label">设备数量</span>
|
<span class="value">{{ item.deviceCount || 0 }}</span>
|
</div>
|
</div>
|
|
<div class="row">
|
<span class="label">场景类型</span>
|
<span class="value">{{ getSceneTypeName(item.sceneType) }}</span>
|
</div>
|
<div class="row">
|
<span class="label">有效时间</span>
|
</div>
|
<div class="row">
|
<span class="value">{{ formatTimeRange(item.effectiveDateStart, item.effectiveDateEnd) }}</span>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, onMounted } from 'vue'
|
import dayjs from 'dayjs'
|
import sceneLogo from '@/assets/images/dataCockpit/scene.png'
|
import areaLogo from '@/assets/images/dataCockpit/area.png'
|
import EmptyState from './EmptyState.vue'
|
import { newDefenseSceneManageList, sceneManageStatisticsApi } from '@/api/dataCockpit'
|
import { getDictionaryByCode } from '@/api/system/dictbiz'
|
|
const loading = ref(false)
|
const sceneTypeDict = ref([])
|
const loadingTimer = ref(null)
|
|
const categoryList = ref([
|
{
|
name: '场景',
|
val: 0,
|
logo: sceneLogo // 暂时复用
|
},
|
{
|
name: '区域',
|
val: 0,
|
logo: areaLogo // 暂时复用
|
}
|
])
|
|
const sceneList = ref([])
|
|
const formatPoint = (lng, lat) => {
|
if (!lng || !lat) return '-'
|
return `${lng}, ${lat}`
|
}
|
|
const formatTimeRange = (start, end) => {
|
if (!start && !end) return '-'
|
const s = start ? dayjs(start).format('YYYY-MM-DD HH:mm:ss') : '-'
|
const e = end ? dayjs(end).format('YYYY-MM-DD HH:mm:ss') : '-'
|
return `${s} ~ ${e}`
|
}
|
|
const getSceneTypeName = (code) => {
|
const item = sceneTypeDict.value.find(i => i.dictKey === String(code))
|
return item ? item.dictValue : (code || '-')
|
}
|
|
const fetchDict = async () => {
|
try {
|
const res = await getDictionaryByCode('CommandSceneType')
|
if (res.data.code === 200) {
|
sceneTypeDict.value = res.data.data.CommandSceneType || []
|
}
|
} catch (error) {
|
console.error('获取场景类型字典失败:', error)
|
}
|
}
|
|
const fetchStatistics = async () => {
|
try {
|
const params = {
|
time: dayjs().format('YYYY-MM-DD HH:mm:ss')
|
}
|
const res = await sceneManageStatisticsApi(params)
|
|
if (res.data.code === 200) {
|
const { sceneManageCount, areaCount } = res.data.data
|
categoryList.value[0].val = sceneManageCount || 0
|
categoryList.value[1].val = areaCount || 0
|
}
|
} catch (error) {
|
console.error('获取场景统计失败:', error)
|
}
|
}
|
|
const emit = defineEmits(['click'])
|
|
const fetchList = async () => {
|
// 只有超过200ms才显示loading,避免闪烁
|
loadingTimer.value = setTimeout(() => {
|
loading.value = true
|
}, 200)
|
|
try {
|
const params = {
|
time: dayjs().format('YYYY-MM-DD HH:mm:ss')
|
}
|
const res = await newDefenseSceneManageList(params)
|
if (res.data.code === 200) {
|
sceneList.value = res.data.data || []
|
}
|
} catch (error) {
|
console.error('获取场景列表失败:', error)
|
} finally {
|
if (loadingTimer.value) clearTimeout(loadingTimer.value)
|
loading.value = false
|
}
|
}
|
|
onMounted(async () => {
|
await fetchDict()
|
fetchStatistics()
|
fetchList()
|
})
|
</script>
|
|
<style lang="scss" scoped>
|
.scene-deployment {
|
display: flex;
|
flex-direction: column;
|
height: 100%;
|
}
|
|
.category-container {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
gap: 28px;
|
box-sizing: border-box;
|
|
.category-item {
|
position: relative;
|
width: 0;
|
flex: 1;
|
display: flex;
|
height: 64px;
|
|
&-logo {
|
display: flex;
|
align-items: center;
|
|
img {
|
width: 40px;
|
height: 40px;
|
}
|
}
|
|
&-content {
|
width: 0;
|
flex: 1;
|
display: flex;
|
flex-direction: column;
|
border-bottom: 1px solid #6C6C89;
|
|
span {
|
margin-left: 8px;
|
}
|
|
.name {
|
font-family: Open Sans, Open Sans;
|
font-weight: 400;
|
font-size: 16px;
|
color: #C3C3DD;
|
line-height: 20px;
|
text-align: left;
|
font-style: normal;
|
text-transform: none;
|
}
|
|
.val {
|
margin-top: 1rem;
|
font-family: DinAB;
|
font-weight: bold;
|
font-size: 22px;
|
color: #FFFFFF;
|
line-height: 20px;
|
text-align: left;
|
font-style: normal;
|
text-transform: none;
|
}
|
}
|
}
|
}
|
|
.content {
|
flex: 1;
|
margin-top: 20px;
|
overflow-y: auto;
|
overflow-x: hidden;
|
}
|
|
.scene-card {
|
margin-top: 10px;
|
padding: 10px;
|
color: #fff;
|
background: #191933;
|
border-radius: 6px 6px 6px 6px;
|
cursor: pointer;
|
|
&:first-child {
|
margin-top: 0;
|
}
|
|
&:hover {
|
filter: brightness(1.05);
|
}
|
|
.card-header {
|
display: flex;
|
align-items: center;
|
gap: 6px;
|
min-width: 0;
|
|
.title-tooltip {
|
flex: 1;
|
min-width: 0;
|
display: block;
|
}
|
|
.name {
|
display: inline-block;
|
max-width: 100%;
|
font-family: Source Han Sans CN, Source Han Sans CN;
|
font-weight: bold;
|
font-size: 14px;
|
color: #FFFFFF;
|
text-align: left;
|
font-style: normal;
|
text-transform: none;
|
white-space: nowrap;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
}
|
}
|
|
.card-body {
|
margin-top: 10px;
|
display: flex;
|
flex-direction: column;
|
|
font-family: Source Han Sans CN, Source Han Sans CN;
|
font-weight: 400;
|
font-size: 12px;
|
color: #9E9EBA;
|
text-align: left;
|
font-style: normal;
|
text-transform: none;
|
|
.row {
|
margin-top: 10px;
|
|
line-height: 22px;
|
|
.label {
|
margin-right: 10px;
|
color: #D4D5D7;
|
}
|
|
&:first-child {
|
margin-top: 0;
|
}
|
|
&:last-child {
|
margin-top: 0;
|
}
|
}
|
|
.rows {
|
margin-top: 10px;
|
|
display: flex;
|
|
.col {
|
flex: 1;
|
|
.label {
|
margin-right: 10px;
|
color: #D4D5D7;
|
}
|
}
|
}
|
}
|
}
|
</style>
|