Zlpt_Portal/src/views/home/map.vue

1531 lines
57 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import EquipCard from 'components/equipCard.vue'
import EquipCardNew from 'components/equipCardNew/index.vue'
import NavMenu from 'components/Navmenu/index.vue'
import { getGoodsClassListApi, getCompanyListApi, getSwiperListApi } from 'http/api/home'
import { useStore } from 'store/user'
import { mainStore } from 'store/main'
import { getHotList } from 'http/api/equip'
import { loginNewApi } from 'http/api/home/index'
import { getUserInfoAPI } from 'http/api/login/index'
import { ElMessage } from 'element-plus'
import { wgs84ToBd09Direct } from 'utils/map'
import { getMapData, mapLoginApi, getIotListApi, getBadgeInfoApi } from 'http/api/map'
import icon1 from '@/assets/img/work-card.jpg'
import icon2 from '@/assets/img/IOT.jpg'
const router: any = useRouter()
const userStore = useStore()
const store: any = mainStore()
const tokenNew = localStorage.getItem('tokenNew')
const companyList: any = ref([])
const classList: any = ref([])
const selectOptions = ref<boolean>(false) // 分类
const selectOptionsValue = ref<string>('分类筛选')
const mapContainer = ref(null) // 地图容器
const mapDialog = ref(false) // 地图弹框
const mapWorkCard = ref(false) // 工牌信息弹框
const mapWorkCardData: any = ref({}) // 工牌信息数据
// 定时器
let timer: any = ref()
// 标记点
const points: any = ref([])
const iot: any = ref([])
const mapData = ref()
const tagData: any = ref()
const tagIndex: any = ref()
// 监听 mapDialog
watch(
() => mapDialog.value,
(newValue) => {
if (!newValue && timer.value) {
// 清除定时器
clearInterval(timer.value)
}
},
)
// 登录
const loginApi = async () => {
try {
const res: any = await mapLoginApi({})
console.log('🚀 ~ loginApi ~ res:', res)
} catch (error) {
console.log('🚀 ~ loginApi ~ error:', error)
getMapDataList()
}
}
// 获取地图数据
const getMapDataList = async () => {
try {
await getMapData()
} catch (res: any) {
console.log('--------------', res)
console.log('🚀 ~ getMapDataList ~ res:', res)
if (res && res.length > 0) {
const point = res.map((item: any) => {
const longitudeNum = Number(item.longitude)
const latitudeNum = Number(item.latitude)
console.log(longitudeNum, latitudeNum)
let { longitude, latitude } = wgs84ToBd09Direct(latitudeNum, longitudeNum)
console.log('🚀 ~ getMapDataList ~ longitude:', longitude, latitude)
return {
id: item.uuid,
lng: longitude,
lat: latitude,
item: item,
isWork: false,
}
})
points.value = [...JSON.parse(JSON.stringify(points.value)), ...point]
}
//getWorkData()
initMap()
}
}
// 获取工牌信息
const getWorkData = async () => {
try {
await getIotListApi()
} catch (res: any) {
console.log('🚀 ~ getWorkData ~ res:', res)
if (res.errorCode != 200) {
initMap()
return
}
const point = res.devices.map((item: any) => {
return {
id: item.user_id,
lng: item.jingdu,
lat: item.weidu,
isWork: true,
}
})
// 数组合并
points.value = [...JSON.parse(JSON.stringify(points.value)), ...point]
console.log('🚀 ~ getWorkData ~ points.value:', points.value)
initMap()
}
}
// 获取工牌详情
const getWorkCardDetails = async (id: any) => {
try {
await getBadgeInfoApi(id)
} catch (res: any) {
console.log('🚀 ~ getWorkCardDetails ~ res:', res)
if (res.errorCode != 200) {
return
}
mapWorkCardData.value = res.data[0]
}
}
// 获取公司名称
const getCompanyListData = async () => {
const res: any = await getCompanyListApi()
const result: any = await getGoodsClassListApi()
// 过滤掉 isShow 为 false 的数据
companyList.value = res.data.filter((item: any) => item.isShow)
// console.log('🚀 ~ getCompanyListData ~ companyList.value:', companyList.value)
classList.value = result.data
// console.log('res公司名称', res)
}
getCompanyListData()
// 点击跳转装备共享大厅
const onSharedHall = (level: number, typeId: any, name: any) => {
router.push({
name: 'equipList',
query: {
level,
typeId,
name,
},
})
}
const onSharedHallByCompany = (companyId: any, name: any) => {
router.push({
name: 'equipList',
query: {
companyId,
name,
},
})
}
const handlerGoodsDetails = (...arg: any) => {
const arr = arg.map((key: any, index: number) => {
return {
level: index + 1 + '',
typeId: key.id,
typeName: key.name,
}
})
router.push({
name: 'equipList',
state: { typeTag: arr },
})
}
const hotDeviceList: any = ref([])
/* 获取热搜装备 */
const getHotDeviceList = async () => {
const res: any = await getHotList({ pageSize: 3 })
hotDeviceList.value = res.data
}
/* 热搜卡片点击跳转至详情页 */
const onClick = (val: any) => {
router.push({
name: 'equipDetail',
query: {
id: val.id,
},
})
}
// 分类点击事件
const onSelectOptions = () => {
selectOptions.value = !selectOptions.value
}
// 分类选择事件
const onSelectItem = (type: number) => {
if (type === 1) {
selectOptionsValue.value = '分类筛选'
} else {
selectOptionsValue.value = '公司筛选'
}
selectOptions.value = false
}
const swiperList = ref([])
// 获取轮播图
const getSwiperListData = async () => {
const res: any = await getSwiperListApi()
swiperList.value = res.rows
// console.log(res, '轮播图信息')
}
const onClickSwiper = (item: any) => {
if (item.slideLink) {
const link = item.slideLink.startsWith('http')
? item.slideLink
: `https://${item.slideLink}`
window.open(link, '_blank')
} else {
router.push({ name: 'equipList' })
}
}
getSwiperListData()
const formatUtcTimeV2 = (utcTime: any, date: any) => {
if (!utcTime || !date) return '未知时间'
// 解析UTC时间和日期
const hours = parseInt(utcTime.substring(0, 2))
const minutes = parseInt(utcTime.substring(2, 4))
const seconds = parseInt(utcTime.substring(4, 6))
const day = parseInt(date.substring(0, 2))
const month = parseInt(date.substring(2, 4)) - 1 // 月份是0-11
const year = 2000 + parseInt(date.substring(4, 6)) // 假设是20xx年
// 创建UTC时间对象
const utcDate = new Date(Date.UTC(year, month, day, hours, minutes, seconds))
// 转换为北京时间 (UTC+8)
// const beijingOffset = 8 * 60 * 60 * 1000; // 8小时的毫秒数
const beijingTime = new Date(utcDate.getTime())
// 格式化输出
return `${beijingTime
.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
})
.replace(/\//g, '-')} (北京时间)`
}
// 定位状态类型定义
type PositionStatus = 'A' | 'V' | string
// GPS质量类型定义
type GpsQuality = '0' | '1' | '2' | string
// 模式指示器类型定义
type ModeIndicator = 'A' | 'D' | 'E' | 'N' | string
// 定位来源类型定义
type PositionSource = 'gnss' | 'lbs' | 'wifi' | string
// 假设type的映射关系如下根据实际业务调整
const typeMap = {
'2': '小型数据终端',
'3': '智能工牌',
}
// 获取type对应的名称
const getTypeName = (type: string) => {
// 如果有匹配的名称则返回,否则返回原始值(带提示)
return typeMap[type as keyof typeof typeMap] || `未知类型(${type})`
}
/**
* 解析定位状态文本
* @param status 定位状态编码
* @returns 定位状态中文描述
*/
const getStatusText = (status: PositionStatus): string => {
const statusMap: Record<PositionStatus, string> = {
'A': '有效定位',
'V': '无效定位',
}
return statusMap[status] || (status || '-')
}
/**
* 解析GPS质量文本
* @param quality GPS质量编码
* @returns GPS质量中文描述
*/
const getQualityText = (quality: GpsQuality): string => {
const qualityMap: Record<GpsQuality, string> = {
'0': '无效',
'1': 'GPS定位',
'2': '差分GPS定位',
}
return qualityMap[quality] || (quality || '-')
}
// 检查是否有电力数据
const hasPowerData = computed(() => {
return !!mapData.value.aphase || !!mapData.value.bphase || !!mapData.value.cphase
})
/**
* 解析模式指示器文本
* @param mode 模式编码
* @returns 模式中文描述
*/
const getModeText = (mode: ModeIndicator): string => {
const modeMap: Record<ModeIndicator, string> = {
'A': '自主模式',
'D': '差分模式',
'E': '估算模式',
'N': '数据无效',
}
return modeMap[mode] || (mode || '-')
}
/**
* 解析定位来源文本
* @param source 定位来源编码
* @returns 定位来源中文描述
*/
const getPositionSourceText = (source: PositionSource): string => {
const sourceMap: Record<PositionSource, string> = {
'gnss': 'GNSS定位',
'lbs': '基站定位',
'wifi': 'WiFi定位',
}
return sourceMap[source] || (source || '-')
}
const initMap = () => {
if (window.BMap) {
const map = new BMap.Map(mapContainer.value)
const point = new BMap.Point(106.674974, 26.489328) // 默认贵州贵阳
// 添加标记点
points.value.forEach((item: any) => {
const point = new BMap.Point(item.lng, item.lat)
let icon = null
if (item.item.type == '3') {
icon = new BMap.Icon(icon1, new BMap.Size(30, 30), {
imageSize: new BMap.Size(30, 30),
})
} else {
icon = new BMap.Icon(icon2, new BMap.Size(30, 30), {
imageSize: new BMap.Size(30, 30),
})
}
const marker = icon ? new BMap.Marker(point, { icon }) : new BMap.Marker(point)
map.addOverlay(marker)
// const label = new BMap.Label(item.name, { offset: new BMap.Size(20, -10) })
// marker.setLabel(label) // 设置标记点名称
marker.addEventListener('click', () => {
// 点击标记点事件
console.log('点击了标记点', item)
if (item.item.type == '3') {
//getWorkCardDetails(item.id)
mapWorkCard.value = true
mapWorkCardData.value = item.item
} else {
// 打开详情弹框 - 目前没有
mapDialog.value = true
mapData.value = item.item
tagData.value = mapData.value.aphase
tagIndex.value = 1
timer.value = setInterval(() => {
loginApi()
}, 180000)
}
})
})
map.addControl(new BMap.NavigationControl()) // 添加平移缩放控件
map.centerAndZoom(point, 11) // 设置地图中心点及缩放级别
map.enableScrollWheelZoom(true) // 启用滚轮缩放
// 将贵阳整个地图放大到级别 7
} else {
console.error('BMap 未加载')
}
}
const handleTag = (tag: number) => {
console.log('tag', tag)
tagIndex.value = tag
if (tag == 1) {
tagData.value = mapData.value.aphase
} else if (tag == 2) {
tagData.value = mapData.value.bphase
} else {
tagData.value = mapData.value.cphase
}
console.log('🚀 ~ handleTag ~ tagData.value:', tagData.value)
}
onMounted(async () => {
loginApi()
if (!tokenNew) {
const origin = window.location.href
console.log(origin.split('ticket=')[1], 'origin')
if (origin.indexOf('ticket') != -1) {
// console.log('origin.split爱玩送ticket')
const res: any = await loginNewApi({
ticket: origin.split('ticket=')[1].split('#/')[0],
sysType: 0,
})
store.setToken(res.data.access_token)
localStorage.setItem('tokenNew', res.data.access_token)
const result: any = await getUserInfoAPI()
store.setUserInfo(result.user)
const roles = result.roles
const isAdmin = roles.some((e: any) => e == 'admin')
if (isAdmin) {
localStorage.setItem('rolesType', '3')
} else {
localStorage.setItem('rolesType', '1')
}
userStore.editcurrentMenuItem('goodsManagement')
// 跳转登录页面
}
}
})
</script>
<template>
<div class="home-index-banner">
<div class="home-index">
<!-- 商品菜单导航以及轮播图区域 -->
<div class="home-goods">
<ul class="left-nav">
<!-- 左侧机械名称菜单按钮 -->
<li class="left-filter" @click="onSelectOptions">
<div>
{{ selectOptionsValue }}
<el-icon style="margin-left: 10px">
<ArrowDownBold />
</el-icon>
</div>
<div class="select-options" v-if="selectOptions">
<div @click.stop="onSelectItem(1)">分类筛选</div>
<div @click.stop="onSelectItem(2)">公司筛选</div>
</div>
</li>
<template v-if="selectOptionsValue === '分类筛选'">
<div v-for="item in classList" :key="item.name" class="item-container">
<li class="item-nav" @click="onSharedHall(1, item.id, item.name)">
{{ item.name }}
<ul class="sub-goods">
<!-- 级联框内 类别名称 -->
<li
v-for="child in item.children"
:key="child.id"
@click.stop="onSharedHall(2, child.id, child.name)"
>
<!-- 第二级 -->
<span class="second-name">
{{ child.name }}
</span>
<span style="display: flex; flex: 1; flex-wrap: wrap">
<a
v-for="son in child.children"
:key="son.id"
style="font-size: 14px; font-weight: normal"
@click.stop="onSharedHall(3, son.id, son.name)"
>
{{ son.name }} ( {{ son.maCount }} )
</a>
</span>
</li>
</ul>
</li>
</div>
</template>
<template v-else>
<div
v-for="item in companyList"
:key="item.companyId"
class="item-container"
>
<li
class="item-nav"
@click="onSharedHallByCompany(item.companyId, item.companyName)"
>
{{ item.companyName }}
{{ item.maCount ? `(${item.maCount})` : '(0)' }}
</li>
</div>
</template>
</ul>
<div class="right-content">
<NavMenu />
<!-- 地图 -->
<div class="swiper-img">
<div ref="mapContainer" style="width: 100%; height: 100%"></div>
</div>
</div>
</div>
<!-- 热搜装备 -->
<div class="hot-equip-container" v-if="false">
<div class="hot-equip">
<span>最新装备</span>
<a
@click="
() => {
router.push({ name: 'equipList' })
}
"
style="
color: #00377a;
font-weight: bold;
text-decoration: underline;
font-size: 16px;
letter-spacing: 1px;
"
>更多产品</a
>
</div>
<div v-for="item in hotDeviceList" :key="item.typeName" style="margin-top: 15px">
<div class="hot-title">
{{ item.typeName }}
</div>
<ul class="equip-pic">
<li v-for="g in item.devInfoList" :key="g.maId" style="cursor: pointer">
<EquipCardNew
@onClick="onClick"
:id="g.maId"
:companyId="g.companyId"
:company="g.companyName"
:operateAddress="g.operateAddress"
:name="g.deviceName"
:typeName="g.typeName"
:price="g.dayLeasePrice"
:url="g.picUrl"
/>
</li>
</ul>
</div>
</div>
</div>
</div>
<el-dialog
v-model="mapDialog"
title="IOT设备信息详情"
width="70%"
:close-on-click-modal="false"
:show-close="true"
custom-class="iot-fullscreen-dialog"
>
<div class="iot-data-container">
<!-- 1.1 设备基本信息分区 -->
<div class="data-section">
<h3 class="section-heading">一、设备基础信息 <span class="item-value">{{ mapData.uuid || '-' }}</span></h3>
<el-row :gutter="30" class="section-content">
<el-col :span="8">
<div class="data-item">
<span class="item-label">设备类型</span>
<span class="item-value">{{ getTypeName(mapData.type) || '-' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">最后更新时间</span>
<span class="item-value">{{ formatUtcTimeV2(mapData.utcTime, mapData.date) || '-' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">定位状态</span>
<span class="item-value">{{ getStatusText(mapData.status) || '-' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">电池电量</span>
<span class="item-value">
{{ mapData.soc ? `${Number(mapData.soc).toFixed(2)}%` : '-' }}
</span>
</div>
</el-col>
</el-row>
</div>
<!-- 1.2 环境数据分区 -->
<div class="data-section">
<h3 class="section-heading">二、环境数据</h3>
<el-row :gutter="30" class="section-content">
<el-col :span="8">
<div class="data-item">
<span class="item-label">温度</span>
<span class="item-value">
{{ mapData.temperature ? `${mapData.temperature}℃` : '-' }}
</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">湿度</span>
<span class="item-value">
{{ mapData.humidity ? `${mapData.humidity}%` : '-' }}
</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">定位来源</span>
<span class="item-value">{{ getPositionSourceText(mapData.positionSource) || '-' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">定位精度</span>
<span class="item-value">
{{ mapData.accuracy ? `${mapData.accuracy}米` : '-' }}
</span>
</div>
</el-col>
</el-row>
</div>
<!-- 1.3 位置信息分区 -->
<div class="data-section">
<h3 class="section-heading">三、位置信息</h3>
<el-row :gutter="30" class="section-content">
<el-col :span="8">
<div class="data-item">
<span class="item-label">经度</span>
<span class="item-value">
{{ !isNaN(Number(mapData.longitude)) ? `${mapData.longitude} ${mapData.lonDirection || 'E'}` : '-' }}
</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">纬度</span>
<span class="item-value">
{{ !isNaN(Number(mapData.latitude)) ? `${mapData.latitude} ${mapData.latDirection || 'N'}` : '-' }}
</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">速度</span>
<span class="item-value">
{{ mapData.speedOverGround ? `${mapData.speedOverGround}节` : '-' }}
</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">航向</span>
<span class="item-value">
{{ mapData.courseOverGround ? `${mapData.courseOverGround}°` : '-' }}
</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">海拔</span>
<span class="item-value">
{{ mapData.altitude ? `${mapData.altitude}米` : '-' }}
</span>
</div>
</el-col>
</el-row>
</div>
<!-- 1.4 运动传感器数据分区 -->
<div class="data-section">
<h3 class="section-heading">四、运动传感器数据</h3>
<el-row :gutter="30" class="section-content">
<el-col :span="6">
<div class="data-item">
<span class="item-label">X轴加速度</span>
<span class="item-value">
{{ mapData.accX ? `${Number(mapData.accX).toFixed(2)} m/s²` : '-' }}
</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">Y轴加速度</span>
<span class="item-value">
{{ mapData.accY ? `${Number(mapData.accY).toFixed(2)} m/s²` : '-' }}
</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">Z轴加速度</span>
<span class="item-value">
{{ mapData.accZ ? `${Number(mapData.accZ).toFixed(2)} m/s²` : '-' }}
</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">翻滚角</span>
<span class="item-value">
{{ mapData.roll ? `${Number(mapData.roll).toFixed(2)}°` : '-' }}
</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">X轴角速度</span>
<span class="item-value">
{{ mapData.gyroX ? `${Number(mapData.gyroX).toFixed(2)} rad/s` : '-' }}
</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">Y轴角速度</span>
<span class="item-value">
{{ mapData.gyroY ? `${Number(mapData.gyroY).toFixed(2)} rad/s` : '-' }}
</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">Z轴角速度</span>
<span class="item-value">
{{ mapData.gyroZ ? `${Number(mapData.gyroZ).toFixed(2)} rad/s` : '-' }}
</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">俯仰角</span>
<span class="item-value">
{{ mapData.pitch ? `${Number(mapData.pitch).toFixed(2)}°` : '-' }}
</span>
</div>
</el-col>
</el-row>
</div>
<!-- 1.5 定位质量信息分区 -->
<div class="data-section">
<h3 class="section-heading">五、定位质量信息</h3>
<el-row :gutter="30" class="section-content">
<el-col :span="8">
<div class="data-item">
<span class="item-label">定位质量</span>
<span class="item-value">{{ getQualityText(mapData.quality) || '-' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">模式指示器</span>
<span class="item-value">{{ getModeText(mapData.modeIndicator) || '-' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">导航状态</span>
<span class="item-value">{{ mapData.navStatus || '-' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">使用卫星数</span>
<span class="item-value">{{ mapData.numSatellitesUsed || '-' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">水平精度因子</span>
<span class="item-value">{{ mapData.hdop || '-' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">GNRMC校验和</span>
<span class="item-value">{{ mapData.checksumRMC || '-' }}</span>
</div>
</el-col>
</el-row>
</div>
<!-- 1.6 电力数据分区(条件显示) -->
<div class="data-section" v-show="hasPowerData">
<h3 class="section-heading">六、电力数据</h3>
<el-row :gutter="30" class="section-content">
<el-col :span="24">
<div class="phase-switch">
<el-button
v-show="mapData.aphase"
:type="tagIndex === 1 ? 'primary' : 'default'"
@click="handleTag(1)"
size="small"
>
A相
</el-button>
<el-button
v-show="mapData.bphase"
:type="tagIndex === 2 ? 'primary' : 'default'"
@click="handleTag(2)"
size="small"
>
B相
</el-button>
<el-button
v-show="mapData.cphase"
:type="tagIndex === 3 ? 'primary' : 'default'"
@click="handleTag(3)"
size="small"
>
C相
</el-button>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">电压</span>
<span class="item-value">{{ tagData?.voltage ? `${Number(tagData.voltage).toFixed(2)} V` : '-' }}</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">电流</span>
<span class="item-value">{{ tagData?.current ? `${Number(tagData.current).toFixed(2)} A` : '-' }}</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">有功功率</span>
<span class="item-value">{{ tagData?.activePower ? `${Number(tagData.activePower).toFixed(2)} W` : '-' }}</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">无功功率</span>
<span class="item-value">{{ tagData?.reactivePower ? `${Number(tagData.reactivePower).toFixed(2)} VAR` : '-' }}</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">功率因素</span>
<span class="item-value">{{ tagData?.powerFactor ? `${Number(tagData.powerFactor).toFixed(2)}` : '-' }}</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">频率</span>
<span class="item-value">{{ tagData?.frequency ? `${Number(tagData.frequency).toFixed(2)} Hz` : '-' }}</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">正向有功</span>
<span class="item-value">{{ tagData?.forwardActiveEnergy ? `${Number(tagData.forwardActiveEnergy).toFixed(2)} kWh` : '-' }}</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">正向无功</span>
<span class="item-value">{{ tagData?.forwardReactiveEnergy ? `${Number(tagData.forwardReactiveEnergy).toFixed(2)} kvarh` : '-' }}</span>
</div>
</el-col>
</el-row>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="mapDialog = false">关闭弹窗</el-button>
</div>
</template>
</el-dialog>
<!-- &lt;!&ndash; 工牌信息弹框 &ndash;&gt;-->
<!-- <el-dialog v-model="mapWorkCard" title="工牌信息" width="50%">-->
<!-- <el-row :gutter="20" class="work-card">-->
<!-- <el-col :span="12" :offset="0">设备名称: {{ mapWorkCardData.user_name }}</el-col>-->
<!-- <el-col :span="12" :offset="0">最近定位时间: {{ mapWorkCardData.sys_time }}</el-col>-->
<!-- <el-col :span="12" :offset="0">最近位置更新时间: {{ mapWorkCardData.datetime }}</el-col>-->
<!-- <el-col :span="12" :offset="0">最近信号时间: {{ mapWorkCardData.heart_time }}</el-col>-->
<!-- <el-col :span="12" :offset="0">超速设置值: {{ mapWorkCardData.sudu }}</el-col>-->
<!-- <el-col :span="12" :offset="0">状态: {{ mapWorkCardData.status }}</el-col>-->
<!-- <el-col :span="12" :offset="0">激活时间: {{ mapWorkCardData.use_time }}</el-col>-->
<!-- <el-col :span="12" :offset="0">电话: {{ mapWorkCardData.tel }}</el-col>-->
<!-- <el-col :span="12" :offset="0">车牌号: {{ mapWorkCardData.sex }}</el-col>-->
<!-- <el-col :span="12" :offset="0">设备号: {{ mapWorkCardData.sim_id }}</el-col>-->
<!-- <el-col :span="12" :offset="0">手机号码: {{ mapWorkCardData.phone }}</el-col>-->
<!-- <el-col :span="12" :offset="0">设备ID: {{ mapWorkCardData.user_id }}</el-col>-->
<!-- <el-col :span="12" :offset="0">型号: {{ mapWorkCardData.product_type }}</el-col>-->
<!-- <el-col :span="12" :offset="0">图标序号: {{ mapWorkCardData.iconType }}</el-col>-->
<!-- <el-col :span="12" :offset="0">用户到期时间: {{ mapWorkCardData.out_time }}</el-col>-->
<!-- <el-col :span="12" :offset="0">经度: {{ mapWorkCardData.jingdu }}</el-col>-->
<!-- <el-col :span="12" :offset="0">iccid: {{ mapWorkCardData.su }}</el-col>-->
<!-- <el-col :span="12" :offset="0">联系人: {{ mapWorkCardData.owner }}</el-col>-->
<!-- <el-col :span="12" :offset="0">经纬度: {{ mapWorkCardData.jingwei }}</el-col>-->
<!-- <el-col :span="12" :offset="0"-->
<!-- >离线报警开关: {{ mapWorkCardData.alarm != 0 ? '开' : '关' }}-->
<!-- </el-col-->
<!-- >-->
<!-- <el-col :span="12" :offset="0">服务商描述: {{ mapWorkCardData.deviceRemark }}</el-col>-->
<!-- <el-col :span="12" :offset="0">设备软件版本号: {{ mapWorkCardData.macVersion }}</el-col>-->
<!-- <el-col :span="12" :offset="0">视频地址: {{ mapWorkCardData.VideoConfig }}</el-col>-->
<!-- <el-col :span="12" :offset="0">高温报警值: {{ mapWorkCardData.HighTempAlarm }}</el-col>-->
<!-- <el-col :span="12" :offset="0">低温报警值: {{ mapWorkCardData.LowTempAlarm }}</el-col>-->
<!-- <el-col :span="12" :offset="0">厂商编码: {{ mapWorkCardData.VendorCode }}</el-col>-->
<!-- <el-col :span="12" :offset="0">业主ID: {{ mapWorkCardData.OwnerId }}</el-col>-->
<!-- <el-col :span="12" :offset="0">终端类型: {{ mapWorkCardData.TerminalType }}</el-col>-->
<!-- <el-col :span="12" :offset="0">设备编码: {{ mapWorkCardData.DeviceCode }}</el-col>-->
<!-- <el-col :span="12" :offset="0">备注: {{ mapWorkCardData.remark }}</el-col>-->
<!-- </el-row>-->
<!-- </el-dialog>-->
<el-dialog
v-model="mapWorkCard"
title="工牌"
:close-on-click-modal="false"
:show-close="true"
custom-class="iot-fullscreen-dialog"
width="70%"
>
<!-- 弹窗内容区域:分类展示数据 -->
<div class="iot-data-container">
<!-- 1. 设备基础信息区 -->
<div class="data-section">
<h3 class="section-heading">一、设备基础信息<span class="item-value">{{ mapWorkCardData.uuid || '-' }}</span></h3>
<el-row :gutter="30" class="section-content">
<el-col :span="8">
<div class="data-item">
<span class="item-label">设备类型</span>
<span class="item-value">
{{ mapWorkCardData.type ? getTypeName(mapWorkCardData.type) : '-' }}
</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">最后更新时间</span>
<span
class="item-value">{{ formatUtcTimeV2(mapWorkCardData.utcTime, mapWorkCardData.date) || '-'
}}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">定位来源</span>
<span class="item-value">{{ getPositionSourceText(mapWorkCardData.positionSource) }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">电池电量</span>
<span class="item-value">
{{ mapWorkCardData.soc ? `${Number(mapWorkCardData.soc).toFixed(2)}%` : '-' }}
</span></div>
</el-col>
</el-row>
</div>
<!-- 2. 定位核心数据区 -->
<div class="data-section">
<h3 class="section-heading">二、定位核心数据</h3>
<el-row :gutter="30" class="section-content">
<el-col :span="8">
<div class="data-item">
<span class="item-label">定位状态</span>
<span class="item-value">{{ getStatusText(mapWorkCardData.status) }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">纬度值</span>
<span class="item-value">{{ mapWorkCardData.latitude || '-' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">经度值</span>
<span class="item-value">{{ mapWorkCardData.longitude || '-' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">定位精度</span>
<span class="item-value">{{ mapWorkCardData.accuracy ? `${mapWorkCardData.accuracy}米` : '-'
}}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">GPS质量指示</span>
<span class="item-value">{{ getQualityText(mapWorkCardData.quality) }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">使用卫星数量</span>
<span class="item-value">{{ mapWorkCardData.numSatellitesUsed || '-' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">水平精度因子HDOP</span>
<span class="item-value">{{ mapWorkCardData.hdop || '-' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">模式指示器</span>
<span class="item-value">{{ getModeText(mapWorkCardData.modeIndicator) }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">导航状态</span>
<span class="item-value">{{ mapWorkCardData.navStatus || '-' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="data-item">
<span class="item-label">地面速率/航向</span>
<span class="item-value">
{{ mapWorkCardData.speedOverGround ? `${mapWorkCardData.speedOverGround}节` : '无数据' }} /
{{ mapWorkCardData.courseOverGround ? `${mapWorkCardData.courseOverGround}°` : '无数据' }}
</span>
</div>
</el-col>
</el-row>
</div>
<!-- 3. 传感器数据区 -->
<div class="data-section">
<h3 class="section-heading">三、传感器采集数据</h3>
<el-row :gutter="30" class="section-content">
<el-col :span="6">
<div class="data-item">
<span class="item-label">X轴加速度</span>
<span
class="item-value">{{ mapWorkCardData.accX ? `${Number(mapWorkCardData.accX).toFixed(2)} m/s²` : '-'
}}</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">Y轴加速度</span>
<span
class="item-value">{{ mapWorkCardData.accY ? `${Number(mapWorkCardData.accY).toFixed(2)} m/s²` : '-'
}}</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">Z轴加速度</span>
<span
class="item-value">{{ mapWorkCardData.accZ ? `${Number(mapWorkCardData.accZ).toFixed(2)} m/s²` : '-'
}}</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">翻滚角</span>
<span
class="item-value">{{ mapWorkCardData.roll ? `${Number(mapWorkCardData.roll).toFixed(2)}°` : '-'
}}</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">X轴角速度</span>
<span
class="item-value">{{ mapWorkCardData.gyroX ? `${Number(mapWorkCardData.gyroX).toFixed(2)} rad/s` : '-'
}}</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">Y轴角速度</span>
<span
class="item-value">{{ mapWorkCardData.gyroY ? `${Number(mapWorkCardData.gyroY).toFixed(2)} rad/s` : '-'
}}</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">Z轴角速度</span>
<span
class="item-value">{{ mapWorkCardData.gyroZ ? `${Number(mapWorkCardData.gyroZ).toFixed(2)} rad/s` : '-'
}}</span>
</div>
</el-col>
<el-col :span="6">
<div class="data-item">
<span class="item-label">俯仰角</span>
<span
class="item-value">{{ mapWorkCardData.pitch ? `${Number(mapWorkCardData.pitch).toFixed(2)}°` : '-'
}}</span>
</div>
</el-col>
</el-row>
</div>
</div>
</el-dialog>
</template>
<style lang="scss" scoped>
.work-card {
.el-col {
margin-bottom: 10px;
color: #333;
line-height: 1.5;
}
}
.card-item {
margin-bottom: 15px;
text-align: left;
.item {
margin-bottom: 15px;
}
}
.card-title {
font-weight: bold;
color: #333;
}
:deep(.el-carousel__container) {
.el-carousel__item {
.el-image {
height: 100%;
img {
}
}
}
}
.home-index-banner {
background-color: #fff;
}
.home-index {
.home-goods {
height: 700px;
display: flex;
position: relative;
.left-nav {
width: 270px;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
background-color: #f7f9fa;
overflow: hidden;
overflow-y: auto;
border-radius: 16px;
.left-filter {
margin-top: 10px;
padding: 16px 0;
position: relative;
display: flex;
align-content: center;
justify-content: center;
color: #00377a;
font-size: 22px;
// height: 46px;
// line-height: 46px;
// text-align: center;
font-weight: bold;
cursor: pointer;
width: 100%;
.select-options {
position: absolute;
bottom: 0;
left: 0;
transform: translate(50%, 100%);
// left: 50%;
// bottom: -65px;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
// transform: translateX(-50%);
background-color: #fff;
div {
padding: 10px 30px;
text-align: left;
// font-size: 14px;
font-size: 16px;
font-weight: normal;
cursor: pointer;
color: #333;
}
div:hover {
color: #fff;
background-color: #00377a;
}
}
}
.item-container {
width: 100%;
text-align: center;
.item-nav {
// text-align: left;
// padding-left: 50px;
display: inline-block;
margin-top: 10px;
// padding: 0 10px;
color: #000;
min-height: 32px;
line-height: 32px;
text-align: center;
padding: 2px 20px;
// font-size: 16px !important;
&:hover {
cursor: pointer;
// color: #2282ff;
// font-weight: bold;
background-color: #00377a;
border-radius: 18px;
color: #fff;
}
}
.sub-goods {
position: absolute;
display: none;
top: 0;
left: 270px;
width: 1242px;
min-height: 100%;
max-height: 100%;
background-color: #fff;
z-index: 999;
// opacity: 0.9;
border: 1px solid #eee;
overflow-y: auto;
box-sizing: border-box;
li {
// margin: 10px 0;
padding: 10px 80px;
color: #333;
font-weight: bold;
display: flex;
align-items: center;
// background: orange;
.second-name {
// width: 160px;
margin-left: 10px;
}
span a {
margin: 0 30px;
font-size: 16px;
font-weight: normal;
color: #333;
&:hover {
color: #00377a;
border-bottom: 1px solid #00377a !important;
}
}
.last-level {
margin-left: 3px;
}
.last-level:hover {
color: #00377a;
border-bottom: 1px solid #00377a !important;
}
}
}
}
.item-container:hover {
.sub-goods {
display: block !important;
z-index: 9999;
}
}
}
.right-content {
box-sizing: border-box;
flex: 1;
height: 100%;
margin-left: 20px;
display: flex;
flex-direction: column;
.swiper-img {
margin-top: 20px;
flex: 1;
border-radius: 8px;
}
}
}
.hot-equip {
margin-top: 30px;
height: 37px;
display: flex;
align-items: center;
justify-content: space-between;
span {
background-color: #00377a;
padding: 10px 18px;
color: #fff;
}
a {
color: rgba(24, 103, 221, 0.8);
font-size: 14px;
cursor: pointer;
}
}
.hot-title {
padding: 15px 0 10px 20px;
font-size: 16px;
font-weight: bold;
letter-spacing: 1px;
}
.equip-pic {
display: flex;
flex-wrap: wrap;
li {
width: calc((100% - 100px) / 4);
margin: 8px 0 8px 20px;
&:nth-child(4n) {
margin-right: 20px;
}
}
}
.consult-nav {
width: 100%;
height: 40px;
border-bottom: 1px solid #e0e0e0;
display: flex;
li {
height: 40px;
line-height: 40px;
margin: 0 15px;
&:hover {
border-bottom: 1px solid #00377a;
cursor: pointer;
}
}
}
.consult-content {
margin-top: 20px;
height: 210px;
display: flex;
align-items: center;
.left-bg {
background: url(../../assets/img/home/2023_12_01_beijing2/left_bg.png) no-repeat;
background-size: cover;
width: 340px;
height: 210px;
}
.right-consult {
height: 210px;
flex: 1;
width: calc(100% - 340px);
// padding-left: 35px;
overflow-y: auto;
.consult-box {
margin-bottom: 10px;
//height: 70px;
padding-left: 15px;
cursor: pointer;
.consult-title {
height: 30px;
display: flex;
justify-content: space-between;
align-items: center;
h2 {
font-weight: bold;
}
span {
color: #827d7d;
font-size: 14px;
}
}
.consult-info {
width: calc(100% - 100px);
height: 10px;
line-height: 40px;
border-bottom: 1px dashed #979797;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
}
}
:deep(.el-carousel__container) {
height: 100%;
}
.el-carousel--horizontal {
border-radius: 14px;
}
/* 全屏弹窗基础样式 */
/* 数据分区样式 */
.data-section {
margin-bottom: 25px;
padding: 16px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
/* 分区标题样式 */
.section-heading {
margin-bottom: 15px;
padding-left: 12px;
font-size: 16px;
font-weight: 700;
color: #1890ff;
border-left: 3px solid #1890ff;
}
/* 分区内容样式 */
.section-content {
padding: 10px 0;
}
/* 数据项样式 */
.data-item {
padding: 12px 8px;
border-bottom: 1px dashed #f0f0f0;
}
.data-item:last-child {
border-bottom: none;
}
/* 数据项标签样式 */
.item-label {
display: inline-block;
width: 45%;
font-size: 14px;
color: #6b7280;
}
/* 数据项值样式 */
.item-value {
font-size: 14px;
color: #1f2329;
font-weight: 500;
}
/* 未启用功能项样式 */
.disabled-item {
padding: 8px 0;
font-size: 14px;
color: #86909c;
}
/* 底部按钮区样式 */
.dialog-footer {
text-align: right;
padding: 10px 35px 20px;
background-color: #fff;
border-top: 1px solid #f0f0f0;
}
/* 滚动条优化 */
.iot-data-container::-webkit-scrollbar {
width: 8px;
}
.iot-data-container::-webkit-scrollbar-track {
background-color: #f1f1f1;
border-radius: 4px;
}
</style>