refactor(superManagement): 重构超级后台首页地图展示功能

- 新增 MapVisionParams 类用于地图视野参数
- 移除 EnterprisesUnitController 中的 mapPoint 方法
- 新增 SuperIndexController、SuperIndexMapper 和 SuperIndexService
- 更新 SecurityUnitUseStatisticsDTO,添加省市区街道编码字段
- 优化 SignInterceptor 中的签名生成和验证逻辑
- 更新 OpenApiMapper.xml,移除冗余的删除标志条件
- 重构 MapContainer组件,移除初始化地图样式- 更新路由配置,移除数据总览菜单项
- 重命名 EnterprisesUnitInfoWindowContent 组件
- 重构数据总览页面,改为在首页展示地图信息
This commit is contained in:
luozhun 2024-11-21 14:16:22 +08:00
parent 5bb44b0dc2
commit 00c6b0409f
17 changed files with 217 additions and 151 deletions

View File

@ -0,0 +1,22 @@
package com.changhu.common.pojo.params;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.locationtech.jts.geom.Point;
/**
* @author 20252
* @createTime 2024/11/21 上午11:18
* @desc MapVisionParams...
*/
@Data
public class MapVisionParams {
@Schema(description = "左上角")
private Point upperLeft;
@Schema(description = "右上角")
private Point upperRight;
@Schema(description = "左下角")
private Point lowerLeft;
@Schema(description = "右下角")
private Point lowerRight;
}

View File

@ -6,7 +6,6 @@ import com.changhu.common.annotation.JsonBody;
import com.changhu.common.db.enums.UserType; import com.changhu.common.db.enums.UserType;
import com.changhu.common.exception.MessageException; import com.changhu.common.exception.MessageException;
import com.changhu.common.pojo.vo.SelectNodeVo; import com.changhu.common.pojo.vo.SelectNodeVo;
import com.changhu.module.management.pojo.entity.EnterprisesUnit;
import com.changhu.module.management.pojo.params.EnterprisesUnitSaveOrUpdateParams; import com.changhu.module.management.pojo.params.EnterprisesUnitSaveOrUpdateParams;
import com.changhu.module.management.pojo.queryParams.EnterprisesUnitPagerQueryParams; import com.changhu.module.management.pojo.queryParams.EnterprisesUnitPagerQueryParams;
import com.changhu.module.management.pojo.vo.EnterprisesUnitPagerVo; import com.changhu.module.management.pojo.vo.EnterprisesUnitPagerVo;
@ -64,10 +63,4 @@ public class EnterprisesUnitController {
return enterprisesUnitService.queryListByAdministrativeDivisionCodes(administrativeDivisionCodes); return enterprisesUnitService.queryListByAdministrativeDivisionCodes(administrativeDivisionCodes);
} }
@Operation(summary = "企事业单位地图点位")
@GetMapping("/mapPoint")
public List<EnterprisesUnit> mapPoint() {
return enterprisesUnitService.list();
}
} }

View File

@ -0,0 +1,34 @@
package com.changhu.module.superManagement.controller;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.changhu.common.annotation.JsonBody;
import com.changhu.module.management.pojo.entity.EnterprisesUnit;
import com.changhu.module.superManagement.service.SuperIndexService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
/**
* @author 20252
* @createTime 2024/11/21 上午11:31
* @desc SuperIndexController...
*/
@JsonBody
@Tag(name = "超级后台首页")
@RequestMapping("/super/index")
public class SuperIndexController {
@Autowired
private SuperIndexService superIndexService;
@Operation(summary = "企事业单位地图点位")
@GetMapping("/mapPoint")
public List<EnterprisesUnit> mapPoint() {
return Db.lambdaQuery(EnterprisesUnit.class).list();
}
}

View File

@ -0,0 +1,12 @@
package com.changhu.module.superManagement.mapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author 20252
* @createTime 2024/11/21 上午11:32
* @desc SuperIndexMapper...
*/
@Mapper
public interface SuperIndexMapper {
}

View File

@ -0,0 +1,9 @@
package com.changhu.module.superManagement.service;
/**
* @author 20252
* @createTime 2024/11/21 上午11:31
* @desc SuperIndexService...
*/
public interface SuperIndexService {
}

View File

@ -0,0 +1,13 @@
package com.changhu.module.superManagement.service.impl;
import com.changhu.module.superManagement.service.SuperIndexService;
import org.springframework.stereotype.Service;
/**
* @author 20252
* @createTime 2024/11/21 上午11:31
* @desc SuperIndexServiceImpl...
*/
@Service
public class SuperIndexServiceImpl implements SuperIndexService {
}

View File

@ -20,12 +20,20 @@ public class SecurityUnitUseStatisticsDTO {
private Long enterprisesUnitId; private Long enterprisesUnitId;
@Schema(description = "事业单位名称") @Schema(description = "事业单位名称")
private String enterprisesUnitName; private String enterprisesUnitName;
@Schema(description = "省编码")
private String province;
@Schema(description = "") @Schema(description = "")
private String provinceName; private String provinceName;
@Schema(description = "市编码")
private String city;
@Schema(description = "") @Schema(description = "")
private String cityName; private String cityName;
@Schema(description = "区/县编码")
private String districts;
@Schema(description = "区/县") @Schema(description = "区/县")
private String districtsName; private String districtsName;
@Schema(description = "街道编码")
private String street;
@Schema(description = "街道") @Schema(description = "街道")
private String streetName; private String streetName;
@Schema(description = "事业单位详细地址") @Schema(description = "事业单位详细地址")

View File

@ -4,7 +4,7 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil; import cn.hutool.core.util.URLUtil;
import cn.hutool.crypto.digest.MD5; import cn.hutool.crypto.digest.MD5;
import cn.hutool.http.HttpUtil; import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.TypeReference; import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.toolkit.Db; import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.changhu.common.db.enums.IsEnable; import com.changhu.common.db.enums.IsEnable;
import com.changhu.common.exception.MessageException; import com.changhu.common.exception.MessageException;
@ -67,7 +67,7 @@ public class SignInterceptor implements HandlerInterceptor {
.orElseThrow(() -> new MessageException("无效的accessKey")); .orElseThrow(() -> new MessageException("无效的accessKey"));
if (IsEnable.FALSE.equals(accessKeyEntity.getIsEnable())) { if (IsEnable.FALSE.equals(accessKeyEntity.getIsEnable())) {
throw new MessageException("无效的accessKey"); throw new MessageException("accessKey已禁用");
} }
if (accessKeyEntity.getEffectiveTime() > 0 && System.currentTimeMillis() - Long.parseLong(timestamp) > accessKeyEntity.getEffectiveTime()) { if (accessKeyEntity.getEffectiveTime() > 0 && System.currentTimeMillis() - Long.parseLong(timestamp) > accessKeyEntity.getEffectiveTime()) {
@ -80,20 +80,17 @@ public class SignInterceptor implements HandlerInterceptor {
} }
Map<String, Object> hashMap = new HashMap<>(); Map<String, Object> hashMap = new HashMap<>();
//添加请求url参数
Map<String, String> map = HttpUtil.decodeParamMap(request.getQueryString(), StandardCharsets.UTF_8);
if (!map.isEmpty()) {
hashMap.putAll(map);
}
hashMap.put(ACCESS_KEY, accessKey); hashMap.put(ACCESS_KEY, accessKey);
hashMap.put(TIMESTAMP, timestamp); hashMap.put(TIMESTAMP, timestamp);
//添加请求url参数
Optional.ofNullable(HttpUtil.decodeParamMap(request.getQueryString(), StandardCharsets.UTF_8))
.ifPresent(hashMap::putAll);
//添加body参数 //添加body参数
CustomHttpServletRequestWrapper c = (CustomHttpServletRequestWrapper) request; Optional.ofNullable(JSON.<Map<String, Object>>parseObject(((CustomHttpServletRequestWrapper) request).getBody(), Map.class))
Optional.ofNullable(new TypeReference<Map<String, Object>>() { .ifPresent(hashMap::putAll);
}.parseObject(c.getBody())).ifPresent(hashMap::putAll); //生成签名
String nowSign = generatedSign(hashMap, accessKeyEntity.getSecretKey()); String nowSign = generatedSign(hashMap, accessKeyEntity.getSecretKey());
//比对签名
if (!sign.equals(nowSign)) { if (!sign.equals(nowSign)) {
throw new MessageException("签名错误"); throw new MessageException("签名错误");
} }
@ -118,9 +115,4 @@ public class SignInterceptor implements HandlerInterceptor {
return MD5.create().digestHex(str).toUpperCase(); return MD5.create().digestHex(str).toUpperCase();
} }
public static void main(String[] args) {
String str1 = "Access-Key=w2wzi0wefmmo6s735z2el8tfzitya5gj&addr=%E6%B9%96%E5%8D%97%E7%9C%81%E9%95%BF%E6%B2%99%E5%B8%82&age=14&name=zhangsan&Time-Stamp=1732084303463&Secret-Key=db1b5214-02ee-497f-957c-88323b4351bf";
String str2 = "Access-Key=w2wzi0wefmmo6s735z2el8tfzitya5gj&addr=%E6%B9%96%E5%8D%97%E7%9C%81%E9%95%BF%E6%B2%99%E5%B8%82&age=14&name=zhangsan&Time-Stamp=1732084303463&Secret-Key=db1b5214-02ee-497f-957c-88323b4351bf";
}
} }

View File

@ -14,8 +14,8 @@
from ck_assessment_record car from ck_assessment_record car
left join enterprises_unit eu on car.enterprises_unit_id = eu.snow_flake_id and eu.delete_flag = 0 left join enterprises_unit eu on car.enterprises_unit_id = eu.snow_flake_id and eu.delete_flag = 0
left join ck_project cp on car.ck_project_id = cp.snow_flake_id and cp.delete_flag = 0 left join ck_project cp on car.ck_project_id = cp.snow_flake_id and cp.delete_flag = 0
left join mini_program_user mpu on mpu.identity = 'police' and car.create_by = mpu.snow_flake_id and mpu.delete_flag = 0 left join mini_program_user mpu on mpu.identity = 'police' and car.create_by = mpu.snow_flake_id
left join police_unit pu on mpu.unit_id = pu.snow_flake_id and pu.delete_flag = 0 left join police_unit pu on mpu.unit_id = pu.snow_flake_id
left join ck_assessment_record_details card on car.snow_flake_id = card.ck_assessment_record_id and card.delete_flag = 0 left join ck_assessment_record_details card on car.snow_flake_id = card.ck_assessment_record_id and card.delete_flag = 0
left join ck_standard cs on card.ck_standard_id = cs.snow_flake_id left join ck_standard cs on card.ck_standard_id = cs.snow_flake_id
where car.delete_flag = 0 where car.delete_flag = 0

View File

@ -47,6 +47,10 @@
select select
eu.snow_flake_id as 'enterprisesUnitId', eu.snow_flake_id as 'enterprisesUnitId',
eu.name as 'enterprisesUnitName', eu.name as 'enterprisesUnitName',
eu.province,
eu.city,
eu.districts,
eu.street,
ad1.name as 'provinceName', ad1.name as 'provinceName',
ad2.name as 'cityName', ad2.name as 'cityName',
ad3.name as 'districtsName', ad3.name as 'districtsName',

View File

@ -19,7 +19,6 @@ const props = withDefaults(defineProps<MapContainerProps>(), {
viewMode: "3D", viewMode: "3D",
// //
zoom: 11, zoom: 11,
mapStyle: 'amap://styles/darkblue'
} }
} }
}) })

View File

@ -52,13 +52,6 @@ export const SYSTEM_MENUS: SystemMenu[] = [
component: () => import('@/views/unitManage/securityUnit/index.vue') component: () => import('@/views/unitManage/securityUnit/index.vue')
} }
] ]
}, {
title: '数据总览',
name: 'dataOverview',
path: '/dataOverview',
type: 'menu',
isFull: true,
component: () => import('@/views/data/dataOverview.vue')
}, { }, {
title: '开放平台', title: '开放平台',
name: 'openPlatform', name: 'openPlatform',

View File

@ -11,7 +11,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import {EnterprisesUnit} from "@/types/views/data/dataOverview.ts"; import {EnterprisesUnit} from "@/types/views/index.ts";
defineProps<EnterprisesUnit>() defineProps<EnterprisesUnit>()

View File

@ -1,112 +0,0 @@
<template>
<div class="container">
<div class="header">
<h1>警保联动数据总览</h1>
</div>
<MapContainer class="map-container" ref="mapRef" :init-callback="initMap">
<div class="left-panel panel">
<h2>左侧统计面板</h2>
<!-- 添加你的统计数据 -->
</div>
<div class="right-panel panel">
<h2>右侧统计面板</h2>
<!-- 添加你的统计数据 -->
</div>
</MapContainer>
</div>
</template>
<script setup lang="ts">
import MapContainer from "@/components/aMap/MapContainer.vue";
import {createApp, h, ref} from "vue";
import {ComponentExposed} from "vue-component-type-helpers";
import api from "@/axios";
import EnterprisesUnitInfoWindowContent from "@/views/data/components/EnterprisesUnitInfoWindowContent.vue";
import {EnterprisesUnit} from "@/types/views/data/dataOverview.ts";
const mapRef = ref<ComponentExposed<typeof MapContainer>>(null)
let infoWindow: AMap.InfoWindow = null;
const initMap = async () => {
const {data} = await api.get<EnterprisesUnit[]>('/enterprisesUnit/mapPoint')
mapRef.value?.mapInstance?.clearMap()
const markers = data.map(item => {
if (!item.point) {
return null;
}
const marker = new AMap.Marker({
icon: new AMap.Icon({
image: __APP_ENV.VITE_APP_MINIO_URL + item.type.extData.icon,
size: new AMap.Size(66, 66),
imageSize: new AMap.Size(66, 66),
}),
position: item.point,
offset: new AMap.Pixel(-33, -66)
})
marker.on('click', () => {
if (!infoWindow) {
infoWindow = new AMap.InfoWindow({
isCustom: true,
offset: new AMap.Pixel(66, -66),
closeWhenClickMap: true
});
}
const element = document.createElement('div')
//h vue
const _InfoWindow = h(EnterprisesUnitInfoWindowContent, item)
const app = createApp(_InfoWindow)
app.mount(element)
infoWindow.setContent(element)
infoWindow.open(mapRef.value?.mapInstance, item.point)
})
return marker
}).filter(Boolean)
mapRef.value.mapInstance.add(markers)
mapRef.value.mapInstance.setFitView()
}
</script>
<style scoped lang="scss">
.container {
position: relative;
height: 100vh;
}
.header {
background-color: rgba(255, 255, 255, 0.7);
color: #333;
text-align: center;
padding: 20px;
position: absolute;
top: 20px;
left: 0;
right: 0;
z-index: 10;
}
.map-container {
height: 100%;
position: relative;
}
.panel {
background-color: rgba(255, 255, 255, 0.7);
padding: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
position: absolute;
top: 100px; /* 调整顶部距离以避免与标题重叠 */
z-index: 10;
}
.left-panel {
width: 15%;
left: 10px;
}
.right-panel {
width: 15%;
right: 10px;
}
</style>

View File

@ -1,13 +1,112 @@
<template> <template>
<div> <div class="container">
index页面 <div class="header">
<h1>警保联动数据总览</h1>
</div>
<MapContainer class="map-container" ref="mapRef" :init-callback="initMap">
<div class="left-panel panel">
<h2>左侧统计面板</h2>
<!-- 添加你的统计数据 -->
</div>
<div class="right-panel panel">
<h2>右侧统计面板</h2>
<!-- 添加你的统计数据 -->
</div>
</MapContainer>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import MapContainer from "@/components/aMap/MapContainer.vue";
import {createApp, h, ref} from "vue";
import {ComponentExposed} from "vue-component-type-helpers";
import api from "@/axios";
import EnterprisesUnitInfoWindowContent from "@/views/components/EnterprisesUnitInfoWindowContent.vue";
import {EnterprisesUnit} from "@/types/views/index.ts";
const mapRef = ref<ComponentExposed<typeof MapContainer>>(null)
let infoWindow: AMap.InfoWindow = null;
const initMap = async () => {
const {data} = await api.get<EnterprisesUnit[]>('/super/index/mapPoint')
mapRef.value?.mapInstance?.clearMap()
const markers = data.map(item => {
if (!item.point) {
return null;
}
const marker = new AMap.Marker({
icon: new AMap.Icon({
image: __APP_ENV.VITE_APP_MINIO_URL + item.type.extData.icon,
size: new AMap.Size(66, 66),
imageSize: new AMap.Size(66, 66),
}),
position: item.point,
offset: new AMap.Pixel(-33, -66)
})
marker.on('click', () => {
if (!infoWindow) {
infoWindow = new AMap.InfoWindow({
isCustom: true,
offset: new AMap.Pixel(66, -66),
closeWhenClickMap: true
});
}
const element = document.createElement('div')
//h vue
const _InfoWindow = h(EnterprisesUnitInfoWindowContent, item)
const app = createApp(_InfoWindow)
app.mount(element)
infoWindow.setContent(element)
infoWindow.open(mapRef.value?.mapInstance, item.point)
})
return marker
}).filter(Boolean)
mapRef.value.mapInstance.add(markers)
mapRef.value.mapInstance.setFitView()
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.container {
position: relative;
height: 100%;
}
.header {
background-color: rgba(255, 255, 255, 0.7);
color: #333;
text-align: center;
padding: 20px;
position: absolute;
top: 20px;
left: 0;
right: 0;
z-index: 10;
}
.map-container {
height: 100%;
position: relative;
}
.panel {
background-color: rgba(255, 255, 255, 0.7);
padding: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
position: absolute;
top: 100px; /* 调整顶部距离以避免与标题重叠 */
z-index: 10;
}
.left-panel {
width: 15%;
left: 10px;
}
.right-panel {
width: 15%;
right: 10px;
}
</style> </style>

View File

@ -129,8 +129,8 @@ const a = () => {
const secretKey = "db1b5214-02ee-497f-957c-88323b4351bf" const secretKey = "db1b5214-02ee-497f-957c-88323b4351bf"
const now = Date.now() const now = Date.now()
const params = { const params = {
code: 'SSP001', id: "1855852231820054528",
level: 5 type: 'ENTERPRISES_UNIT'
} }
const sign = generatedSign(params, now, accessKey, secretKey) const sign = generatedSign(params, now, accessKey, secretKey)
const headers2 = { const headers2 = {