# 网格管理页面设计文档 ## 1. 页面概述 网格管理页面允许系统管理员创建、查看、编辑和删除地理网格。每个网格代表一个责任区域,可以关联到特定的主管或网格员。此功能是任务分配和地理数据可视化的基础。 ## 2. 页面布局 ![网格管理页面布局示意图](https://placeholder-for-grid-page-mockup.png) ### 2.1 布局结构 页面由两部分组成: - **左侧**: 网格列表,以表格形式展示所有已定义的网格及其基本信息(名称、负责人等)。 - **右侧**: 交互式地图,用于可视化展示所选网格的地理边界。当创建或编辑网格时,地图将进入绘图模式。 ## 3. 组件结构 ```vue ``` ## 4. 数据结构 ```typescript // 网格列表项 interface GridListItem { id: number; name: string; manager?: string; // GeoJSON 字符串 geometry: string; } // 网格表单数据 (用于对话框) interface GridFormData { id?: number; name: string; managerId?: number; // GeoJSON 字符串 geometry: string; } ``` ## 5. 状态管理 ```typescript // 地图实例 let mapInstance = null; let currentGridLayer = null; // 组件内状态 const mapContainer = ref(); const dialogVisible = ref(false); const selectedGridId = ref(null); // 全局状态 (Pinia Store) const gridStore = useGridStore(); const { grids, loading } = storeToRefs(gridStore); ``` ## 6. 交互逻辑 ### 6.1 地图与列表交互 ```typescript onMounted(() => { gridStore.fetchGrids(); initializeMap(); }); const initializeMap = () => { // ... 地图初始化逻辑 }; // 点击表格行,在地图上高亮显示对应网格 const handleRowClick = (row: GridListItem) => { if (currentGridLayer) { mapInstance.removeLayer(currentGridLayer); } if (row.geometry) { const geoJson = JSON.parse(row.geometry); currentGridLayer = L.geoJSON(geoJson).addTo(mapInstance); mapInstance.fitBounds(currentGridLayer.getBounds()); } }; ``` ### 6.2 CRUD 操作 ```typescript const handleCreate = () => { selectedGridId.value = null; dialogVisible.value = true; }; const handleEdit = (grid: GridListItem) => { selectedGridId.value = grid.id; dialogVisible.value = true; }; const handleDelete = async (grid: GridListItem) => { await gridStore.deleteGrid(grid.id); ElMessage.success('网格删除成功'); gridStore.fetchGrids(); }; const onFormSuccess = () => { dialogVisible.value = false; gridStore.fetchGrids(); }; ``` ## 7. API 调用 ```typescript // api/grid.ts export const gridApi = { getGrids: () => apiClient.get('/grid'), getGridById: (id: number) => apiClient.get(`/grid/${id}`), createGrid: (data: GridFormData) => apiClient.post('/grid', data), updateGrid: (id: number, data: GridFormData) => apiClient.put(`/grid/${id}`, data), deleteGrid: (id: number) => apiClient.delete(`/grid/${id}`), }; // stores/grid.ts export const useGridStore = defineStore('grid', { state: () => ({ grids: [] as GridListItem[], loading: false, }), actions: { async fetchGrids() { this.loading = true; try { const { data } = await gridApi.getGrids(); this.grids = data; } finally { this.loading = false; } }, // ... create, update, delete actions } }); ``` ## 8. 样式设计 ```scss .grid-management-page { padding: 24px; .page-container { margin-top: 24px; } .table-toolbar { display: flex; justify-content: space-between; align-items: center; } .map-container { height: 600px; } } ``` ## 9. 关联组件 ### `GridFormDialog.vue` 这是本页面的核心复杂组件,用于创建和编辑网格。 - **Props**: `modelValue`, `gridId` - **内部组件**: - 一个表单,包含网格名称、负责人(下拉选择)等字段。 - 一个内嵌的 Leaflet 地图,用于绘制和编辑网格边界。 - **功能**: - **地图绘制**: 提供多边形(Polygon)绘制工具。用户可以在地图上绘制闭合区域来定义网格边界。 - **数据加载**: 在编辑模式下,根据 `gridId` 加载网格数据,并在表单和内嵌地图上显示。 - **数据保存**: 用户完成绘制和表单填写后,点击保存。组件将绘制的多边形转换为 GeoJSON 字符串,连同表单数据一起,调用 store 的 action 进行保存。 ## 10. 测试用例 - **集成测试**: - 测试能否成功创建一个新网格,包括在地图上绘制边界和填写信息。 - 测试点击列表中的网格,地图上是否正确显示其边界。 - 测试编辑功能,包括修改网格信息和在地图上重新编辑边界。 - 测试删除网格功能。