|
|
@@ -28,7 +28,12 @@
|
|
|
<el-table :data="tableData" border stripe v-loading="loading">
|
|
|
<el-table-column prop="manholeCode" label="窨井编码" min-width="120" />
|
|
|
<el-table-column prop="manholeName" label="窨井名称" min-width="150" />
|
|
|
- <el-table-column prop="networkId" label="关联管网ID" min-width="120" />
|
|
|
+ <el-table-column prop="networkId" label="关联管网" min-width="150">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <span v-if="row.networkId">{{ getNetworkName(row.networkId) }}</span>
|
|
|
+ <el-tag v-else type="info" size="small">未关联</el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
<el-table-column prop="location" label="位置" min-width="180" />
|
|
|
<el-table-column prop="manholeDepth" label="深度(米)" width="90" />
|
|
|
<el-table-column prop="manholeShape" label="形状" width="80">
|
|
|
@@ -58,6 +63,7 @@
|
|
|
|
|
|
<el-card v-else class="map-card">
|
|
|
<div id="manholeMap" style="width: 100%; height: 600px"></div>
|
|
|
+ <div v-if="mapError" style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#f56c6c;font-size:14px;">{{ mapError }}</div>
|
|
|
</el-card>
|
|
|
|
|
|
<el-dialog title="关联监测设备" v-model="deviceDialogVisible" width="950px" destroy-on-close>
|
|
|
@@ -100,7 +106,7 @@
|
|
|
</el-dialog>
|
|
|
|
|
|
<el-dialog :title="dialogTitle" v-model="dialogVisible" width="650px" destroy-on-close>
|
|
|
- <el-form :model="formData" ref="formRef" label-width="100px">
|
|
|
+ <el-form :model="formData" :rules="rules" ref="formRef" label-width="100px">
|
|
|
<el-form-item label="窨井编码" prop="manholeCode">
|
|
|
<el-input v-model="formData.manholeCode" placeholder="请输入窨井编码" />
|
|
|
</el-form-item>
|
|
|
@@ -108,15 +114,17 @@
|
|
|
<el-input v-model="formData.manholeName" placeholder="请输入窨井名称" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="关联管网">
|
|
|
- <el-input v-model="formData.networkId" placeholder="请输入管网设施ID" />
|
|
|
+ <el-select v-model="formData.networkId" placeholder="请选择管网" clearable style="width: 100%">
|
|
|
+ <el-option v-for="n in networkOptions" :key="n.networkId" :label="`${n.networkName}(${n.networkCode})`" :value="n.networkId" />
|
|
|
+ </el-select>
|
|
|
</el-form-item>
|
|
|
- <el-form-item label="位置描述">
|
|
|
+ <el-form-item label="位置描述" prop="location">
|
|
|
<el-input v-model="formData.location" placeholder="请输入位置描述" />
|
|
|
</el-form-item>
|
|
|
- <el-form-item label="经度">
|
|
|
+ <el-form-item label="经度" prop="longitude">
|
|
|
<el-input-number v-model="formData.longitude" :precision="10" :step="0.0001" style="width: 100%" />
|
|
|
</el-form-item>
|
|
|
- <el-form-item label="纬度">
|
|
|
+ <el-form-item label="纬度" prop="latitude">
|
|
|
<el-input-number v-model="formData.latitude" :precision="10" :step="0.0001" style="width: 100%" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="深度(米)">
|
|
|
@@ -151,12 +159,12 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { ref, reactive, computed, onMounted, nextTick, watch } from 'vue'
|
|
|
+import { ref, reactive, computed, onMounted, nextTick, watch, onBeforeUnmount } from 'vue'
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
import {
|
|
|
getManholePage, addManhole, updateManhole, deleteManhole,
|
|
|
getManholeDevices, addManholeDeviceRel, deleteManholeDeviceRel,
|
|
|
- getEquipmentList
|
|
|
+ getEquipmentList, getPipeNetworkOptions
|
|
|
} from '@/api/pipeNetwork/basic'
|
|
|
import { getDicts } from '@/api/system/dict/data'
|
|
|
|
|
|
@@ -176,9 +184,17 @@ const formData = reactive({
|
|
|
location: '', longitude: null, latitude: null, manholeDepth: null,
|
|
|
manholeShape: '', material: '', ownershipUnit: '', status: '0', remark: ''
|
|
|
})
|
|
|
+const rules = {
|
|
|
+ manholeCode: [{ required: true, message: '请输入窨井编码', trigger: 'blur' }],
|
|
|
+ manholeName: [{ required: true, message: '请输入窨井名称', trigger: 'blur' }],
|
|
|
+ longitude: [{ required: true, message: '请输入经度', trigger: 'blur' }],
|
|
|
+ latitude: [{ required: true, message: '请输入纬度', trigger: 'blur' }],
|
|
|
+ location: [{ required: true, message: '请输入位置描述', trigger: 'blur' }]
|
|
|
+}
|
|
|
|
|
|
const pipeNetworkStatusDict = ref([])
|
|
|
const manholeShapeDict = ref([])
|
|
|
+const networkOptions = ref([])
|
|
|
|
|
|
const deviceDialogVisible = ref(false)
|
|
|
const currentManhole = reactive({ manholeId: '', manholeName: '' })
|
|
|
@@ -194,6 +210,10 @@ function getDictLabel(dict, value) {
|
|
|
const item = dict.find(d => d.dictValue === value)
|
|
|
return item ? item.dictLabel : value
|
|
|
}
|
|
|
+function getNetworkName(networkId) {
|
|
|
+ const found = networkOptions.value.find(n => n.networkId === networkId)
|
|
|
+ return found ? found.networkName : networkId
|
|
|
+}
|
|
|
|
|
|
async function loadDicts() {
|
|
|
const [statusRes, shapeRes] = await Promise.all([
|
|
|
@@ -210,23 +230,37 @@ async function loadData() {
|
|
|
const res = await getManholePage(pageNum.value, pageSize.value, searchForm)
|
|
|
tableData.value = res.data.records || []
|
|
|
total.value = res.data.total || 0
|
|
|
+ if (viewMode.value === 'map' && mapInitialized) { renderMarkers() }
|
|
|
} catch (e) { console.error(e) } finally { loading.value = false }
|
|
|
}
|
|
|
|
|
|
function handleSearch() { pageNum.value = 1; loadData() }
|
|
|
function handleReset() { Object.assign(searchForm, { manholeName: '', manholeCode: '', status: '' }); handleSearch() }
|
|
|
+async function loadNetworkOptions() {
|
|
|
+ if (networkOptions.value.length > 0) return
|
|
|
+ try {
|
|
|
+ const res = await getPipeNetworkOptions()
|
|
|
+ networkOptions.value = res.data || []
|
|
|
+ } catch (e) { console.error(e) }
|
|
|
+}
|
|
|
function handleAdd() {
|
|
|
dialogTitle.value = '新增'
|
|
|
Object.assign(formData, { manholeId: '', manholeCode: '', manholeName: '', networkId: '', location: '', longitude: null, latitude: null, manholeDepth: null, manholeShape: '', material: '', ownershipUnit: '', status: '0', remark: '' })
|
|
|
dialogVisible.value = true
|
|
|
+ loadNetworkOptions()
|
|
|
}
|
|
|
-function handleEdit(row) { dialogTitle.value = '编辑'; Object.assign(formData, row); dialogVisible.value = true }
|
|
|
+function handleEdit(row) { dialogTitle.value = '编辑'; Object.assign(formData, row); dialogVisible.value = true; loadNetworkOptions() }
|
|
|
async function handleSubmit() {
|
|
|
+ const valid = await formRef.value.validate().catch(() => false)
|
|
|
+ if (!valid) return
|
|
|
try {
|
|
|
if (formData.manholeId) { await updateManhole(formData); ElMessage.success('修改成功') }
|
|
|
else { await addManhole(formData); ElMessage.success('新增成功') }
|
|
|
dialogVisible.value = false; loadData()
|
|
|
- } catch (e) { console.error(e) }
|
|
|
+ } catch (e) {
|
|
|
+ const msg = e?.response?.data?.msg || e?.message || '操作失败'
|
|
|
+ ElMessage.error(msg)
|
|
|
+ }
|
|
|
}
|
|
|
function handleDelete(row) {
|
|
|
ElMessageBox.confirm('确认删除该窨井信息?', '提示', { type: 'warning' }).then(async () => {
|
|
|
@@ -302,22 +336,91 @@ function handleUnbind(dev) {
|
|
|
}).catch(() => {})
|
|
|
}
|
|
|
|
|
|
+let mapInstance = null
|
|
|
+let mapInitialized = false
|
|
|
+const mapError = ref('')
|
|
|
+
|
|
|
+function waitForBMapGL() {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ if (window.BMapGL) { resolve(window.BMapGL); return }
|
|
|
+ let attempts = 0
|
|
|
+ const timer = setInterval(() => {
|
|
|
+ attempts++
|
|
|
+ if (window.BMapGL) { clearInterval(timer); resolve(window.BMapGL); return }
|
|
|
+ if (attempts >= 80) { clearInterval(timer); reject(new Error('百度地图加载超时')) }
|
|
|
+ }, 200)
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
async function initMap() {
|
|
|
await nextTick()
|
|
|
const el = document.getElementById('manholeMap')
|
|
|
- if (!el) return
|
|
|
- /* try {
|
|
|
- const L = await import('leaflet')
|
|
|
+ if (!el || mapInitialized) return
|
|
|
+
|
|
|
+ try {
|
|
|
+ const BMapGL = await waitForBMapGL()
|
|
|
+ mapInstance = new BMapGL.Map(el, { enableMapClick: true })
|
|
|
+ const center = tableData.value.length > 0 && tableData.value[0].longitude
|
|
|
+ ? [Number(tableData.value[0].longitude), Number(tableData.value[0].latitude)]
|
|
|
+ : [110.3965, 28.4638]
|
|
|
+ mapInstance.centerAndZoom(new BMapGL.Point(center[0], center[1]), 15)
|
|
|
+ mapInstance.enableScrollWheelZoom(true)
|
|
|
+ mapInitialized = true
|
|
|
+ renderMarkers()
|
|
|
} catch (e) {
|
|
|
- el.innerHTML = '<div style="display:flex;align-items:center;justify-content:center;height:100%;color:#999;">地图加载需要Leaflet依赖,请安装: npm install leaflet</div>'
|
|
|
- }*/
|
|
|
+ console.error(e)
|
|
|
+ mapError.value = '百度地图加载失败,请刷新页面重试'
|
|
|
+ }
|
|
|
}
|
|
|
-watch(viewMode, (v) => { if (v === 'map') initMap() })
|
|
|
|
|
|
-onMounted(async () => { await loadDicts(); loadData() })
|
|
|
+function renderMarkers() {
|
|
|
+ if (!mapInstance || typeof BMapGL === 'undefined') return
|
|
|
+ try { mapInstance.clearOverlays() } catch (_) {}
|
|
|
+
|
|
|
+ const data = tableData.value.filter(m => m.longitude && m.latitude)
|
|
|
+ if (data.length === 0) return
|
|
|
+
|
|
|
+ data.forEach(m => {
|
|
|
+ const lng = Number(m.longitude)
|
|
|
+ const lat = Number(m.latitude)
|
|
|
+ const pt = new BMapGL.Point(lng, lat)
|
|
|
+ const marker = new BMapGL.Marker(pt)
|
|
|
+ mapInstance.addOverlay(marker)
|
|
|
+
|
|
|
+ const shapeLabel = getDictLabel(manholeShapeDict.value, m.manholeShape)
|
|
|
+ const statusLabel = getDictLabel(pipeNetworkStatusDict.value, m.status)
|
|
|
+ const html = `<div style="font-size:13px;line-height:1.8;max-width:260px;">
|
|
|
+ <b>${m.manholeName}</b><br/>
|
|
|
+ 编码:${m.manholeCode}<br/>
|
|
|
+ 位置:${m.location || '-'}<br/>
|
|
|
+ 深度:${m.manholeDepth != null ? m.manholeDepth + 'm' : '-'}<br/>
|
|
|
+ 形状:${shapeLabel}<br/>
|
|
|
+ 材质:${m.material || '-'}<br/>
|
|
|
+ 状态:${statusLabel}
|
|
|
+ </div>`
|
|
|
+
|
|
|
+ marker.addEventListener('click', () => {
|
|
|
+ const infoWindow = new BMapGL.InfoWindow(html, { width: 240 })
|
|
|
+ mapInstance.openInfoWindow(infoWindow, pt)
|
|
|
+ })
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+watch(viewMode, (v) => { if (v === 'map') { initMap() } else { mapInitialized = false } })
|
|
|
+
|
|
|
+onMounted(async () => { await loadDicts(); loadData(); loadNetworkOptions() })
|
|
|
+
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ if (mapInstance) {
|
|
|
+ try { mapInstance.destroy() } catch (_) {}
|
|
|
+ mapInstance = null
|
|
|
+ mapInitialized = false
|
|
|
+ }
|
|
|
+})
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
.manhole-container { padding: 16px; }
|
|
|
.search-card { margin-bottom: 16px; }
|
|
|
+.map-card { position: relative; }
|
|
|
</style>
|