371 行
13 KiB
HTML
可执行文件
371 行
13 KiB
HTML
可执行文件
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>配送区域设置</title>
|
|
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.min.js"></script>
|
|
<script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.9/index.js"></script>
|
|
<link href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.9/theme-chalk/index.css" rel="stylesheet">
|
|
<script src="https://map.qq.com/api/gljs?v=1.exp&key=BHHBZ-CVK3Q-PKW5B-BJBDV-PZILV-IIBJA&libraries=service,geometry"></script>
|
|
<style>
|
|
body {
|
|
margin: 0;
|
|
padding: 20px;
|
|
font-family: Arial, sans-serif;
|
|
background: #f5f7fa;
|
|
}
|
|
|
|
.delivery-container {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
background: white;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 12px rgba(0,0,0,0.1);
|
|
padding: 20px;
|
|
}
|
|
|
|
.map-wrapper {
|
|
position: relative;
|
|
height: 500px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
#deliveryMap {
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.toolbar {
|
|
position: absolute;
|
|
top: 10px;
|
|
left: 10px;
|
|
z-index: 1000;
|
|
background: white;
|
|
padding: 10px;
|
|
border-radius: 4px;
|
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.draw-btn {
|
|
background: #409eff;
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 16px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
margin-right: 10px;
|
|
}
|
|
|
|
.draw-btn:hover {
|
|
background: #66b1ff;
|
|
}
|
|
|
|
.draw-btn.active {
|
|
background: #f56c6c;
|
|
}
|
|
|
|
.area-list {
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.area-item {
|
|
border: 1px solid #eee;
|
|
border-radius: 4px;
|
|
padding: 15px;
|
|
margin-bottom: 10px;
|
|
background: #fafafa;
|
|
}
|
|
|
|
.area-item h4 {
|
|
margin: 0 0 10px 0;
|
|
color: #333;
|
|
}
|
|
|
|
.area-info {
|
|
color: #666;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.area-actions {
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.area-actions button {
|
|
margin-right: 10px;
|
|
padding: 4px 12px;
|
|
border: 1px solid #ddd;
|
|
background: white;
|
|
border-radius: 3px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.area-actions button:hover {
|
|
background: #f0f0f0;
|
|
}
|
|
|
|
.status-info {
|
|
background: #e6f7ff;
|
|
border: 1px solid #91d5ff;
|
|
border-radius: 4px;
|
|
padding: 10px;
|
|
margin-bottom: 20px;
|
|
color: #0050b3;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="app" class="delivery-container">
|
|
<h2>配送区域设置</h2>
|
|
|
|
<div class="status-info">
|
|
<span v-if="!isDrawing">点击"开始绘制"按钮,然后在地图上点击多个点来创建配送区域</span>
|
|
<span v-else>绘制模式:在地图上点击添加边界点,已添加 {{currentPoints.length}} 个点</span>
|
|
</div>
|
|
|
|
<div class="map-wrapper">
|
|
<div class="toolbar">
|
|
<button class="draw-btn" :class="{active: isDrawing}" @click="toggleDraw">
|
|
{{isDrawing ? '完成绘制' : '开始绘制'}}
|
|
</button>
|
|
<button class="draw-btn" @click="clearCurrent" v-if="isDrawing">取消</button>
|
|
<button class="draw-btn" @click="clearAll" v-if="deliveryAreas.length > 0">清空全部</button>
|
|
</div>
|
|
<div id="deliveryMap"></div>
|
|
</div>
|
|
|
|
<div class="area-list" v-if="deliveryAreas.length > 0">
|
|
<h3>配送区域列表 ({{deliveryAreas.length}}个)</h3>
|
|
<div class="area-item" v-for="(area, index) in deliveryAreas" :key="index">
|
|
<h4>配送区域 {{index + 1}}</h4>
|
|
<div class="area-info">
|
|
面积: {{area.area}} 平方米 | 边界点: {{area.points.length}}个
|
|
</div>
|
|
<div class="area-actions">
|
|
<button @click="locateArea(area)">定位</button>
|
|
<button @click="deleteArea(index)">删除</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 隐藏的表单字段,用于提交数据 -->
|
|
<input type="hidden" name="delivery_areas" :value="deliveryAreasJson">
|
|
</div>
|
|
|
|
<script>
|
|
new Vue({
|
|
el: '#app',
|
|
data: {
|
|
map: null,
|
|
isDrawing: false,
|
|
currentPoints: [],
|
|
currentPolyline: null,
|
|
deliveryAreas: [],
|
|
polygons: []
|
|
},
|
|
computed: {
|
|
deliveryAreasJson() {
|
|
return JSON.stringify(this.deliveryAreas);
|
|
}
|
|
},
|
|
mounted() {
|
|
this.initMap();
|
|
},
|
|
methods: {
|
|
// 初始化地图
|
|
initMap() {
|
|
this.map = new TMap.Map('deliveryMap', {
|
|
center: new TMap.LatLng(39.984104, 116.307503),
|
|
zoom: 12
|
|
});
|
|
|
|
// 绑定地图点击事件
|
|
this.map.on('click', this.onMapClick);
|
|
},
|
|
|
|
// 地图点击事件
|
|
onMapClick(evt) {
|
|
if (!this.isDrawing) return;
|
|
|
|
const latLng = evt.latLng;
|
|
this.currentPoints.push(latLng);
|
|
|
|
// 更新绘制线条
|
|
this.updateDrawingLine();
|
|
},
|
|
|
|
// 更新绘制线条
|
|
updateDrawingLine() {
|
|
if (this.currentPolyline) {
|
|
this.currentPolyline.setMap(null);
|
|
}
|
|
|
|
if (this.currentPoints.length > 1) {
|
|
this.currentPolyline = new TMap.MultiPolyline({
|
|
map: this.map,
|
|
styles: {
|
|
'drawing': {
|
|
color: '#3777FF',
|
|
width: 3,
|
|
borderColor: '#FFF',
|
|
borderWidth: 2
|
|
}
|
|
},
|
|
geometries: [{
|
|
styleId: 'drawing',
|
|
paths: this.currentPoints
|
|
}]
|
|
});
|
|
}
|
|
},
|
|
|
|
// 切换绘制状态
|
|
toggleDraw() {
|
|
if (this.isDrawing) {
|
|
this.finishDrawing();
|
|
} else {
|
|
this.startDrawing();
|
|
}
|
|
},
|
|
|
|
// 开始绘制
|
|
startDrawing() {
|
|
this.isDrawing = true;
|
|
this.currentPoints = [];
|
|
this.$message.success('开始绘制配送区域,请在地图上点击添加边界点');
|
|
},
|
|
|
|
// 完成绘制
|
|
finishDrawing() {
|
|
if (this.currentPoints.length < 3) {
|
|
this.$message.warning('至少需要3个点才能形成区域');
|
|
return;
|
|
}
|
|
|
|
// 创建多边形
|
|
const polygon = new TMap.MultiPolygon({
|
|
map: this.map,
|
|
styles: {
|
|
'area': {
|
|
color: 'rgba(55, 119, 255, 0.3)',
|
|
borderColor: '#3777FF',
|
|
borderWidth: 2
|
|
}
|
|
},
|
|
geometries: [{
|
|
styleId: 'area',
|
|
paths: [this.currentPoints]
|
|
}]
|
|
});
|
|
|
|
// 计算面积
|
|
const area = this.calculateArea(this.currentPoints);
|
|
|
|
// 保存区域数据
|
|
const areaData = {
|
|
points: this.currentPoints.map(p => ({lat: p.lat, lng: p.lng})),
|
|
area: Math.round(area),
|
|
polygon: polygon
|
|
};
|
|
|
|
this.deliveryAreas.push(areaData);
|
|
this.polygons.push(polygon);
|
|
|
|
// 清理绘制状态
|
|
this.clearDrawing();
|
|
|
|
this.$message.success(`配送区域创建成功,面积: ${Math.round(area)} 平方米`);
|
|
},
|
|
|
|
// 清理绘制状态
|
|
clearDrawing() {
|
|
this.isDrawing = false;
|
|
this.currentPoints = [];
|
|
if (this.currentPolyline) {
|
|
this.currentPolyline.setMap(null);
|
|
this.currentPolyline = null;
|
|
}
|
|
},
|
|
|
|
// 取消当前绘制
|
|
clearCurrent() {
|
|
this.clearDrawing();
|
|
this.$message.info('已取消绘制');
|
|
},
|
|
|
|
// 清空所有区域
|
|
clearAll() {
|
|
this.$confirm('确定要清空所有配送区域吗?', '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
}).then(() => {
|
|
// 清除地图上的多边形
|
|
this.polygons.forEach(polygon => {
|
|
polygon.setMap(null);
|
|
});
|
|
|
|
this.deliveryAreas = [];
|
|
this.polygons = [];
|
|
this.clearDrawing();
|
|
|
|
this.$message.success('已清空所有配送区域');
|
|
});
|
|
},
|
|
|
|
// 定位到指定区域
|
|
locateArea(area) {
|
|
if (area.points.length > 0) {
|
|
const bounds = new TMap.LatLngBounds();
|
|
area.points.forEach(point => {
|
|
bounds.extend(new TMap.LatLng(point.lat, point.lng));
|
|
});
|
|
this.map.fitBounds(bounds, {padding: 50});
|
|
}
|
|
},
|
|
|
|
// 删除指定区域
|
|
deleteArea(index) {
|
|
this.$confirm('确定要删除这个配送区域吗?', '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
}).then(() => {
|
|
// 从地图上移除多边形
|
|
if (this.polygons[index]) {
|
|
this.polygons[index].setMap(null);
|
|
this.polygons.splice(index, 1);
|
|
}
|
|
|
|
this.deliveryAreas.splice(index, 1);
|
|
this.$message.success('配送区域已删除');
|
|
});
|
|
},
|
|
|
|
// 计算多边形面积
|
|
calculateArea(points) {
|
|
if (points.length < 3) return 0;
|
|
|
|
let area = 0;
|
|
const earthRadius = 6371000; // 地球半径(米)
|
|
|
|
for (let i = 0; i < points.length; i++) {
|
|
const j = (i + 1) % points.length;
|
|
const lat1 = points[i].lat * Math.PI / 180;
|
|
const lat2 = points[j].lat * Math.PI / 180;
|
|
const lng1 = points[i].lng * Math.PI / 180;
|
|
const lng2 = points[j].lng * Math.PI / 180;
|
|
|
|
area += (lng2 - lng1) * (2 + Math.sin(lat1) + Math.sin(lat2));
|
|
}
|
|
|
|
area = Math.abs(area * earthRadius * earthRadius / 2);
|
|
return area;
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |