新增全部导出功能

This commit is contained in:
yiqiuyang
2025-10-13 11:33:48 +08:00
parent 31f8c849b8
commit 7dca973b3b

View File

@ -4,7 +4,9 @@
<div class="images flex a-c" v-for="item in imagesList" :key="item.id">
<img :src="item.src" @click="drawRectangle" />
<el-button class="form-btn" type="primary" size="mini" @click="analyzeAverageSlope">确定</el-button>
<el-button class="form-btn right" type="primary" size="mini" @click="dialogVisible = true">导出</el-button>
<el-button class="form-btn right" type="primary" size="mini" :disabled="showExport" @click="clickExport">
导出
</el-button>
</div>
</div>
@ -62,7 +64,7 @@
</div>
<!-- 地图 -->
<div class="center" id="cesiumContainer"></div>
<div class="center" id="cesiumContainer" v-loading="mapLoading" :element-loading-text="mapLoadText"></div>
<div class="right flex column" v-loading="showLoading" element-loading-text="数据加载中">
<!-- 路点 -->
@ -105,6 +107,8 @@
<!-- 导出界面 -->
<el-dialog :visible.sync="dialogVisible" title="导出目录" width="90%" top="10vh">
<el-tabs v-model="activeName" type="card">
<el-tab-pane v-for="(item, index) in tabs" :label="item.label" :name="item.id">
<div class="road flex j-s a-c">
<!-- 道路附属点 -->
<div class="point">
@ -114,8 +118,8 @@
</div>
<vxe-table
class="item"
ref="roadPointListREF"
:data="exportList.roadPointList"
:ref="`${item.id}_roadPointListREF`"
:data="currentTabList.roadPointList"
align="center"
:height="tableHeight"
:row-config="{isCurrent: true, isHover: true, keyField: 'seq'}"
@ -157,8 +161,8 @@
</div>
<vxe-table
class="item"
ref="roadLineListREF"
:data="exportList.roadLineList"
:ref="`${item.id}_roadLineListREF`"
:data="currentTabList.roadLineList"
align="center"
:height="tableHeight"
:row-config="{isCurrent: true, isHover: true, keyField: 'seq'}"
@ -202,8 +206,8 @@
</div>
<vxe-table
class="item"
ref="waterPointListREF"
:data="exportList.waterPointList"
:ref="`${item.id}_waterPointListREF`"
:data="currentTabList.waterPointList"
align="center"
:height="tableHeight"
:row-config="{isCurrent: true, isHover: true, keyField: 'seq'}"
@ -245,8 +249,8 @@
</div>
<vxe-table
class="item"
ref="waterLineListREF"
:data="exportList.waterLineList"
:ref="`${item.id}_waterLineListREF`"
:data="currentTabList.waterLineList"
align="center"
:height="tableHeight"
:row-config="{isCurrent: true, isHover: true, keyField: 'seq'}"
@ -280,6 +284,8 @@
</vxe-table>
</div>
</div>
</el-tab-pane>
</el-tabs>
<div slot="footer" class="dialog-footer">
<el-button size="mini" @click="dialogVisible = false">取消</el-button>
@ -294,6 +300,7 @@
import {getStorage} from '@/utils/localStorage'
import plantJson from '/public/config/plant.json'
import soilJson from '/public/config/soil.json'
import FileSaver from 'file-saver'
import axios from 'axios'
import iniParser from 'ini-parser'
@ -307,7 +314,8 @@ export default {
roadLineList: [],
waterPointList: [],
waterLineList: [],
mapLoading: true,
mapLoadText: '地图数据加载中',
form: {
leftTop: '',
rightBottom: '',
@ -345,20 +353,26 @@ export default {
roadWaterLock: false,
dialogVisible: false,
rectTotalScore: '0.31',
exportList: {
roadPointList: [],
roadLineList: [],
waterPointList: [],
waterLineList: [],
},
tabs: [],
tabList: [],
rectTotalScore: '',
activeName: '',
tableHeight: 280,
// showExport: true,
showExport: false,
}
},
created() {
this._polyCache = new WeakMap()
},
mounted() {
this.getMapJson()
this.getColorList()
},
computed: {
// 示例区域:矩形四个角点
positions() {
@ -371,11 +385,12 @@ export default {
[a[0], a[1]],
]
},
},
mounted() {
this.getMapJson()
this.getColorList()
// 导出目录的当前 tab
currentTabList() {
let list = this.tabList.find((item) => item.id === this.activeName)
return list[list?.key]
},
},
beforeDestroy() {
@ -400,6 +415,9 @@ export default {
this.plantJson = plantJson
this.soilJson = soilJson
this.initMarsMap()
setTimeout(() => {
this.mapLoading = false
}, 1000)
})
},
@ -431,8 +449,10 @@ export default {
return
}
// 清除现有矩形
this.clearRectangles()
if (this.polygon && (uploadedJson?.leftTop || uploadedJson?.rightBottom)) {
window.graphicLayer.removeGraphic(this.polygon)
this.polygon = null
}
this.form.leftTop = uploadedJson.leftTop
@ -457,7 +477,13 @@ export default {
window.viewer.addLayer(window.graphicLayer)
window.shortestPathLayer = new window.mars3d.layer.GraphicLayer()
window.viewer.addLayer(window.shortestPathLayer)
// 添加地图点击事件监听,用于结束绘制
window.viewer.on(mars3d.EventType.dblClick, (event) => {
// 如果正在绘制,点击地图可以结束绘制(除了绘制点)
window.graphicLayer.stopDraw()
this.form.leftTop = ''
this.form.rightBottom = ''
})
this.loadGeoJson()
},
@ -726,6 +752,7 @@ export default {
this.clearRectangles()
if (this.polygon) {
window.graphicLayer.removeGraphic(this.polygon)
this.polygon = null
}
this.isHand = true
let isEntityGraphic = false
@ -750,6 +777,7 @@ export default {
drawInitialArea() {
// 如果多边形尚未创建,则创建它
if (!this.polygon) {
console.log('this.positions===>', this.positions)
this.polygon = new mars3d.graphic.PolygonEntity({
positions: this.positions.map((p) => Cesium.Cartesian3.fromDegrees(p[0], p[1], 0)),
style: {
@ -809,21 +837,22 @@ export default {
if (!this.form.leftTop || !this.form.rightBottom) {
return this.$message.warning('请选择范围!')
}
console.log('开始坡度分析')
this.mapLoading = true
this.$message.success('开始分析')
this.mapLoadText = '坡度分析中'
this.analyzing = true
this.selectedRect = null
// 清除之前的矩形
this.clearRectangles()
console.log('this.rectangles===>', this.rectangles)
// 获取分割参数
const xSplit = parseInt(this.form.xLength) || 3
const ySplit = parseInt(this.form.yLength) || 3
// 计算区域边界
console.log('this.positions===>', this.positions)
const lats = this.positions.map((p) => p[1])
const lngs = this.positions.map((p) => p[0])
const minLat = Math.min(...lats)
@ -927,6 +956,7 @@ export default {
} catch (e) {
console.error('坡度分析失败', e)
this.$message.error('坡度分析失败,请检查地形数据')
this.mapLoading = false
} finally {
rectInfoMap.clear()
this.drawLabelAndRec()
@ -941,6 +971,7 @@ export default {
const len = list.length
if (!len) {
this.$message.success('计算结束,暂无符合条件的区域!')
this.mapLoading = false
return
}
@ -952,7 +983,6 @@ export default {
const b = list[i]
const color = this.getColors(list[i].totalScore)
/* 2.1 面要素 options */
rectOpts.push({
id: b.id,
positions: Cesium.Cartesian3.fromDegreesArray(b.positions.flat()),
@ -962,29 +992,42 @@ export default {
outline: true,
outlineColor: '#ffffff',
outlineWidth: 1,
// 关键设置:启用填充并设置填充颜色
fill: true,
material: color, // 使用相同的颜色作为填充材质
// 提高填充的优先级,确保可以点击
material: color,
classificationType: Cesium.ClassificationType.BOTH,
},
center: new mars3d.LngLatPoint(b.center[0], b.center[1], 0),
// 添加自定义属性,用于事件识别
attr: {
isRectangle: true,
originalData: b,
},
// 关键设置:启用深度测试和拾取
depthTestAgainstTerrain: false, // 禁用地形深度测试
allowPicking: true, // 确保允许拾取
depthTestAgainstTerrain: false,
allowPicking: true,
})
/* 2.2 标签 options */
let tab = {
id: i + 1 + '',
key: b.totalScore,
[b.totalScore]: {
roadPointList: [],
roadLineList: [],
waterPointList: [],
waterLineList: [],
},
}
this.tabs.push({
id: i + 1 + '',
label: b.totalScore,
})
this.tabList.push(tab)
labelOpts.push({
id: `label_${b.id}`,
position: new mars3d.LngLatPoint(b.center[0], b.center[1], 0),
style: {
text: String(b.totalScore), // 必须字符串
text: String(b.totalScore),
font_size: 24,
font_family: '楷体',
color: '#000000',
@ -993,10 +1036,8 @@ export default {
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
visibleDepth: false,
scaleByDistance: true,
// 禁用标签的拾取,让点击事件穿透到矩形
disablePicking: true, // 关键设置
disablePicking: true,
},
// 添加自定义属性,用于事件识别
attr: {
isLabel: true,
relatedRectId: b.id,
@ -1004,33 +1045,39 @@ export default {
})
}
/* 3. 批量创建 Graphic底层一次性构造避免反复 new */
this.rectangles = rectOpts.map((opt) => new mars3d.graphic.PolygonEntity(opt))
this.activeName = this.tabs[0].id
console.log('this.rectangles===>', this.rectangles, this.rectangles.length)
this.labels = labelOpts.map((opt) => new mars3d.graphic.LabelEntity(opt))
/* 4. 一次性添加到图层mars3d 支持数组)*/
window.graphicLayer.addGraphic(this.rectangles)
window.graphicLayer.addGraphic(this.labels)
/* 5. 图层级事件委托:只监听矩形图形的点击事件 */
window.graphicLayer.off(mars3d.EventType.click, this._selectRect, this) // 先清旧监听
window.graphicLayer.off(mars3d.EventType.click, this._selectRect, this)
// 为每个矩形图形单独绑定点击事件
this.rectangles.forEach((rectGraphic) => {
rectGraphic.on(mars3d.EventType.click, (event) => {
this._selectRect(event)
})
})
/* 6. 事件处理函数 */
this._selectRect = (event) => {
const graphic = event.graphic
// 确保只有矩形图形会触发选择
if (graphic && graphic.attr && graphic.attr.isRectangle) {
this.selectRectangle(graphic)
}
}
if (!this.roadWaterLock) {
this.loadLayers(['roadPoint', 'roadLine', 'waterPoint', 'waterLine'], (results) => {
this.roadWaterLock = true
this.$message.success(`计算成功!共有${len}个符合条件的区域`)
this.showExport = false
this.mapLoading = false
})
} else {
this.mapLoading = false
}
},
/**
@ -1132,28 +1179,27 @@ export default {
center: rect.center,
}
this.rectTotalScore = rect.attr.originalData.totalScore
this.roadPointList = []
this.roadLineList = []
this.waterPointList = []
this.waterLineList = []
this.exportList.roadPointList = []
this.exportList.roadLineList = []
this.exportList.waterPointList = []
this.exportList.waterLineList = []
if (!this.roadWaterLock) {
this.loadLayers(['roadPoint', 'roadLine', 'waterPoint', 'waterLine'], (results) => {
this.roadWaterLock = true
this.getRoadWaterIds(rect)
})
} else {
this.getRoadWaterIds(rect)
// 清除tablist中原本存在的数据
let tabIndex = this.tabList.findIndex((item) => item.key === this.rectTotalScore)
if (tabIndex !== -1) {
this.tabList[tabIndex][this.rectTotalScore].roadPointList = []
this.tabList[tabIndex][this.rectTotalScore].roadLineList = []
this.tabList[tabIndex][this.rectTotalScore].waterPointList = []
this.tabList[tabIndex][this.rectTotalScore].waterLineList = []
}
this.rectTotalScore = rect.attr.originalData.totalScore
this.getRoadWaterIds(rect, tabIndex)
},
getRoadWaterIds(rect) {
// 获取相交的道路和水路
getRoadWaterIds(rect, tabIndex) {
const positions = rect.points.map((d) => [d.lng, d.lat])
let roadPointId = this.getIntersectId(positions, this.layers['roadPoint'].layer)
@ -1163,39 +1209,58 @@ export default {
if (roadPointId) {
this.roadPointList.push(this.layers['roadPoint'].layer.getGraphicById(roadPointId).options.attr)
this.exportList.roadPointList.push(this.layers['roadPoint'].layer.getGraphicById(roadPointId).options.attr)
this.tabList[tabIndex][this.rectTotalScore].roadPointList.push(
this.layers['roadPoint'].layer.getGraphicById(roadPointId).options.attr
)
} else if (roadLineId) {
this.roadLineList.push(this.layers['roadLine'].layer.getGraphicById(roadLineId).options.attr)
this.exportList.roadLineList.push(this.layers['roadLine'].layer.getGraphicById(roadLineId).options.attr)
this.tabList[tabIndex][this.rectTotalScore].roadLineList.push(
this.layers['roadLine'].layer.getGraphicById(roadLineId).options.attr
)
} else if (waterPointId) {
this.waterPointList.push(this.layers['waterPoint'].layer.getGraphicById(waterPointId).options.attr)
this.exportList.waterPointList.push(this.layers['waterPoint'].layer.getGraphicById(waterPointId).options.attr)
this.tabList[tabIndex][this.rectTotalScore].waterPointList.push(
this.layers['waterPoint'].layer.getGraphicById(waterPointId).options.attr
)
} else if (waterLineId) {
this.waterLineList.push(this.layers['waterLine'].layer.getGraphicById(waterLineId).options.attr)
this.exportList.waterLineList.push(this.layers['waterLine'].layer.getGraphicById(waterLineId).options.attr)
this.tabList[tabIndex][this.rectTotalScore].waterLineList.push(
this.layers['waterLine'].layer.getGraphicById(waterLineId).options.attr
)
}
},
// 点击导出按钮
clickExport() {
this.rectangles.forEach((rectGraphic) => {
this.selectRectangle(rectGraphic)
})
this.dialogVisible = true
},
// 导出为 JSON文件
exportJSON() {
// const data = JSON.stringify(this.tabList)
// FileSaver.saveAs(new Blob([data], {type: 'application/json'}), 'data.json')
try {
let file = {
id: 1,
[this.rectTotalScore]: this.exportList,
}
fetch('./config.ini')
.then((r) => r.text())
.then((res) => {
const parsedData = iniParser.parse(res)
this.$alert(parsedData)
axios
.post(`http://${parsedData.http.address}:${parsedData.http.port}/api/area`, JSON.stringify(file), {
.post(
`http://${parsedData.http.address}:${parsedData.http.port}/api/area`,
JSON.stringify(this.tabList),
{
headers: {'Content-Type': 'application/json'},
})
}
)
.then((res) => {
this.$alert(res)
// this.$message.success(res)
// this.$message.success('导出成功!')
this.$message.success(res)
this.$message.success('导出成功!')
})
.catch((error) => {
this.$message.error(error)
@ -1208,30 +1273,38 @@ export default {
// 新增
handleAdd(type) {
let tabIndex = this.tabList.findIndex((item) => item.id === this.activeName)
let list = this.tabList[tabIndex]
const newRow = {
seq: this.exportList[type].length + 1,
seq: list[list.key][type].length + 1,
编码: '',
名称: '',
A: '',
editing: true,
}
this.exportList[type].push(newRow)
list[list.key][type].push(newRow)
setTimeout(() => {
this.$refs[`${type}REF`].refreshScroll()
this.$refs[`${type}REF`].scrollToRow(newRow, 'id')
this.$refs[`${this.activeName}_${type}REF`].refreshScroll()
this.$refs[`${this.activeName}_${type}REF`].scrollToRow(newRow, 'id')
}, 50)
},
handleEdit(row) {
this.$set(row, 'editing', true)
},
handleSave(row) {
this.$set(row, 'editing', false)
},
handleDelete(type, row) {
const index = this.exportList[type].findIndex((item) => item.id === row.id)
let tabIndex = this.tabList.findIndex((item) => item.id === this.activeName)
let list = this.tabList[tabIndex]
const index = list[list.key][type].findIndex((item) => item.id === row.id)
if (index !== -1) {
this.exportList[type].splice(index, 1)
list[list.key][type].splice(index, 1)
}
},
@ -1249,6 +1322,14 @@ export default {
window.graphicLayer.removeGraphic(this.labels)
this.labels = []
}
this.roadPointList = []
this.roadLineList = []
this.waterPointList = []
this.waterLineList = []
this.tabs = []
this.tabList = []
this.rectTotalScore = ''
this.activeName = ''
},
},
}