Browse Source

优化类型

master
xh 1 week ago
parent
commit
708e1aa578
  1. 2
      web/.env.prod
  2. 1
      web/README.md
  3. 24
      web/build/vite/index.ts
  4. 9
      web/src/api/gas/handdetector/index.ts
  5. 214
      web/src/views/HandDevice/Home/components/OpenLayerMap.vue
  6. 16
      web/src/views/HandDevice/Home/components/types/map.types.ts
  7. 14
      web/src/views/HandDevice/Home/components/utils/map.utils.ts
  8. 19
      web/src/views/HandDevice/Home/index.vue
  9. 8
      web/src/views/gas/fencealarm/index.vue

2
web/.env.prod

@ -3,7 +3,7 @@ NODE_ENV=production
VITE_DEV=false
# 请求路径
VITE_BASE_URL='https://mobile.zdhlcn.com'
VITE_BASE_URL='http://mobile.icpcdev.site'
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务
VITE_UPLOAD_TYPE=server

1
web/README.md

@ -0,0 +1 @@
sudo unzip -o /home/zdhlroot/roadmap.zip -d /opt/website/mobile.zdhlcn.com/roadmap/

24
web/build/vite/index.ts

@ -66,10 +66,10 @@ export function createVitePlugins() {
resolvers: [ElementPlusResolver()],
globs: ["src/components/**/**.{vue, md}", '!src/components/DiyEditor/components/mobile/**']
}),
EslintPlugin({
cache: false,
include: ['src/**/*.vue', 'src/**/*.ts', 'src/**/*.tsx'] // 检查的文件
}),
// EslintPlugin({
// cache: false,
// include: ['src/**/*.vue', 'src/**/*.ts', 'src/**/*.tsx'] // 检查的文件
// }),
VueI18nPlugin({
runtimeOnly: true,
compositionOnly: true,
@ -79,14 +79,14 @@ export function createVitePlugins() {
iconDirs: [pathResolve('src/assets/svgs')],
symbolId: 'icon-[dir]-[name]',
}),
viteCompression({
verbose: true, // 是否在控制台输出压缩结果
disable: false, // 是否禁用
threshold: 10240, // 体积大于 threshold 才会被压缩,单位 b
algorithm: 'gzip', // 压缩算法,可选 [ 'gzip' , 'brotliCompress' ,'deflate' , 'deflateRaw']
ext: '.gz', // 生成的压缩包后缀
deleteOriginFile: false //压缩后是否删除源文件
}),
// viteCompression({
// verbose: true, // 是否在控制台输出压缩结果
// disable: false, // 是否禁用
// threshold: 10240, // 体积大于 threshold 才会被压缩,单位 b
// algorithm: 'gzip', // 压缩算法,可选 [ 'gzip' , 'brotliCompress' ,'deflate' , 'deflateRaw']
// ext: '.gz', // 生成的压缩包后缀
// deleteOriginFile: false //压缩后是否删除源文件
// }),
ViteEjsPlugin(),
topLevelAwait({
// https://juejin.cn/post/7152191742513512485

9
web/src/api/gas/handdetector/index.ts

@ -23,9 +23,16 @@ export interface HandDetector {
accuracy?: number // 数值除数
sortOrder?: number // 排序
remark?: string // 备注
}
// GAS手持探测器报警信息
export interface HandDetectorData extends HandDetector {
time?: number // 时间
value?: number // 数值
gasStatus?: number //气体报警状态
batteryStatus?: number //电池报警状态
fenceStatus?: number //电子围栏报警状态
onlineStatus?: number //在线状态
enableStatus?: number //启用状态
}
// GAS手持探测器 API

214
web/src/views/HandDevice/Home/components/OpenLayerMap.vue

@ -33,11 +33,15 @@
<div class="top-panel__center">
<div class="data_item">
<div class="data_item__title">手持设备</div>
<div class="data_item__value">2000<span class="data_item__unit"></span></div>
<div class="data_item__value"
>{{ handDetectorCount }}<span class="data_item__unit"></span></div
>
</div>
<div class="data_item">
<div class="data_item__title">在线数量</div>
<div class="data_item__value">200<span class="data_item__unit"></span></div>
<div class="data_item__value"
>{{ onlineCount }}<span class="data_item__unit"></span></div
>
</div>
<!-- <div class="data_item">
<div class="data_item__title">用户数量</div>
@ -123,6 +127,17 @@ const panelVisible = ref(false)
const selectedMarker = ref<MarkerData | null>(null)
const search = ref('')
/**
* gasStatus 气体报警状态
batteryStatus 电池报警状态
fenceStatus 电子围栏报警状态
onlineStatus 1在线 0离线
enableStatus 1启用 0未启用
*/
//
const handDetectorCount = computed(() => props.markers.length)
const onlineCount = computed(() => props.markers.filter((item) => item.onlineStatus === 1).length)
// 使
const {
services,
@ -290,11 +305,11 @@ onMounted(() => {
defineExpose({ refreshFences })
</script>
<style scoped lang="scss">
.map-container {
width: 100%;
height: 100%;
}
:deep(.ol-viewport) {
width: 100% !important;
@ -305,81 +320,6 @@ defineExpose({ refreshFences })
width: 100% !important;
height: 100% !important;
}
.info-panel {
position: absolute;
top: 100px;
right: 20px;
background-color: rgba(255, 255, 255, 0.9);
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
z-index: 1000;
width: 300px;
max-height: 80vh;
overflow-y: auto;
display: flex;
flex-direction: column;
}
.info-panel__header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 15px;
border-bottom: 1px solid #eee;
background-color: #f5f5f5;
border-radius: 8px 8px 0 0;
}
.info-panel__title {
font-size: 16px;
font-weight: bold;
color: #333;
}
.info-panel__close {
background-color: #ff4d4f;
color: white;
border: none;
border-radius: 50%;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 18px;
font-weight: bold;
transition: background-color 0.3s ease;
}
.info-panel__close:hover {
background-color: #d9363e;
}
.info-panel__body {
padding: 15px;
flex-grow: 1;
display: flex;
flex-direction: column;
}
.info-panel__empty {
text-align: center;
color: #888;
padding: 20px;
}
.info-panel__name {
font-size: 18px;
font-weight: bold;
margin-bottom: 5px;
color: #555;
}
.info-panel__coord {
font-size: 14px;
color: #666;
}
/* 顶部面板样式 */
@ -397,7 +337,6 @@ defineExpose({ refreshFences })
flex-wrap: wrap;
height: 100px;
box-sizing: border-box;
}
.top-panel__left {
flex: 0 0 260px;
@ -408,21 +347,22 @@ defineExpose({ refreshFences })
height: 100%;
display: flex;
align-items: center;
}
.search-group {
display: flex;
align-items: center;
gap: 8px;
padding: 8px;
}
.search-type {
flex: 0 0 120px;
}
.search-input {
width: 220px;
}
}
}
.top-panel__center {
flex: 1 1 auto;
@ -430,7 +370,6 @@ defineExpose({ refreshFences })
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 12px;
align-items: center;
}
.data_item {
background: rgba(255, 255, 255, 0.85);
@ -441,7 +380,6 @@ defineExpose({ refreshFences })
display: flex;
flex-direction: column;
justify-content: center;
}
.data_item__title {
font-size: 12px;
@ -453,13 +391,15 @@ defineExpose({ refreshFences })
font-weight: 600;
color: #303133;
margin-top: 4px;
}
.data_item__unit {
font-size: 12px;
color: #909399;
margin-left: 6px;
}
}
}
}
.top-panel__right {
display: flex;
@ -473,49 +413,141 @@ defineExpose({ refreshFences })
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
white-space: nowrap;
height: 100%;
}
.legend-title {
color: #606266;
}
.normal-legend,
.alarm1-legend,
.alarm2-legend {
.normal-legend {
padding: 4px 8px;
border-radius: 999px;
color: #fff;
font-size: 12px;
line-height: 1;
}
.normal-legend {
background: #67c23a;
}
.alarm1-legend {
padding: 4px 8px;
border-radius: 999px;
color: #fff;
font-size: 12px;
line-height: 1;
background: #e6a23c;
}
.alarm2-legend {
padding: 4px 8px;
border-radius: 999px;
color: #fff;
font-size: 12px;
line-height: 1;
background: #f56c6c;
}
}
}
@media (max-width: 992px) {
.top-panel {
.top-panel__left {
flex: 1 1 100%;
}
.top-panel__center {
flex: 1 1 100%;
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.top-panel__right {
flex: 1 1 100%;
justify-content: flex-start;
}
}
}
@media (max-width: 600px) {
.top-panel {
.top-panel__center {
grid-template-columns: 1fr;
}
}
}
.info-panel {
position: absolute;
top: 100px;
right: 20px;
background-color: rgba(255, 255, 255, 0.9);
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
z-index: 1000;
width: 300px;
max-height: 80vh;
overflow-y: auto;
display: flex;
flex-direction: column;
.info-panel__header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 15px;
border-bottom: 1px solid #eee;
background-color: #f5f5f5;
border-radius: 8px 8px 0 0;
.info-panel__title {
font-size: 16px;
font-weight: bold;
color: #333;
}
.info-panel__close {
background-color: #ff4d4f;
color: white;
border: none;
border-radius: 50%;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 18px;
font-weight: bold;
transition: background-color 0.3s ease;
&:hover {
background-color: #d9363e;
}
}
}
.info-panel__body {
padding: 15px;
flex-grow: 1;
display: flex;
flex-direction: column;
.info-panel__empty {
text-align: center;
color: #888;
padding: 20px;
}
.info-panel__name {
font-size: 18px;
font-weight: bold;
margin-bottom: 5px;
color: #555;
}
.info-panel__coord {
font-size: 14px;
color: #666;
}
}
}
</style>

16
web/src/views/HandDevice/Home/components/types/map.types.ts

@ -36,20 +36,22 @@ export interface MarkerData extends HandDetector {
/** 坐标 [经度, 纬度] */
coordinates: [number, number]
/** 气体状态 */
gasStatus?: MarkerStatus
gasStatus?: number
/** 电池状态 */
batteryStatus?: MarkerStatus
batteryStatus?: number
/** 围栏状态 */
fenceStatus?: MarkerStatus
fenceStatus?: number
/** 在线状态 */
onlineStatus?: MarkerStatus
onlineStatus?: number
/** 标记标题 */
name: string
/** 自定义数据 */
data?: any,
value?: number,
unit?: string,
data?: any
value?: number
unit?: string
time?: number
enableStatus?: number //启用状态
}
// 地图组件 Props 接口

14
web/src/views/HandDevice/Home/components/utils/map.utils.ts

@ -31,17 +31,17 @@ export const getHighestPriorityStatus = (markerData: MarkerData): keyof typeof S
const statuses: Array<keyof typeof STATUS_PRIORITY> = []
// 检查各种状态
const gasStatus = getStatusMapping('gas', markerData.gasStatus)
const batteryStatus = getStatusMapping('battery', markerData.batteryStatus)
const fenceStatus = getStatusMapping('fence', markerData.fenceStatus)
const onlineStatus = markerData.onlineStatus === '0' ? 'offline' : null
const gasStatus = getStatusMapping('gas', String(markerData.gasStatus))
const batteryStatus = getStatusMapping('battery', String(markerData.batteryStatus))
const fenceStatus = getStatusMapping('fence', String(markerData.fenceStatus))
const onlineStatus = String(markerData.onlineStatus) === '0' ? 'offline' : null
// 收集非正常状态
if (gasStatus && markerData.gasStatus !== '0')
if (gasStatus && markerData.gasStatus !== 0)
statuses.push(gasStatus as keyof typeof STATUS_PRIORITY)
if (batteryStatus && markerData.batteryStatus !== '0')
if (batteryStatus && markerData.batteryStatus !== 0)
statuses.push(batteryStatus as keyof typeof STATUS_PRIORITY)
if (fenceStatus && markerData.fenceStatus !== '0')
if (fenceStatus && markerData.fenceStatus !== 0)
statuses.push(fenceStatus as keyof typeof STATUS_PRIORITY)
if (onlineStatus) statuses.push(onlineStatus)

19
web/src/views/HandDevice/Home/index.vue

@ -4,18 +4,18 @@
<script lang="ts" setup>
import OpenLayerMap from './components/OpenLayerMap.vue'
import { getLastestDetectorData } from '@/api/gas'
import { HandDetector } from '@/api/gas/handdetector'
import { MarkerData } from './components/types/map.types'
import { HandDetectorData } from '@/api/gas/handdetector'
import { MarkerData,FenceData } from './components/types/map.types'
import { Fence } from '@/api/gas/fence'
import { FenceApi } from '@/api/gas/fence'
import dayjs from 'dayjs'
const getDataTimer = ref<NodeJS.Timeout | null>(null)
const markers = ref<MarkerData[]>([])
const fences = ref<Fence[]>([])
const fences = ref<FenceData[]>([])
const inited = ref(false)
const getMarkers = async () => {
console.log('getMarkers')
return await getLastestDetectorData().then((res: HandDetector[]) => {
return await getLastestDetectorData().then((res: HandDetectorData[]) => {
res = res.filter((i) => i.enableStatus === 1)
var res2 = res.map((i) => {
return {
@ -24,7 +24,12 @@ const getMarkers = async () => {
data: [],
time: i.time ? dayjs(i.time).format('YYYY-MM-DD HH:mm:ss') : '',
value: i.value,
unit: i.unit
unit: i.unit,
gasStatus: i.gasStatus, //
batteryStatus: i.batteryStatus, //
fenceStatus: i.fenceStatus, //
onlineStatus: i.onlineStatus, //线
enableStatus: i.enableStatus //
}
})
markers.value = res2 as unknown as any[]
@ -45,13 +50,13 @@ const getFences = async () => {
fenceRange: JSON.parse(i.fenceRange)
}
})
fences.value = fencesData as unknown as Fence[]
fences.value = fencesData as unknown as FenceData[]
})
}
onMounted(() => {
getMarkers()
getFences()
console.log('定时器,暂时关掉,太烦了');
console.log('定时器,暂时关掉,太烦了')
// getDataTimer.value = setInterval(() => {
// getMarkers()

8
web/src/views/gas/fencealarm/index.vue

@ -129,12 +129,13 @@
@selection-change="handleRowCheckboxChange"
>
<el-table-column type="selection" width="55" />
<el-table-column label="持有人" align="center" prop="name">
<el-table-column label="持有人" align="center" prop="sn">
<template #default="scope">
{{
{{ scope.row.sn }}
<!-- {{
handDetectorStore.getHandDetectorList.find((item) => item.id === scope.row.detectorId)
?.name
}}
}} -->
</template>
</el-table-column>
<!-- <el-table-column label="围栏" align="center" prop="fenceId">
@ -144,7 +145,6 @@
</el-table-column> -->
<el-table-column label="报警类型" align="center" prop="type">
<template #default="scope">
<!-- {{ handDetectorStore.getAlarmTypes }} -->
{{ handDetectorStore.getAlarmTypes.find((item) => item.level === scope.row.type)?.name }}
</template>
</el-table-column>

Loading…
Cancel
Save