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.exception.MessageException;
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.queryParams.EnterprisesUnitPagerQueryParams;
import com.changhu.module.management.pojo.vo.EnterprisesUnitPagerVo;
@ -64,10 +63,4 @@ public class EnterprisesUnitController {
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;
@Schema(description = "事业单位名称")
private String enterprisesUnitName;
@Schema(description = "省编码")
private String province;
@Schema(description = "")
private String provinceName;
@Schema(description = "市编码")
private String city;
@Schema(description = "")
private String cityName;
@Schema(description = "区/县编码")
private String districts;
@Schema(description = "区/县")
private String districtsName;
@Schema(description = "街道编码")
private String street;
@Schema(description = "街道")
private String streetName;
@Schema(description = "事业单位详细地址")

View File

@ -4,7 +4,7 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.TypeReference;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.changhu.common.db.enums.IsEnable;
import com.changhu.common.exception.MessageException;
@ -67,7 +67,7 @@ public class SignInterceptor implements HandlerInterceptor {
.orElseThrow(() -> new MessageException("无效的accessKey"));
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()) {
@ -80,20 +80,17 @@ public class SignInterceptor implements HandlerInterceptor {
}
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(TIMESTAMP, timestamp);
//添加请求url参数
Optional.ofNullable(HttpUtil.decodeParamMap(request.getQueryString(), StandardCharsets.UTF_8))
.ifPresent(hashMap::putAll);
//添加body参数
CustomHttpServletRequestWrapper c = (CustomHttpServletRequestWrapper) request;
Optional.ofNullable(new TypeReference<Map<String, Object>>() {
}.parseObject(c.getBody())).ifPresent(hashMap::putAll);
Optional.ofNullable(JSON.<Map<String, Object>>parseObject(((CustomHttpServletRequestWrapper) request).getBody(), Map.class))
.ifPresent(hashMap::putAll);
//生成签名
String nowSign = generatedSign(hashMap, accessKeyEntity.getSecretKey());
//比对签名
if (!sign.equals(nowSign)) {
throw new MessageException("签名错误");
}
@ -118,9 +115,4 @@ public class SignInterceptor implements HandlerInterceptor {
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
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 mini_program_user mpu on mpu.identity = 'police' and car.create_by = mpu.snow_flake_id and mpu.delete_flag = 0
left join police_unit pu on mpu.unit_id = pu.snow_flake_id and pu.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
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
where car.delete_flag = 0

View File

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

View File

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

View File

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

View File

@ -11,7 +11,7 @@
</template>
<script setup lang="ts">
import {EnterprisesUnit} from "@/types/views/data/dataOverview.ts";
import {EnterprisesUnit} from "@/types/views/index.ts";
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>
<div>
index页面
<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/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>
<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>

View File

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