提交 dfadc655 作者: 吴佳伟

fix: 农场地图增加农场和基地的区域渲染

上级 a9b217aa
......@@ -27,7 +27,7 @@
})
const showDialog = ref(false)
onShow(() => {
getFarmbaseInfoList()
// getFarmbaseInfoList()
})
const model = reactive({
......@@ -91,6 +91,44 @@
farmbaseApi.getFarmbaseInfoById({ id }).then((res) => {
model.farmbaseInfo = res
getDeviceTypeCount()
// 切换基地后,将地图视角飞到当前基地上方
let geojson = res.geojson
if (typeof geojson === 'string') {
try {
geojson = JSON.parse(geojson)
} catch (e) {
geojson = null
}
}
if (geojson) {
// 直接从 geometry 坐标计算中心点和缩放范围
const coords = geojson.features?.[0]?.geometry?.coordinates?.[0]
if (coords && coords.length > 0) {
let minLon = Infinity, minLat = Infinity, maxLon = -Infinity, maxLat = -Infinity
for (const c of coords) {
if (c[0] < minLon) minLon = c[0]
if (c[0] > maxLon) maxLon = c[0]
if (c[1] < minLat) minLat = c[1]
if (c[1] > maxLat) maxLat = c[1]
}
const center: [number, number] = [(minLon + maxLon) / 2, (minLat + maxLat) / 2]
// 使用 flyTo 而非 fitBounds,避免 maxBounds 约束干扰
map.flyTo({
center,
zoom: 15,
duration: 1000,
})
}
} else if (res.longitude && res.latitude) {
map.flyTo({
center: [Number(res.longitude), Number(res.latitude)],
zoom: 15,
duration: 1000,
})
} else {
console.warn('切换基地: 既没有geojson也没有经纬度')
}
})
}
......@@ -108,101 +146,233 @@
// 查询农场数据
const res = await NongchangAPI.farmsList()
console.log('农场列表', res.records)
if (!res.records || res.records.length === 0) {
Message.toast('未查询到农场信息')
return
}
// 获取第一个农场信息
const item = res.records?.[0]
model.id = item.id
model.name = item.farmName
model.description = item.description
if (item.longitude && item.latitude) {
model.lonlat = `${item.longitude},${item.latitude}`
} else {
// 模拟位置数据
model.lonlat = '111.024108, 29.554847'
Message.toast('未设置农场坐标位置,已使用模拟位置数据')
}
// 设置页面标题
uni.setNavigationBarTitle({
title: item.farmName,
})
// 设置地图中心点
map.flyTo({
center: model.lonlat.split(',').map(Number) as [number, number],
duration: 0,
})
// 渲染地块数据
model.plots = [
turf.polygon(
[
[
[111.0235, 29.5562],
[111.0255, 29.5562],
[111.0255, 29.5558],
[111.0235, 29.5558],
[111.0235, 29.5562],
],
],
{
color: 'yellow',
name: '基地 A',
popup: `{{name}}`,
// 渲染农场和基地地块数据
let farmGeojson = item.geojson
// geojson 可能是字符串,需要解析
if (typeof farmGeojson === 'string') {
try {
farmGeojson = JSON.parse(farmGeojson)
} catch (e) {
console.error('解析农场 geojson 失败:', e)
farmGeojson = null
}
}
if (farmGeojson) {
const farmFeatures = farmGeojson.features ? farmGeojson.features : [farmGeojson]
// 注入农场名称到每个 feature
for (const feature of farmFeatures) {
feature.properties = feature.properties || {}
feature.properties.farmName = item.farmName
}
addDefaultGeoJSONSource(map, `${page.id}-farm-plot`, farmFeatures)
// 添加农场填充层
map.addLayer({
type: 'fill',
id: `${page.id}-farm-plot-fill`,
source: `${page.id}-farm-plot`,
paint: {
'fill-color': '#5db66f',
'fill-opacity': 0.2,
'fill-outline-color': '#5db66f',
},
),
turf.polygon(
[
[
[111.0225, 29.5565],
[111.0238, 29.5568],
[111.023, 29.5555],
[111.022, 29.5558],
[111.0225, 29.5565],
],
],
{
color: 'red',
name: '基地 B',
popup: `{{name}}`,
})
map.addLayer({
type: 'line',
id: `${page.id}-farm-plot-line`,
source: `${page.id}-farm-plot`,
layout: {
'line-join': 'round',
'line-cap': 'round',
},
),
turf.polygon(
[
[
[111.0258, 29.555],
[111.0262, 29.5542],
[111.0252, 29.554],
[111.0258, 29.555],
],
],
{
color: 'blue',
name: '基地 C',
popup: `{{name}}`,
paint: {
'line-color': '#5db66f',
'line-width': 4,
},
),
})
// 添加农场名称文字标签(已禁用)
// map.addLayer({
// type: 'symbol',
// id: `${page.id}-farm-label`,
// source: `${page.id}-farm-plot`,
// layout: {
// 'text-field': ['get', 'farmName'],
// 'text-size': 16,
// 'text-anchor': 'center',
// 'text-allow-overlap': true,
// },
// paint: {
// 'text-color': '#ffffff',
// 'text-halo-color': '#5db66f',
// 'text-halo-width': 2,
// },
// })
} else {
console.warn('农场没有 geojson 数据, item:', JSON.stringify(item)?.substring(0, 500))
}
// 查询农场基地信息
const farmbaseRes = await farmbaseApi.list({ farmId: model.id })
const farmbaseRecords = farmbaseRes.records || []
model.farmbaseInfoList = farmbaseRecords
// 预定义颜色池(每个基地循环使用)
const colorPool = [
{ fill: '#e74c3c', line: '#e74c3c' }, // 红
{ fill: '#3498db', line: '#3498db' }, // 蓝
{ fill: '#2ecc71', line: '#2ecc71' }, // 绿
{ fill: '#f1c40f', line: '#f1c40f' }, // 黄
{ fill: '#9b59b6', line: '#9b59b6' }, // 紫
{ fill: '#e67e22', line: '#e67e22' }, // 橙
{ fill: '#1abc9c', line: '#1abc9c' }, // 青
{ fill: '#e91e63', line: '#e91e63' }, // 粉
]
addDefaultGeoJSONSource(map, `${page.id}-plot`, model.plots)
addDefaultSplotLayer(map, `${page.id}-plot`, {
paint: {
'fill-opacity': 0.2,
'fill-outline-color': ['get', 'color'],
},
})
map.addLayer({
type: 'line',
id: `${page.id}-plot-line`,
source: `${page.id}-plot`,
layout: {
'line-join': 'round',
'line-cap': 'round',
},
paint: {
'line-color': ['get', 'color'],
'line-width': 2,
},
})
// 为每个基地创建独立的 source 和 layer
for (let i = 0; i < farmbaseRecords.length; i++) {
const base = farmbaseRecords[i]
let geojson = base.geojson
// geojson 可能是字符串,需要解析
if (typeof geojson === 'string') {
try {
geojson = JSON.parse(geojson)
} catch (e) {
console.error(`解析基地 ${base.baseName} geojson 失败:`, e)
continue
}
}
if (!geojson) continue
// 为当前基地分配颜色
const color = colorPool[i % colorPool.length]
const sourceId = `${page.id}-base-plot-${base.id}`
const fillLayerId = `${sourceId}-fill`
const lineLayerId = `${sourceId}-line`
const labelLayerId = `${sourceId}-label`
// 处理 geojson,注入基地名称属性
const features = geojson.features ? geojson.features : [geojson]
for (const feature of features) {
feature.properties = feature.properties || {}
feature.properties.baseName = base.baseName
}
// 添加 source
addDefaultGeoJSONSource(map, sourceId, features)
// 添加填充层(直接创建,不使用 addDefaultSplotLayer)
map.addLayer({
type: 'fill',
id: fillLayerId,
source: sourceId,
paint: {
'fill-color': color.fill,
'fill-opacity': 0.5,
'fill-outline-color': color.line,
},
})
// 添加边框层
map.addLayer({
type: 'line',
id: lineLayerId,
source: sourceId,
layout: {
'line-join': 'round',
'line-cap': 'round',
},
paint: {
'line-color': color.line,
'line-width': 3,
},
})
// 添加基地名称文字标签
map.addLayer({
type: 'symbol',
id: labelLayerId,
source: sourceId,
layout: {
'text-field': ['get', 'baseName'],
'text-size': 14,
'text-anchor': 'center',
'text-offset': [0, 0],
'text-allow-overlap': true,
},
paint: {
'text-color': '#ffffff',
'text-halo-color': color.line,
'text-halo-width': 2,
},
})
}
// 将地图视角飞到第一个基地的上方
if (farmbaseRecords.length > 0) {
const firstBase = farmbaseRecords[0]
model.farmbaseInfo = firstBase
let firstGeojson = firstBase.geojson
if (typeof firstGeojson === 'string') {
try {
firstGeojson = JSON.parse(firstGeojson)
} catch (e) {
firstGeojson = null
}
}
if (firstGeojson) {
const coords = firstGeojson.features?.[0]?.geometry?.coordinates?.[0]
if (coords && coords.length > 0) {
let minLon = Infinity, minLat = Infinity, maxLon = -Infinity, maxLat = -Infinity
for (const c of coords) {
if (c[0] < minLon) minLon = c[0]
if (c[0] > maxLon) maxLon = c[0]
if (c[1] < minLat) minLat = c[1]
if (c[1] > maxLat) maxLat = c[1]
}
map.flyTo({
center: [(minLon + maxLon) / 2, (minLat + maxLat) / 2],
zoom: 15,
duration: 0,
})
}
} else if (firstBase.longitude && firstBase.latitude) {
map.flyTo({
center: [Number(firstBase.longitude), Number(firstBase.latitude)],
zoom: 15,
duration: 0,
})
}
}
getDeviceTypeCount()
// 如果农场没有 geojson 但有坐标,则使用坐标定位
if (!farmGeojson && item.longitude && item.latitude) {
model.lonlat = `${item.longitude},${item.latitude}`
} else if (!farmGeojson && !item.longitude) {
model.lonlat = '111.024108, 29.554847'
Message.toast('未设置农场坐标位置,已使用模拟位置数据')
}
// 渲染设备数据
// 渲染设备数据
model.devices = [
......@@ -233,9 +403,6 @@
'icon-size': 1,
},
})
// 查询农场信息
getFarmbaseInfoList()
},
onSourceRequestHandle: () => {
page.requests--
......@@ -248,28 +415,6 @@
},
})
/* const mapAddImage = new Image();
mapAddImage.src = '/static/images/test/mapLayer.png';
// 添加自定义图像图层
map.on('load','custom-image',()=>{
console.log("进到自定义的地图里了")
// 添加图片资源
map.addImage('custom-image', mapAddImage, { pixelRatio: 2 }); // 确保路径正确且图片可访问
// 添加图层到地图上,并指定位置和大小
map.addLayer({
id: 'custom-image-layer', // 图层的唯一ID
type: 'raster', // 或者使用 'raster' 根据需要选择类型
source: {
type: 'image', // 指定源类型为图像
url: '/static/images/test/mapLayer.png' // 同上,确保路径正确
},
layout: {
'icon-image': 'custom-image', // 使用上面添加的图片ID
'icon-anchor': 'center' // 设置锚点为图片中心,根据需要调整
}
});
}) */
// 左侧工具栏小部件
const [registerToolBoxWidget] = useToolBoxWidget({
show: true,
......@@ -379,7 +524,6 @@ map.on('load','custom-image',()=>{
}
// 保留原有的导航栏按钮点击回调(如果有需要的话)
onNavigationBarButtonTap((e) => {
console.log(e)
if (e.index === 0) {
Navigate.to(`/pages/jidiguanli/add?farmId=${model.id}`)
}
......@@ -509,6 +653,7 @@ map.on('load','custom-image',()=>{
</view>
</view>
<view class="box-3">
<!-- 基地切换 -->
<view class="box-3-tags">
<view
class="box-3-tags-item"
......@@ -898,9 +1043,12 @@ map.on('load','custom-image',()=>{
display: flex;
flex-direction: row;
font-size: 28rpx;
overflow-x: auto;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
.box-3-tags-item {
width: 31%;
display: inline-block;
height: 100%;
margin-right: 20rpx;
text-align: center;
......@@ -909,6 +1057,8 @@ map.on('load','custom-image',()=>{
background-color: rgba($color: #5db66f, $alpha: 0.1);
color: #5db66f;
font-weight: 300;
padding: 0 30rpx;
flex-shrink: 0;
}
.box-3-tags-item-active {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论