7 Commits

Author SHA1 Message Date
zxyroy bf0e8f2e26 脉冲点列表和导出 2026-06-17 20:27:57 +08:00
zxyroy 73c2fc2ffa Merge remote-tracking branch 'origin/main' into zxy
# Conflicts:
#	.gitignore
2026-06-12 11:25:39 +08:00
wzy-warehouse 2b772a937c 修改暴雨地震灾害链影响点列表 2026-06-12 11:20:57 +08:00
wzy-warehouse 1ca5ed016f 修改地震灾害链影响点列表 2026-06-12 10:42:54 +08:00
wzy-warehouse c5615345c8 修改暴雨灾害链中灾害链影响点列表 2026-06-12 10:39:27 +08:00
wzy-warehouse fed824272f 简单修改 2026-06-03 15:27:51 +08:00
zbj d61e1edc20 基础修改 2026-05-23 16:30:09 +08:00
14 changed files with 893 additions and 212 deletions
+1 -3
View File
@@ -1,5 +1,3 @@
NEW_FILE_CODE
# 后端地址
VITE_BACKEND_BASE_URL=http://localhost:8081
@@ -13,4 +11,4 @@ VITE_GEOSERVER_BASE_URL=http://47.92.216.173:4019/geoserver/xian
VITE_WEBSOCKET_URL=http://localhost:8081/websocket
# 文件地址
VITE_FILE_URL=http://localhost:8083
VITE_FILE_URL=http://localhost:8083
+1 -3
View File
@@ -1,5 +1,3 @@
NEW_FILE_CODE
# 后端地址
VITE_BACKEND_BASE_URL=http://localhost:8080
@@ -13,4 +11,4 @@ VITE_GEOSERVER_BASE_URL=http://10.22.245.246/geoserver/xian
VITE_WEBSOCKET_URL=http://localhost:8080/websocket
# 文件地址
VITE_FILE_URL=http://localhost:8083
VITE_FILE_URL=http://localhost:8083
+2 -1
View File
@@ -26,4 +26,5 @@ dist-ssr
auto-imports.d.ts
components.d.ts
pnpm-lock.yaml
package-lock.json
/package-lock.json
/pnpm-workspace.yaml
+3
View File
@@ -17,7 +17,9 @@
"@types/spark-md5": "^3.0.5",
"axios": "^1.12.2",
"cesium": "1.101.0",
"docx": "^9.7.1",
"element-plus": "^2.13.6",
"file-saver": "^2.0.5",
"gm-crypto": "^0.1.12",
"pinia": "^3.0.3",
"proj4": "^2.20.8",
@@ -29,6 +31,7 @@
},
"devDependencies": {
"@tsconfig/node22": "^22.0.2",
"@types/file-saver": "^2.0.7",
"@types/node": "^24.12.2",
"@types/proj4": "^2.19.0",
"@types/sockjs-client": "^1.5.4",
@@ -11,6 +11,9 @@
<!-- 具体功能组件 -->
<AroundAnalysisDetailComponent />
<!-- 脉冲点列表组件 -->
<PulsePointListComponent />
</div>
</template>
@@ -21,6 +24,8 @@ import { useAnalysisButton } from '@/hooks/rain-earthquake/useAnalysisButton';
import AroundAnalysisDetailComponent from './around-analysis/AroundAnalysisDetailComponent.vue';
import ButtonComponent from './around-analysis/ButtonComponent.vue';
import SearchComponent from './around-analysis/SearchComponent.vue';
import PulsePointListComponent from './around-analysis/PulsePointListComponent.vue';
const statusStore = useStatusStore();
@@ -0,0 +1,595 @@
<template>
<div
v-if="showPulsePointList"
ref="listRef"
class="pulse-point-list"
:style="{ right: position.right + 'px', bottom: position.bottom + 'px' }"
>
<div class="list-header" @mousedown="startDrag">
<span>脉冲点列表 ({{ pulsePoints.length }})</span>
<el-button
type="primary"
size="small"
@click="exportToWord"
class="export-btn"
:icon="Download"
>
导出
</el-button>
</div>
<div class="search-box">
<el-input
v-model="searchKeyword"
placeholder="搜索点位..."
clearable
size="small"
prefix-icon="Search"
/>
</div>
<div class="point-list-content">
<el-table
:data="filteredPoints"
border
stripe
max-height="300"
style="width: 100%"
empty-text="暂无数据"
>
<!-- 名称列 - 悬浮时文字换行展开 -->
<el-table-column
prop="value"
label="名称"
width="150"
>
<template #default="{ row }">
<span class="name-cell">
{{ (row as any).value || '未命名' }}
</span>
</template>
</el-table-column>
<el-table-column prop="category" label="类型" width="80" align="center">
<template #default="{ row }">
<el-tag size="small" :type="getCategoryType(row.category)">
{{ getCategoryName((row as any).category) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="坐标" width="135" align="center">
<template #default="{ row }">
<div class="coordinate">
{{ (row as any).lon?.toFixed(4) || '-' }}, {{ (row as any).lat?.toFixed(4) || '-' }}
</div>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, inject, reactive, watch, nextTick } from 'vue';
import { Download } from '@element-plus/icons-vue';
import { Document, Packer, Paragraph, Table, TableRow, TableCell, WidthType, AlignmentType, TextRun, HeadingLevel } from 'docx';
import { saveAs } from 'file-saver';
import type { AnalysisButtonState } from '@/types/common/useAroundAnalysisType';
const analysisButtonState = inject<AnalysisButtonState>('analysisButtonState');
const pulsePoints = computed(() => analysisButtonState?.pulsePoints.value || []);
const showPulsePointList = computed(() => analysisButtonState?.showPulsePointList.value || false);
const searchKeyword = ref('');
const listRef = ref<HTMLElement | null>(null);
// 使用 right 和 bottom 定位(距离右下角的偏移量)
const position = reactive({ right: 20, bottom: 20 });
const isDragging = ref(false);
const dragStart = reactive({ x: 0, y: 0 });
const initialPosition = reactive({ right: 0, bottom: 0 });
const listSize = reactive({ width: 375, height: 420 });
// 获取列表的实际尺寸
const updateListSize = () => {
if (listRef.value) {
const rect = listRef.value.getBoundingClientRect();
listSize.width = rect.width;
listSize.height = rect.height;
}
};
// 边界限制函数
const constrainPosition = (right: number, bottom: number) => {
updateListSize();
const actualLeft = window.innerWidth - listSize.width - right;
const actualTop = window.innerHeight - listSize.height - bottom;
let constrainedRight = right;
let constrainedBottom = bottom;
if (actualLeft < 0) {
constrainedRight = window.innerWidth - listSize.width;
}
if (actualLeft > window.innerWidth - listSize.width) {
constrainedRight = 0;
}
if (actualTop < 100) {
constrainedBottom = window.innerHeight - listSize.height - 100;
}
if (actualTop > window.innerHeight - listSize.height) {
constrainedBottom = 0;
}
constrainedRight = Math.max(0, Math.min(constrainedRight, window.innerWidth - listSize.width));
constrainedBottom = Math.max(0, Math.min(constrainedBottom, window.innerHeight - listSize.height));
return {
right: constrainedRight,
bottom: constrainedBottom
};
};
// 重置位置到右下角
const resetPosition = () => {
nextTick(() => {
updateListSize();
position.right = 20;
position.bottom = 20;
});
};
// 监听列表显示状态
watch(showPulsePointList, async (newValue) => {
if (newValue) {
await nextTick();
resetPosition();
}
});
// 监听窗口大小变化
watch(() => window.innerWidth, () => {
if (showPulsePointList.value) {
resetPosition();
}
});
watch(() => window.innerHeight, () => {
if (showPulsePointList.value) {
resetPosition();
}
});
const filteredPoints = computed(() => {
if (!searchKeyword.value) return pulsePoints.value;
const keyword = searchKeyword.value.toLowerCase();
return pulsePoints.value.filter(point =>
point.value?.toLowerCase().includes(keyword) ||
point.category?.toLowerCase().includes(keyword)
);
});
// 导出为 Word 文档
const exportToWord = async () => {
try {
const points = filteredPoints.value;
// 统计各类别数量
const categoryCount: Record<string, number> = {};
points.forEach(point => {
const category = getCategoryName(point.category);
categoryCount[category] = (categoryCount[category] || 0) + 1;
});
// 创建表格行数据
const tableRows = [
new TableRow({
children: [
new TableCell({
children: [new Paragraph({ text: '序号', alignment: AlignmentType.CENTER })],
width: { size: 8, type: WidthType.PERCENTAGE },
}),
new TableCell({
children: [new Paragraph({ text: '名称', alignment: AlignmentType.CENTER })],
width: { size: 35, type: WidthType.PERCENTAGE },
}),
new TableCell({
children: [new Paragraph({ text: '类型', alignment: AlignmentType.CENTER })],
width: { size: 15, type: WidthType.PERCENTAGE },
}),
new TableCell({
children: [new Paragraph({ text: '坐标', alignment: AlignmentType.CENTER })],
width: { size: 42, type: WidthType.PERCENTAGE },
}),
],
}),
];
// 添加数据行
points.forEach((point, index) => {
tableRows.push(
new TableRow({
children: [
new TableCell({
children: [new Paragraph({ text: String(index + 1), alignment: AlignmentType.CENTER })],
}),
new TableCell({
children: [new Paragraph({ text: point.value || '未命名' })],
}),
new TableCell({
children: [new Paragraph({ text: getCategoryName(point.category), alignment: AlignmentType.CENTER })],
}),
new TableCell({
children: [new Paragraph({
text: `${point.lon?.toFixed(4) || '-'}, ${point.lat?.toFixed(4) || '-'}`,
alignment: AlignmentType.CENTER
})],
}),
],
})
);
});
// 创建统计数据段落
const statsParagraphs = Object.entries(categoryCount).map(([category, count]) => {
return new Paragraph({
children: [
new TextRun({ text: `${category}: `, bold: true }),
new TextRun({ text: `${count}` }),
],
});
});
// 创建文档
const doc = new Document({
sections: [
{
properties: {},
children: [
// 标题
new Paragraph({
text: '脉冲点列表导出报告',
heading: HeadingLevel.HEADING_1,
alignment: AlignmentType.CENTER,
}),
// 空行
new Paragraph({}),
// 总数统计
new Paragraph({
children: [
new TextRun({ text: '总点数: ', bold: true }),
new TextRun({ text: `${points.length}` }),
],
}),
// 空行
new Paragraph({}),
// 分类统计标题
new Paragraph({
text: '分类统计:',
heading: HeadingLevel.HEADING_2,
}),
// 分类统计数据
...statsParagraphs,
// 空行
new Paragraph({}),
// 详细数据标题
new Paragraph({
text: '详细数据:',
heading: HeadingLevel.HEADING_2,
}),
// 空行
new Paragraph({}),
// 表格
new Table({
rows: tableRows,
width: { size: 100, type: WidthType.PERCENTAGE },
}),
],
},
],
});
// 生成并下载文档
const blob = await Packer.toBlob(doc);
const fileName = `脉冲点列表_${new Date().toISOString().slice(0, 10)}.docx`;
saveAs(blob, fileName);
} catch (error) {
console.error('导出失败:', error);
alert('导出失败,请重试');
}
};
// 开始拖动
const startDrag = (e: MouseEvent) => {
// Deleted:if ((e.target as HTMLElement).closest('.close-btn')) return;
isDragging.value = true;
dragStart.x = e.clientX;
dragStart.y = e.clientY;
initialPosition.right = position.right;
initialPosition.bottom = position.bottom;
document.addEventListener('mousemove', onDrag);
document.addEventListener('mouseup', stopDrag);
e.preventDefault();
};
// 拖动中
const onDrag = (e: MouseEvent) => {
if (!isDragging.value) return;
const deltaX = e.clientX - dragStart.x;
const deltaY = e.clientY - dragStart.y;
updateListSize();
const currentLeft = window.innerWidth - listSize.width - position.right;
const currentTop = window.innerHeight - listSize.height - position.bottom;
let newLeft = currentLeft + deltaX;
let newTop = currentTop + deltaY;
newLeft = Math.max(0, newLeft);
newLeft = Math.min(newLeft, window.innerWidth - listSize.width);
newTop = Math.max(100, newTop);
newTop = Math.min(newTop, window.innerHeight - listSize.height);
const newRight = window.innerWidth - listSize.width - newLeft;
const newBottom = window.innerHeight - listSize.height - newTop;
const constrained = constrainPosition(newRight, newBottom);
position.right = constrained.right;
position.bottom = constrained.bottom;
dragStart.x = e.clientX;
dragStart.y = e.clientY;
initialPosition.right = position.right;
initialPosition.bottom = position.bottom;
};
// 停止拖动
const stopDrag = () => {
isDragging.value = false;
document.removeEventListener('mousemove', onDrag);
document.removeEventListener('mouseup', stopDrag);
};
const getCategoryName = (category?: string): string => {
const nameMap: Record<string, string> = {
'school': '学校',
'hospital': '医院',
'danger': '危险源',
'shelter': '避难所',
'fire': '消防站',
'store': '储备点',
'subway': '地铁站',
'hidden-danger': '隐患点',
'risk-point': '风险点',
'bridge': '桥梁',
'reservoir': '水库'
};
return nameMap[category || ''] || category || '未知';
};
const getCategoryType = (category?: string): string => {
const typeMap: Record<string, string> = {
'school': 'primary',
'hospital': 'success',
'danger': 'danger',
'shelter': 'warning',
'fire': 'danger',
'store': 'info',
'subway': '',
'hidden-danger': 'warning',
'risk-point': 'danger',
'bridge': 'info',
'reservoir': 'success'
};
return typeMap[category || ''] || '';
};
</script>
<style scoped>
.pulse-point-list {
position: fixed;
z-index: 100000;
background: rgba(14, 52, 98, 0.95);
border: 1px solid rgba(0, 225, 255, 0.5);
border-radius: 4px;
padding: 15px;
width: auto;
min-width: 350px;
max-width: 450px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
backdrop-filter: blur(10px);
user-select: none;
display: flex;
flex-direction: column;
max-height: calc(100vh - 40px);
}
.list-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
padding-bottom: 10px;
border-bottom: 1px solid rgba(0, 225, 255, 0.3);
cursor: move;
flex-shrink: 0;
}
.list-header span {
color: white;
font-size: 16px;
font-weight: bold;
}
.export-btn {
background-color: rgba(0, 225, 255, 0.3);
border-color: rgba(0, 225, 255, 0.5);
color: white;
}
.export-btn:hover {
background-color: rgba(0, 225, 255, 0.5);
border-color: rgba(0, 225, 255, 0.8);
}
.search-box {
margin-bottom: 12px;
flex-shrink: 0;
}
.point-list-content {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
min-height: 0;
}
.coordinate {
font-size: 13px;
color: rgba(255, 255, 255, 0.8);
white-space: nowrap;
font-family: monospace;
}
/* 表格样式 */
:deep(.el-table) {
background-color: transparent;
--el-table-tr-bg-color: transparent;
--el-table-header-bg-color: rgba(86, 204, 242, 0.3);
--el-table-row-hover-bg-color: rgba(0, 225, 255, 0.2);
--el-table-border-color: rgba(255, 255, 255, 0.2);
--el-table-text-color: white;
--el-table-header-text-color: white;
}
:deep(.el-table th.el-table__cell) {
background: linear-gradient(
180deg,
rgb(86, 204, 242) 0%,
rgb(47, 128, 237) 100%
);
color: white;
font-weight: bold;
padding: 8px 0 !important;
}
:deep(.el-table td.el-table__cell) {
background-color: rgba(15, 61, 118, 0.4);
color: white;
transition: background-color 0.2s ease;
padding: 6px 0 !important;
}
:deep(.el-table--striped .el-table__body tr.el-table__row--striped td) {
background-color: rgba(15, 61, 118, 0.6);
}
:deep(.el-table__body tr:hover) > td {
background-color: rgba(0, 225, 255, 0.15) !important;
}
/* 单元格内容样式 */
:deep(.el-table .cell) {
padding-left: 8px !important;
padding-right: 8px !important;
overflow: visible;
white-space: normal;
word-break: break-word;
}
:deep(.el-input__wrapper) {
background-color: rgba(15, 61, 118, 0.6);
border: 1px solid rgba(0, 225, 255, 0.3);
box-shadow: none;
}
:deep(.el-input__inner) {
color: white;
}
:deep(.el-input__wrapper.is-focus) {
box-shadow: 0 0 0 1px rgba(0, 225, 255, 0.8) inset;
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-thumb {
background: rgba(0, 225, 255, 0.3);
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(0, 225, 255, 0.5);
}
::-webkit-scrollbar-track {
background: rgba(15, 61, 118, 0.3);
border-radius: 3px;
}
/* 隐藏外层容器的滚动条 */
.pulse-point-list::-webkit-scrollbar {
display: none;
}
/* 表格内部滚动条样式 */
.point-list-content::-webkit-scrollbar {
width: 6px;
}
.point-list-content::-webkit-scrollbar-thumb {
background: #888;
border-radius: 3px;
}
.point-list-content::-webkit-scrollbar-thumb:hover {
background: #666;
}
.point-list-content::-webkit-scrollbar-track {
background: transparent;
}
/* 名称单元格样式 - 默认截断,悬浮时换行展开 */
.name-cell {
display: inline-block;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: white;
}
/* 悬浮时展开文字,换行显示完整内容 */
.name-cell:hover {
white-space: normal;
word-break: break-word;
}
/* 强制表格头部文字居中 */
:deep(.el-table th.el-table__cell .cell) {
justify-content: center !important;
text-align: center !important;
}
</style>
@@ -1,7 +1,3 @@
import { ref } from 'vue';
import type { XianHiddenDangerSpots } from '@/types/base/XianHiddenDangerSpots';
import type { PaginationType } from '@/types/common/PaginationType';
import { PointType } from '@/types/common/DisasterType';
import { ControlPanelCategory } from '@/types/common/ControlPanelCategory';
import { useStatusStore } from '@/stores/useStatusStore';
import { useLayerControl } from '../rain-earthquake/useLayerControl.ts';
@@ -25,7 +21,7 @@ import { useLoadingResourceStore } from '@/stores/useLoadingResourceStore.ts';
import { LoadingResource } from '@/types/common/LoadingResourceType.ts';
/**
* 暴雨灾害链
* 地震灾害链
* @returns
*/
export const useEarthquakeDisasterChain = () => {
@@ -34,68 +30,6 @@ export const useEarthquakeDisasterChain = () => {
const resourceStore = useLoadingResourceStore();
const rightHandle = useRightHandle();
// ================灾害链影响点列表================================
/**
* 搜索条件
*/
const conditions = ref({
tableData: '',
hiddenPoint: PointType.LANDSLIDE,
});
/**
* 下拉选项
*/
const selectOptions = [
{ value: PointType.LANDSLIDE, label: '滑坡' },
{ value: PointType.DEBRIS_FLOW, label: '泥石流' },
{ value: PointType.RISK_AREA, label: '风险区' },
];
/**
* 表格数据
*/
const tableDatas = ref<XianHiddenDangerSpots[]>([]);
/**
* 表头配置
*/
const tableColumns = [
{ title: '名称', key: 'disasterName' },
{ title: '位置', key: 'position' },
{ title: '规模等级', key: 'scaleGrade' },
{ title: '险情等级', key: 'riskGrade' },
];
/**
* 分页配置
*/
const paginationConfig = ref<PaginationType>({
currentPage: 1,
pageSize: 10,
total: 10,
totalPage: 1,
});
/**
* 修改搜索条件
* @param value - 新的搜索条件
*/
const changeConditions = (value: {
tableData: string;
hiddenPoint: PointType;
}): void => {
conditions.value = value;
};
/**
* 修改页码
* @param value - 新的页码
*/
const changeCurrentPage = (value: number) => {
paginationConfig.value.currentPage = value;
};
// ================左侧按钮================================
/**
* 左侧按钮信息
@@ -356,15 +290,8 @@ export const useEarthquakeDisasterChain = () => {
};
return {
conditions,
selectOptions,
tableDatas,
tableColumns,
paginationConfig,
leftButtonInfo,
rightButtonInfo,
controlPanel: getControlPanel(),
changeConditions,
changeCurrentPage,
};
};
+47 -8
View File
@@ -90,6 +90,8 @@ export const useAnalysisButton = (): AnalysisButtonState => {
const showAreaDialog = ref(false);
const radius = ref(10);
const dialogPosition = reactive<DialogPosition>({ x: 0, y: 0 });
const pulsePoints = ref<PointResource[]>([]);
const showPulsePointList = ref(false);
let clickHandler: ScreenSpaceEventHandler | null = null;
let currentCenterPosition: Cartesian3 | null = null;
@@ -184,6 +186,8 @@ export const useAnalysisButton = (): AnalysisButtonState => {
const pointsInCircle = getPointsInCircle(currentCenterPosition, radius.value);
addPulseEffectToPoints(pointsInCircle);
pulsePoints.value = pointsInCircle;
showPulsePointList.value = true;
};
// ==================== 地图事件处理 ====================
@@ -236,17 +240,26 @@ export const useAnalysisButton = (): AnalysisButtonState => {
};
// ==================== 资源清理 ====================
const clearAllAnalysisResources = () => {
removeMarker();
clearCircle();
removePulseEffect();
currentCenterPosition = null;
pulsePoints.value = [];
showPulsePointList.value = false;
};
/**
* 仅清除视觉效果,保留标记点和中心点位置
*/
const clearVisualEffectsOnly = () => {
clearCircle();
removePulseEffect();
pulsePoints.value = [];
showPulsePointList.value = false;
};
// ==================== 事件处理 ====================
const handleConfirm = () => {
const handleConfirm = () => {
if (!currentCenterPosition) {
console.error('中心点位置不存在');
return;
@@ -256,11 +269,16 @@ export const useAnalysisButton = (): AnalysisButtonState => {
radius: radius.value,
center: currentCenterPosition
});
// 先清除上一次的视觉效果(保留标记点)
clearVisualEffectsOnly();
// 重新绘制当前选择的效果
drawCircle(currentCenterPosition, radius.value);
const pointsInCircle = getPointsInCircle(currentCenterPosition, radius.value);
addPulseEffectToPoints(pointsInCircle);
pulsePoints.value = pointsInCircle;
showPulsePointList.value = true;
const cartographic = Cartographic.fromCartesian(currentCenterPosition);
const longitude = cartographic.longitude * (180 / Math.PI);
@@ -268,12 +286,28 @@ export const useAnalysisButton = (): AnalysisButtonState => {
const flyHeight = Math.max(radius.value * FLY_HEIGHT_MULTIPLIER, MIN_FLY_HEIGHT);
CesiumUtilsSingleton.flyToTarget([longitude, latitude, flyHeight], FLY_DURATION);
// 关闭对话框并清理资源(包括鼠标样式)
showAreaDialog.value = false;
// 移除地图点击事件监听器,恢复鼠标默认样式
if (clickHandler) {
clickHandler.destroy();
clickHandler = null;
}
// 恢复鼠标默认样式
const viewer = CesiumUtilsSingleton.getViewer();
if (viewer?.canvas) {
statusStore.cursorStyle = 'default';
viewer.canvas.style.cursor = 'default';
}
};
const handleCancel = () => {
showAreaDialog.value = false;
clearAllAnalysisResources();
pulsePoints.value = [];
showPulsePointList.value = false;
};
const handleButtonClick = (index: number, callback: (status: boolean) => void) => {
@@ -320,9 +354,12 @@ export const useAnalysisButton = (): AnalysisButtonState => {
() => infra.value.showReservoir.show,
];
watch(layerVisibilityWatchers, () => {
console.log('检测到图层可见性变化,刷新脉冲效果');
refreshPulseEffect();
watch(layerVisibilityWatchers, () => {
// 只有当有中心点位置且脉冲点列表正在显示时,才刷新脉冲效果
if (currentCenterPosition && showPulsePointList.value) {
console.log('检测到图层可见性变化,刷新脉冲效果');
refreshPulseEffect();
}
});
onUnmounted(() => {
@@ -361,7 +398,7 @@ export const useAnalysisButton = (): AnalysisButtonState => {
},
];
return {
return {
selectedButtonIndex,
showAreaDialog,
radius,
@@ -371,5 +408,7 @@ export const useAnalysisButton = (): AnalysisButtonState => {
handleConfirm,
handleCancel,
refreshPulseEffect,
pulsePoints,
showPulsePointList,
};
};
+1 -85
View File
@@ -1,7 +1,3 @@
import { ref, watch } from 'vue';
import type { XianHiddenDangerSpots } from '@/types/base/XianHiddenDangerSpots';
import type { PaginationType } from '@/types/common/PaginationType';
import { PointType } from '@/types/common/DisasterType';
import { ControlPanelCategory } from '@/types/common/ControlPanelCategory';
import { useStatusStore } from '@/stores/useStatusStore';
import {
@@ -41,69 +37,6 @@ export const useRainDisasterChain = () => {
statusStore.weatherLayers.showRainfallGrid.loading = true;
statusStore.weatherLayers.showRainfallGrid.show = true;
// ================灾害链影响点列表================================
/**
* 搜索条件
*/
const conditions = ref({
tableData: '',
hiddenPoint: PointType.LANDSLIDE,
});
/**
* 下拉选项
*/
const selectOptions = ref([
{ value: PointType.LANDSLIDE, label: '滑坡' },
{ value: PointType.DEBRIS_FLOW, label: '泥石流' },
{ value: PointType.FLASH_FLOOD, label: '山洪' },
{ value: PointType.WATER_LOGGING, label: '内涝' },
]);
/**
* 表格数据
*/
const tableDatas = ref<XianHiddenDangerSpots[]>([]);
/**
* 表头配置
*/
const tableColumns = ref([
{ title: '名称', key: 'disasterName' },
{ title: '位置', key: 'position' },
{ title: '规模等级', key: 'scaleGrade' },
{ title: '险情等级', key: 'riskGrade' },
]);
/**
* 分页配置
*/
const paginationConfig = ref<PaginationType>({
currentPage: 1,
pageSize: 10,
total: 10,
totalPage: 1,
});
/**
* 修改搜索条件
* @param value - 新的搜索条件
*/
const changeConditions = (value: {
tableData: string;
hiddenPoint: PointType;
}): void => {
conditions.value = value;
};
/**
* 修改页码
* @param value - 新的页码
*/
const changeCurrentPage = (value: number) => {
paginationConfig.value.currentPage = value;
};
// ================左侧按钮================================
/**
* 左侧按钮信息
@@ -175,7 +108,7 @@ export const useRainDisasterChain = () => {
*/
const rightButtonInfo = [
{
name: '降雨推演',
name: '自动推演',
callback: (status: unknown) => rightHandle.rainstormSimulation(status),
},
{
@@ -216,7 +149,6 @@ export const useRainDisasterChain = () => {
* 控制面板信息
*/
const getControlPanel = () => {
return [
// 灾害隐患点类别
{
@@ -402,25 +334,9 @@ export const useRainDisasterChain = () => {
];
};
// 监听条件变化
watch(
conditions,
() => {
console.log('条件改变');
},
{ deep: true }
);
return {
conditions,
selectOptions,
tableDatas,
tableColumns,
paginationConfig,
leftButtonInfo,
rightButtonInfo,
changeConditions,
changeCurrentPage,
controlPanel: getControlPanel(),
};
};
+139
View File
@@ -0,0 +1,139 @@
import { ref } from 'vue';
import type { XianHiddenDangerSpots } from '@/types/base/XianHiddenDangerSpots';
import type { PaginationType } from '@/types/common/PaginationType';
import { PointType } from '@/types/common/DisasterType';
/**
* 灾害链表格数据选项
*/
export interface SelectOption {
value: PointType;
label: string;
}
/**
* 表格列配置
*/
export interface TableColumn {
title: string;
key: string;
}
/**
* 搜索条件
*/
export interface SearchConditions {
tableData: string;
hiddenPoint: PointType;
}
/**
* 灾害链表格
* 负责管理灾害链影响点列表的数据获取、搜索和分页
* @returns 表格相关的状态和方法
*/
export const useDisasterChainTable = () => {
// ==================== 状态 ====================
/**
* 下拉选项配置
*/
const selectOptions = ref<SelectOption[]>([]);
/**
* 表格列配置
*/
const tableColumns = ref<TableColumn[]>([]);
/**
* 搜索条件
*/
const conditions = ref<SearchConditions>({
tableData: '',
hiddenPoint: PointType.LANDSLIDE,
});
/**
* 表格数据
*/
const tableDatas = ref<XianHiddenDangerSpots[]>([]);
/**
* 分页配置
*/
const paginationConfig = ref<PaginationType>({
currentPage: 1,
pageSize: 10,
total: 0,
totalPage: 0,
});
/**
* 加载状态
*/
const loading = ref(false);
/**
* 修改搜索条件
* @param value - 新的搜索条件
*/
const changeConditions = ref((value: SearchConditions): void => {
conditions.value = value;
});
/**
* 修改页码
* @param value - 新的页码
*/
const changeCurrentPage = (value: number) => {
paginationConfig.value.currentPage = value;
};
/**
* 设置条件
* @param newConditions 新的条件
*/
const setConditions = (newConditions: SearchConditions) => {
conditions.value = newConditions;
};
/**
* 获取条件
* @returns
*/
const getConditions = () => conditions.value;
/**
* 设置下拉选项
* @param options - 下拉选项数组
*/
const setSelectOptions = (options: SelectOption[]) => {
selectOptions.value = options;
};
/**
* 设置表格列配置
* @param columns - 表格列配置数组
*/
const setTableColumns = (columns: TableColumn[]) => {
tableColumns.value = columns;
};
// ==================== 返回 ====================
return {
// 状态
selectOptions,
tableColumns,
conditions,
tableDatas,
paginationConfig,
loading,
changeConditions,
setConditions,
getConditions,
changeCurrentPage,
setSelectOptions,
setTableColumns,
};
};
@@ -111,4 +111,8 @@ export interface AnalysisButtonState {
handleCancel: () => void;
/** 刷新脉冲效果 */
refreshPulseEffect: () => void;
/** 脉冲点列表 */
pulsePoints: Ref<PointResource[]>;
/** 是否显示脉冲点列表 */
showPulsePointList: Ref<boolean>;
}
+48 -26
View File
@@ -9,16 +9,16 @@
<!-- 断裂带 -->
<FaultComponent
v-if="
useStatusStore().appLoadingCompleted &&
useStatusStore().mapLayers.faultShow.loading
statusStore.appLoadingCompleted &&
statusStore.mapLayers.faultShow.loading
"
/>
<!-- 灾害链影响列表组件 -->
<DisasterChainPointComponent
v-if="
useStatusStore().appLoadingCompleted &&
useStatusStore().uiComponents.disasterChainPointShow.loading
statusStore.appLoadingCompleted &&
statusStore.uiComponents.disasterChainPointShow.loading
"
:select-options="selectOptions"
:table-data-list="tableDatas"
@@ -63,36 +63,58 @@
import LeftButtonComponent from '@/component/rain-earthquake/LeftButtonComponent.vue';
import RightButtonComponent from '@/component/rain-earthquake/RightButtonComponent.vue';
import { useEarthquakeDisasterChain } from '@/hooks/earthquake/useEarthquakeDisasterChain';
import {
useDisasterChainTable,
type SearchConditions,
} from '@/hooks/useDisasterChainTable';
import { useStatusStore } from '@/stores/useStatusStore';
import { DisasterType } from '@/types/common/DisasterType.ts';
import { watch } from 'vue';
import { DisasterType, PointType } from '@/types/common/DisasterType.ts';
import { onBeforeMount } from 'vue';
import { useRoute } from 'vue-router';
const route = useRoute();
const {
conditions,
selectOptions,
tableDatas,
tableColumns,
paginationConfig,
leftButtonInfo,
rightButtonInfo,
controlPanel,
changeConditions,
changeCurrentPage,
} = useEarthquakeDisasterChain();
const { leftButtonInfo, rightButtonInfo, controlPanel } =
useEarthquakeDisasterChain();
const statusStore = useStatusStore();
// 监听条件变化
watch(
conditions,
() => {
console.log('条件改变');
},
{ deep: true }
);
const {
selectOptions,
tableColumns,
tableDatas,
paginationConfig,
changeConditions,
setConditions,
changeCurrentPage,
setSelectOptions,
setTableColumns,
} = useDisasterChainTable();
onBeforeMount(() => {
// 设置下拉选项
setSelectOptions([
{ value: PointType.LANDSLIDE, label: '滑坡' },
{ value: PointType.DEBRIS_FLOW, label: '泥石流' },
{ value: PointType.RISK_AREA, label: '风险区' },
]);
// 设置表格列配置
setTableColumns([
{ title: '名称', key: 'disasterName' },
{ title: '位置', key: 'position' },
{ title: '规模等级', key: 'scaleGrade' },
{ title: '险情等级', key: 'riskGrade' },
]);
/**
* 条件改变执行
* @param value
*/
changeConditions.value = (value: SearchConditions) => {
setConditions(value);
};
});
</script>
<style scoped></style>
+46 -12
View File
@@ -71,25 +71,59 @@
import RightButtonComponent from '@/component/rain-earthquake/RightButtonComponent.vue';
import StepComponent from '@/component/rain-earthquake/StepComponent.vue';
import { useRainDisasterChain } from '@/hooks/rainstorm/useRainDisasterChain';
import {
useDisasterChainTable,
type SearchConditions,
} from '@/hooks/useDisasterChainTable';
import { useStatusStore } from '@/stores/useStatusStore';
import { DisasterType } from '@/types/common/DisasterType.ts';
import { DisasterType, PointType } from '@/types/common/DisasterType.ts';
import { onBeforeMount } from 'vue';
import { useRoute } from 'vue-router';
const route = useRoute();
const {
selectOptions,
tableDatas,
tableColumns,
paginationConfig,
leftButtonInfo,
rightButtonInfo,
controlPanel,
changeConditions,
changeCurrentPage,
} = useRainDisasterChain();
const { leftButtonInfo, rightButtonInfo, controlPanel } =
useRainDisasterChain();
const statusStore = useStatusStore();
const {
selectOptions,
tableColumns,
tableDatas,
paginationConfig,
changeConditions,
setConditions,
changeCurrentPage,
setSelectOptions,
setTableColumns,
} = useDisasterChainTable();
onBeforeMount(() => {
// 设置下拉选项
setSelectOptions([
{ value: PointType.LANDSLIDE, label: '滑坡' },
{ value: PointType.DEBRIS_FLOW, label: '泥石流' },
{ value: PointType.FLASH_FLOOD, label: '山洪' },
{ value: PointType.WATER_LOGGING, label: '内涝' },
]);
// 设置表格列配置
setTableColumns([
{ title: '名称', key: 'disasterName' },
{ title: '位置', key: 'position' },
{ title: '规模等级', key: 'scaleGrade' },
{ title: '险情等级', key: 'riskGrade' },
]);
/**
* 条件改变执行
* @param value
*/
changeConditions.value = (value: SearchConditions) => {
setConditions(value);
};
});
</script>
<style scoped></style>