This commit is contained in:
linfso 2025-08-15 13:44:30 +08:00
parent 4cd1092ff2
commit 9b1b59dff5
5 changed files with 519 additions and 0 deletions

82
common/geo/XDGeoSdk.js Normal file
View File

@ -0,0 +1,82 @@
'use strict'
import * as turf from '@turf/turf';
import { deepClone } from '@/common/custom.js'
/*
中国边界数据 来源 阿里-高德
https://datav.aliyun.com/portal/school/atlas/area_selector
*/
import chinaBoundary from './china-boundary.json';
/*
XDGeoSdk
*/
class XDGeoSdk {
geoJson = null;
geoSimpleJson = null;
chinaPolygon = null;
chinaAreaBoundary = null;
chinaAreaMainLandBoundary = null;
chinaBox = null;
static instance = null;
constructor() {
this.instance = null
this.geoJson=chinaBoundary;
this.chinaAreaBoundary=deepClone(chinaBoundary.features[0].geometry.coordinates);
this.chinaAreaMainLandBoundary=this.chinaAreaBoundary[0][0];
this.chinaPolygon = chinaBoundary.features[0].geometry;
this.chinaBox=turf.bbox(this.chinaPolygon);
var options = {tolerance: 0.01, highQuality: false};
this.geoSimpleJson = turf.simplify(this.geoJson, options);
// console.log("===>this.chinaPolygon==>",this.chinaPolygon);
// console.log("===>geoSimpleJson==>",this.geoSimpleJson);
}
static getInstance() {
if (!this.instance) {
this.instance = new XDGeoSdk()
}
return this.instance
}
getChinaGeoJson(){
return this.geoJson;
// return this.geoSimpleJson;
}
getChinaPolygon(){
return this.chinaAreaBoundary;
}
getChinaMainLandPolygon(){
return this.chinaAreaMainLandBoundary;
}
isInChina(lat,lng) {
// [minLng, minLat, maxLng, maxLat]
const bbox = this.chinaBox;
const isInBbox = lng >= bbox[0] && lng <= bbox[2] && lat >= bbox[1] && lat <= bbox[3];
if (!isInBbox) {
return false;
}
const point = turf.point([lng, lat]);
const chinaPolygon = this.chinaPolygon;
let rst=turf.booleanPointInPolygon(point, chinaPolygon);
return rst;
}
}
export default XDGeoSdk;

File diff suppressed because one or more lines are too long

16
common/geo/chinaGeo.js Normal file
View File

@ -0,0 +1,16 @@
import XDGeoSdk from './XDGeoSdk';
const xdGeoSdk = XDGeoSdk.getInstance();
export function getChinaGeoJson() {
return xdGeoSdk.getChinaGeoJson();
}
export function getChinaPolygon() {
return xdGeoSdk.getChinaPolygon();
}
export function isInChina(lat,lng) {
return xdGeoSdk.isInChina(lat,lng)
}

View File

@ -0,0 +1,110 @@
<template>
<u-row justify="between">
<u-row @click="setClipboardData(modelInfo.billCode)">
<view>
<u-text v-if="modelInfo.billCode" :text="`运单号:${modelInfo.billCode}` " size="26"></u-text>
<u-text v-else :text="`订单号:${modelInfo.orderSn}` " size="26"></u-text>
</view>
<view class="pl-10">
<u-icon name="file-text" size="32" custom-style=""></u-icon>
</view>
</u-row>
<view>
<view v-if="showInfoBtn" @click="goto(`post/detail?billCode=${modelInfo.billCode}`)" class="com-tag-grey">
运单信息
</view>
<tpx-text-dic v-if="!showInfoBtn" :value="modelInfo.orderStatus" :list="dicData.emis_order_status" ></tpx-text-dic>
</view>
</u-row>
<view @click="goto(`post/detail?billCode=${modelInfo.billCode}`)">
<u-row custom-style="margin-top: 5rpx;" justify="center">
<u-col span="4">
<u-text :text="(sender.countryName + sender.provinceName)||'-'" size="30" :bold="true" align="center"></u-text>
<!-- <u-text :text="sender.name" size="26" color="#999" margin="20rpx 0 0 0"
align="center"></u-text> -->
</u-col>
<u-col span="4" justify="center" align="center" custom-style="text-align: center;">
<image style="width: 70rpx;height: 14rpx;" :src="getCdnUrl('post/toline.png')">
</image>
<!-- getCdnUrl('post/toline-grey.png') -->
<view class="mt-10">
<tpx-text-dic :value="modelInfo.waybillStatus" :list="dicData.emis_waybill_status" ></tpx-text-dic>
</view>
</u-col>
<u-col span="4">
<u-text :text="(reciever.countryName + reciever.provinceName)||'-'" size="30" :bold="true" align="center"></u-text>
<!-- <u-text :text="reciever.name" size="26" color="#999" margin="20rpx 0 0 0"
align="center"></u-text> -->
</u-col>
</u-row>
<u-text v-if="modelInfo.blSign!=1" :text="`下单时间:${modelInfo.sendDate}`" color="#999" size="24"
margin="10rpx 0 0 0"></u-text>
<u-text v-if="modelInfo.blSign==1" :text="`签收时间:${modelInfo.signDate}`" color="#999" size="24"
margin="10rpx 0 0 0"></u-text>
</view>
</template>
<script>
export default {
computed: {
modelInfo: {
get() {
return this.value
}
},
sender() {
let obj = JSON.parse(JSON.stringify(this.value?.sender || this.value || {}))
obj.countryName = obj.sendCountryName || obj.countryName
obj.provinceName = obj.sendProvinceName || obj.provinceName
obj.name = obj.sendName || obj.name
return obj
},
reciever() {
let obj = JSON.parse(JSON.stringify(this.value?.reciever || this.value || {}))
obj.countryName = obj.receiveCountryName || obj.countryName
obj.provinceName = obj.receiveProvinceName || obj.provinceName
obj.name = obj.receiveName || obj.name
return obj
},
dicData() {
return this.$store.getters.dicData
}
},
props: {
value: {
default () {
return {}
}
},
showInfoBtn: {
default () {
return true
}
},
},
data() {
return {}
},
created() {
},
onHide() {
},
unmounted() {
},
methods: {
}
}
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,310 @@
<template>
<view class="map-container">
<view ref="mapContainer" id="mapContainer" class="map-view" :prop="traceList" :change:prop="mapModule.updateTraceData"></view>
</view>
</template>
<script>
// import {chinaGeo} from "@/common/geo/chinaGeo.js"
// import XDGeoSdk from '@/common/geo/XDGeoSdk';
export default {
props:{
dataList:{
type:Array
},
isSatellite:{
type:Boolean,
default: false
},
initZoom:{
type:Number,
default: 8
}
},
data() {
return {
// 传递给renderjs的数据
traceList:this.dataList,
};
},
watch:{
"dataList": {
handler (newValue, oldValue) {
this.traceList=this.dataList;
},
deep: true
},
},
methods: {
}
};
</script>
<!-- renderjs部分,负责处理地图DOM操作 -->
<script module="mapModule" lang="renderjs">
import * as maptalks from 'maptalks';
import dayjs from "dayjs";
export default {
data() {
return {
map: null,
lineArr:[],
marker: null,
polyline: null,
arrPoints:[],
posStart:[],
posEnd:[],
markerLayer: null,
traceLayer:null,
traceDataList:null,
containerId: `map-container-${Date.now()}-${Math.random().toString(36).substring(3,10)}`,
};
},
watch: {
},
mounted() {
// 初始化地图
this.initMap();
},
methods: {
updateTraceData(newValue, oldValue, ownerInstance, instance){
const plainData = JSON.parse(JSON.stringify(newValue));
this.traceDataList=plainData;
this.drawTrackerLine();
},
// 初始化地图
initMap() {
const that=this;
if(this.map == null){
try{
const IMAGE_VERSION="2025061801";
let tplUrl="https://gis.xdadan.com/g/m/{x}/{y}/{z}.png?v="+IMAGE_VERSION;
if(this.isSatellite){
tplUrl="https://gis.xdadan.com/g/y/{x}/{y}/{z}.png?v="+IMAGE_VERSION;
}
let option = {
crossOrigin: "Anonymous",
urlTemplate: tplUrl,
subdomains: ['0', '1', '2', '3'],
attribution: '',
}
let baseLayer = new maptalks.TileLayer('base', option)
this.map = new maptalks.Map("mapContainer", {
// 默认中心点点位
center: [118.81,32.07],
// 缩放层级
zoom: this.initZoom,
// 倾斜度
pitch: 0,
// 最小缩放层级
minZoom: 1,
// 最大缩放层级
maxZoom: 18,
fpsOnInteracting: 0,
// scaleControl: {
// 'position': {'bottom':'10px','right':'10px'},
// 'maxWidth': 100,
// 'metric': true,
// 'imperial': false
// },
// centerCross : true, // 地图中心显示红色十字符号
baseLayer:baseLayer
});
}catch(ex){
console.log("===>ex==>",ex);
}
let optV={
crossOrigin: "Anonymous",
};
this.traceLayer= new maptalks.VectorLayer('traceLayer',optV).addTo(this.map);
}
this.drawTrackerLine();
},
drawTrackerLine(){
if(this.map==null) {
return;
}
if(this.traceDataList==null){
return;
}
if(this.traceDataList.length<=0){
return ;
}
const that=this;
// 清除地图上的所有标记点
this.traceLayer.clear();
this.arrPoints=[];
this.lineArr=[];
let pointsLine=[];
let lastDayTime=null;
let lastDay=null;
let showTime=null;
let isNeedMark=0;
let isNeedAlarm = 0;
// let deviceNum=this.traceDataList[0].msisdn;
let markerBallUrl="https://lbs.jtrs56.com/static/xdico/green-ball.png";
// let deviceNum=this.dataList[0].deviceName;
for(let i=0;i<this.traceDataList.length;i++){
let itemOrig=this.traceDataList[i];
let lngOrig=itemOrig.longitude/1000000;
let latOrig=itemOrig.latitude/1000000
lastDayTime=itemOrig.createTime;
let lng=null;
let lat=null;
// if(this.layerType==1)
{
// if(isInChina(latOrig,lngOrig)){
// var gcj02Item=coordtransform.wgs84togcj02(lngOrig, latOrig);
// lng=gcj02Item[0];
// lat=gcj02Item[1];
// }else
{
lng=lngOrig;
lat=latOrig;
}
}
this.lineArr.push([lng,lat]);
let pointItem=[lng,lat];
pointsLine.push(pointItem);
this.arrPoints.push(pointItem);
}
// 起点标识
this.posStart=this.lineArr[0];
let startTimeTxt=dayjs(this.traceDataList[0].createTime).format('YYYY-MM-DD HH:mm')
// this.addTextLabel(this.traceLayer,startTimeTxt,[this.posStart[0], this.posStart[1]],[5,30]);
let startMarker = new maptalks.Marker([this.posStart[0], this.posStart[1]], {
cursor : 'pointer',
symbol: {
markerFile: "https://lbs.jtrs56.com/static/xdico/icon_start.png", // 图片地址 assets目录下的地址无法识别 --踩过坑
markerWidth: 28, // 图片大小
markerHeight: 28, // 图片大小
markerDx: 0,
markerDy: 0,
markerOpacity: 1 // 图片透明度
}
});
startMarker.setZIndex(101);
startMarker.addTo(this.traceLayer)
startMarker.on('click', function (e) {
that.showTraceInfo(startMarker,that.traceDataList[0],e);
return false;
})
this.posEnd=this.lineArr[this.lineArr.length-1];
let endTimeTxt=dayjs(this.traceDataList[this.traceDataList.length-1].createTime).format('YYYY-MM-DD HH:mm')
let endMarker = new maptalks.Marker([this.posEnd[0], this.posEnd[1]], {
cursor : 'pointer',
symbol: {
markerFile: "https://lbs.jtrs56.com/static/xdico/icon_end.png", // 图片地址 assets目录下的地址无法识别 --踩过坑
markerWidth: 28, // 图片大小
markerHeight: 28, // 图片大小
markerDx: 0,
markerDy: 0,
markerOpacity: 1 // 图片透明度
}
});
endMarker.setZIndex(101);
var line = new maptalks.LineString(this.lineArr, {
visible : true,
editable : false,
cursor : 'pointer',
draggable : false,
dragShadow : false, // display a shadow during dragging
drawOnAxis : null, // force dragging stick on a axis, can be: x, y
// 'arrowStyle' : 'classic',
// 'arrowPlacement' : 'vertex-last',
// 'markerLineWidth': 1,
// 'markerWidth': 4, // 箭头宽度
// 'markerHeight': 4, // 箭头高度
smoothness: 0.2,
symbol: {
'lineColor' : '#28F',
// 'lineColor' : '#b12d29',
'lineWidth' : 4,
'lineOpacity': 1, // 线透明度
'lineDasharray': null, // 虚线样式(如果不需要虚线则留空)
lineJoin: 'round', // miter, round, bevel
lineCap: 'round', // butt, round, square
}
})
line.setZIndex(10);
line.addTo(this.traceLayer)
this.map.fitExtent(this.traceLayer.getExtent(), 0);
},
}
};
</script>
<style scoped>
.map-container {
width: 100%;
height: 100vh;
position: relative;
}
.map-view {
width: 100%;
height: 100%;
}
.map-controls {
position: absolute;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
padding: 10px;
background-color: rgba(255, 255, 255, 0.8);
border-radius: 8px;
z-index: 100;
}
button {
padding: 8px 16px;
background-color: #42b983;
color: white;
border: none;
border-radius: 4px;
font-size: 14px;
}
button:hover {
background-color: #359e75;
}
:deep .maptalks-attribution {
display: none !important;
}
</style>