文件
mashangyoujiu/Application/Retail/View/Xcx/manager_native.html

869 行
26 KiB
HTML
可执行文件

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>门店管理 - 配送区域绘制</title>
<script src="https://map.qq.com/api/gljs?v=1.exp&key=BHHBZ-CVK3Q-PKW5B-BJBDV-PZILV-IIBJA&libraries=service,geometry"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
background: #f5f7fa;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px;
text-align: center;
}
.header h1 {
font-size: 24px;
font-weight: 600;
}
.content {
padding: 30px;
}
.map-section {
margin-bottom: 30px;
}
.map-container {
position: relative;
border: 2px solid #e4e7ed;
border-radius: 8px;
overflow: hidden;
}
.map-header {
background: #409eff;
color: white;
padding: 15px 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.map-title {
font-size: 16px;
font-weight: 600;
}
.map-status {
font-size: 14px;
}
#map {
width: 100%;
height: 500px;
display: block;
}
.toolbar {
position: absolute;
top: 20px;
left: 20px;
z-index: 1000;
display: flex;
flex-direction: column;
gap: 10px;
}
.tool-group {
background: rgba(255, 255, 255, 0.95);
border-radius: 8px;
padding: 10px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
display: flex;
flex-direction: column;
gap: 8px;
}
.tool-btn {
width: 40px;
height: 40px;
border: none;
border-radius: 6px;
background: white;
color: #606266;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
transition: all 0.3s ease;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
user-select: none;
}
.tool-btn:hover {
background: #f0f2f5;
color: #409eff;
transform: scale(1.05);
}
.tool-btn.active {
background: #409eff;
color: white;
}
.tool-btn.danger {
color: #f56c6c;
}
.tool-btn.danger:hover {
background: #fef0f0;
}
.drawing-tips {
position: absolute;
top: 20px;
right: 20px;
background: rgba(255, 255, 255, 0.95);
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
max-width: 250px;
z-index: 1000;
}
.tips-title {
font-size: 14px;
font-weight: 600;
color: #303133;
margin-bottom: 8px;
}
.tips-content {
font-size: 12px;
color: #606266;
line-height: 1.5;
}
.area-list {
margin-top: 20px;
}
.area-item {
background: white;
border: 1px solid #e4e7ed;
border-radius: 8px;
padding: 15px;
margin-bottom: 10px;
display: flex;
justify-content: space-between;
align-items: center;
transition: all 0.3s ease;
}
.area-item:hover {
border-color: #409eff;
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.15);
}
.area-info h4 {
margin: 0 0 5px 0;
color: #303133;
}
.area-info p {
margin: 0;
font-size: 12px;
color: #909399;
}
.area-actions {
display: flex;
gap: 8px;
}
.btn {
padding: 6px 12px;
border: 1px solid #dcdfe6;
border-radius: 4px;
background: white;
color: #606266;
cursor: pointer;
font-size: 12px;
transition: all 0.3s ease;
}
.btn:hover {
border-color: #409eff;
color: #409eff;
}
.btn.danger {
border-color: #f56c6c;
color: #f56c6c;
}
.btn.danger:hover {
background: #f56c6c;
color: white;
}
.hidden {
display: none !important;
}
.message {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
padding: 12px 20px;
border-radius: 4px;
color: white;
font-size: 14px;
z-index: 9999;
transition: all 0.3s ease;
}
.message.success {
background: #67c23a;
}
.message.error {
background: #f56c6c;
}
.message.warning {
background: #e6a23c;
}
.message.info {
background: #409eff;
}
.form-section {
margin-top: 30px;
padding: 20px;
background: #f8f9fa;
border-radius: 8px;
}
.form-group {
margin-bottom: 15px;
}
.form-label {
display: block;
margin-bottom: 5px;
font-weight: 600;
color: #303133;
}
.form-input {
width: 100%;
padding: 8px 12px;
border: 1px solid #dcdfe6;
border-radius: 4px;
font-size: 14px;
}
.form-textarea {
width: 100%;
padding: 8px 12px;
border: 1px solid #dcdfe6;
border-radius: 4px;
font-size: 14px;
resize: vertical;
min-height: 80px;
}
.btn-primary {
background: #409eff;
border-color: #409eff;
color: white;
}
.btn-primary:hover {
background: #66b1ff;
border-color: #66b1ff;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>门店管理 - 配送区域绘制</h1>
</div>
<div class="content">
<!-- 地图区域 -->
<div class="map-section">
<div class="map-container">
<div class="map-header">
<div class="map-title">配送区域绘制</div>
<div class="map-status" id="mapStatus">地图加载中...</div>
</div>
<div id="map"></div>
<!-- 工具栏 -->
<div class="toolbar">
<div class="tool-group">
<span class="tool-btn" id="drawBtn" title="绘制配送区域" role="button" tabindex="0">✏️</span>
<span class="tool-btn hidden" id="finishBtn" title="完成绘制" role="button" tabindex="0">✅</span>
<span class="tool-btn danger hidden" id="cancelBtn" title="取消绘制" role="button" tabindex="0">❌</span>
</div>
<div class="tool-group">
<span class="tool-btn" id="clearBtn" title="清空所有区域" role="button" tabindex="0">🗑️</span>
</div>
</div>
<!-- 绘制提示 -->
<div class="drawing-tips hidden" id="drawingTips">
<div class="tips-title">绘制提示</div>
<div class="tips-content">
• 点击地图添加边界点<br>
• 至少需要3个点<br>
• 当前已添加 <span id="pointCount">0</span> 个点
</div>
</div>
</div>
</div>
<!-- 区域列表 -->
<div class="area-list">
<h3>配送区域列表</h3>
<div id="areaList">
<div style="text-align: center; padding: 40px; color: #909399;">
暂无配送区域,点击绘制按钮开始创建
</div>
</div>
</div>
<!-- 表单区域 -->
<div class="form-section">
<div class="form-group">
<label class="form-label">门店地址</label>
<input type="text" class="form-input" id="storeAddress" value="北京市朝阳区三里屯" placeholder="请输入门店地址">
</div>
<div class="form-group">
<label class="form-label">配送区域数据</label>
<textarea class="form-textarea" id="deliveryData" placeholder="配送区域JSON数据" readonly></textarea>
</div>
<div class="form-group">
<button class="btn btn-primary" onclick="saveData()">保存设置</button>
<button class="btn" onclick="exportData()">导出数据</button>
</div>
</div>
</div>
</div>
<script>
// 全局变量
let map = null;
let mapReady = false;
let isDrawing = false;
let currentPoints = [];
let currentPolyline = null;
let deliveryAreas = [];
let polygons = [];
// DOM元素
const drawBtn = document.getElementById('drawBtn');
const finishBtn = document.getElementById('finishBtn');
const cancelBtn = document.getElementById('cancelBtn');
const clearBtn = document.getElementById('clearBtn');
const mapStatus = document.getElementById('mapStatus');
const drawingTips = document.getElementById('drawingTips');
const pointCount = document.getElementById('pointCount');
const areaList = document.getElementById('areaList');
const deliveryData = document.getElementById('deliveryData');
// 消息提示
function showMessage(text, type = 'info') {
const message = document.createElement('div');
message.className = `message ${type}`;
message.textContent = text;
document.body.appendChild(message);
setTimeout(() => {
message.style.opacity = '0';
setTimeout(() => {
document.body.removeChild(message);
}, 300);
}, 3000);
}
// 初始化地图
function initMap() {
console.log('开始初始化地图...');
const checkTMap = () => {
if (typeof TMap !== 'undefined') {
console.log('腾讯地图API已加载,创建地图实例');
createMap();
} else {
console.log('等待腾讯地图API加载...');
setTimeout(checkTMap, 500);
}
};
checkTMap();
}
function createMap() {
try {
const mapContainer = document.getElementById('map');
map = new TMap.Map(mapContainer, {
center: new TMap.LatLng(39.915, 116.404),
zoom: 13,
viewMode: '2D'
});
// 监听地图加载完成
map.on('tilesloaded', () => {
console.log('地图瓦片加载完成');
mapReady = true;
mapStatus.textContent = '地图加载完成,可以开始绘制';
showMessage('地图加载成功', 'success');
});
// 监听地图点击
map.on('click', (evt) => {
console.log('地图点击事件', evt);
if (isDrawing) {
addPoint(evt.latLng);
}
});
console.log('地图实例创建成功');
} catch (error) {
console.error('创建地图失败:', error);
showMessage('地图初始化失败', 'error');
}
}
// 绘制功能
function toggleDrawing() {
console.log('切换绘制状态,当前:', isDrawing);
try {
if (isDrawing) {
cancelDrawing();
} else {
startDrawing();
}
} catch (error) {
console.error('切换绘制状态失败:', error);
}
return false;
}
function startDrawing() {
console.log('开始绘制');
try {
if (!mapReady) {
showMessage('地图未准备就绪', 'error');
return false;
}
isDrawing = true;
currentPoints = [];
clearCurrentDrawing();
updateUI();
showMessage('请在地图上点击添加边界点', 'info');
} catch (error) {
console.error('开始绘制失败:', error);
}
return false;
}
function addPoint(latLng) {
console.log('添加点:', latLng);
const point = {
lat: latLng.lat,
lng: latLng.lng
};
currentPoints.push(point);
updateDrawing();
updateUI();
console.log('当前点数:', currentPoints.length);
}
function updateDrawing() {
if (currentPoints.length < 2) return;
// 清除之前的绘制线
clearCurrentDrawing();
try {
// 创建路径
const path = currentPoints.map(point =>
new TMap.LatLng(point.lat, point.lng)
);
// 绘制线条
currentPolyline = new TMap.Polyline({
map: map,
path: path,
strokeColor: '#409eff',
strokeWeight: 3,
strokeDashArray: [10, 10]
});
console.log('更新绘制线条');
} catch (error) {
console.error('更新绘制失败:', error);
}
}
function finishDrawing() {
console.log('完成绘制');
try {
if (currentPoints.length < 3) {
showMessage('至少需要3个点才能形成区域', 'warning');
return false;
}
// 确保路径闭合
const points = [...currentPoints];
const firstPoint = points[0];
const lastPoint = points[points.length - 1];
if (firstPoint.lat !== lastPoint.lat || firstPoint.lng !== lastPoint.lng) {
points.push({...firstPoint});
}
// 计算面积
const area = calculateArea(points);
// 创建新区域
const newArea = {
id: Date.now(),
name: `配送区域${deliveryAreas.length + 1}`,
points: points,
area: area.toFixed(2),
createTime: Date.now()
};
deliveryAreas.push(newArea);
createPolygon(newArea);
updateFormData();
updateAreaList();
// 重置绘制状态
isDrawing = false;
currentPoints = [];
clearCurrentDrawing();
updateUI();
showMessage(`配送区域 "${newArea.name}" 创建成功`, 'success');
} catch (error) {
console.error('完成绘制失败:', error);
showMessage('创建区域失败', 'error');
}
return false;
}
function cancelDrawing() {
console.log('取消绘制');
try {
isDrawing = false;
currentPoints = [];
clearCurrentDrawing();
updateUI();
showMessage('已取消绘制', 'info');
} catch (error) {
console.error('取消绘制失败:', error);
}
return false;
}
function clearCurrentDrawing() {
if (currentPolyline) {
currentPolyline.setMap(null);
currentPolyline = null;
}
}
// 创建多边形
function createPolygon(area) {
try {
const path = area.points.map(point =>
new TMap.LatLng(point.lat, point.lng)
);
const polygon = new TMap.Polygon({
map: map,
paths: [path],
fillColor: 'rgba(64, 158, 255, 0.3)',
strokeColor: '#409eff',
strokeWeight: 2
});
polygons.push(polygon);
} catch (error) {
console.error('创建多边形失败:', error);
}
}
// 计算面积(简化版本)
function calculateArea(points) {
if (points.length < 3) return 0;
let area = 0;
for (let i = 0; i < points.length - 1; i++) {
const p1 = points[i];
const p2 = points[i + 1];
area += (p2.lng - p1.lng) * (p2.lat + p1.lat);
}
return Math.abs(area) * 0.5 * 111 * 111; // 粗略转换为平方公里
}
// 更新UI
function updateUI() {
// 更新按钮状态
drawBtn.classList.toggle('active', isDrawing);
// 显示/隐藏按钮
if (isDrawing) {
drawingTips.classList.remove('hidden');
if (currentPoints.length >= 3) {
finishBtn.classList.remove('hidden');
} else {
finishBtn.classList.add('hidden');
}
cancelBtn.classList.remove('hidden');
} else {
drawingTips.classList.add('hidden');
finishBtn.classList.add('hidden');
cancelBtn.classList.add('hidden');
}
// 更新状态文本
if (mapReady) {
if (isDrawing) {
mapStatus.textContent = '绘制模式 - 点击地图添加边界点';
} else {
mapStatus.textContent = `已设置 ${deliveryAreas.length} 个配送区域`;
}
}
// 更新点数
pointCount.textContent = currentPoints.length;
}
// 更新区域列表
function updateAreaList() {
if (deliveryAreas.length === 0) {
areaList.innerHTML = `
<div style="text-align: center; padding: 40px; color: #909399;">
暂无配送区域,点击绘制按钮开始创建
</div>
`;
return;
}
let html = '';
deliveryAreas.forEach((area, index) => {
html += `
<div class="area-item">
<div class="area-info">
<h4>${area.name}</h4>
<p>面积: ${area.area} 平方公里 | 边界点: ${area.points.length} 个</p>
</div>
<div class="area-actions">
<button class="btn" onclick="locateArea(${index})">定位</button>
<button class="btn danger" onclick="deleteArea(${index})">删除</button>
</div>
</div>
`;
});
areaList.innerHTML = html;
}
// 区域管理
function locateArea(index) {
const area = deliveryAreas[index];
if (!area || !area.points.length) return;
try {
let bounds = new TMap.LatLngBounds();
area.points.forEach(point => {
bounds.extend(new TMap.LatLng(point.lat, point.lng));
});
map.fitBounds(bounds, { padding: 50 });
showMessage('已定位到该区域', 'success');
} catch (error) {
console.error('定位区域失败:', error);
}
}
function deleteArea(index) {
if (confirm('确定要删除这个配送区域吗?')) {
// 删除地图上的多边形
if (polygons[index]) {
polygons[index].setMap(null);
polygons.splice(index, 1);
}
deliveryAreas.splice(index, 1);
updateFormData();
updateAreaList();
updateUI();
showMessage('区域已删除', 'success');
}
}
function clearAll() {
if (confirm('确定要清空所有配送区域吗?')) {
// 清除所有多边形
polygons.forEach(polygon => {
polygon.setMap(null);
});
polygons = [];
deliveryAreas = [];
updateFormData();
updateAreaList();
updateUI();
showMessage('已清空所有区域', 'success');
}
}
// 数据管理
function updateFormData() {
deliveryData.value = JSON.stringify(deliveryAreas, null, 2);
}
function saveData() {
const data = {
address: document.getElementById('storeAddress').value,
delivery_fences: deliveryData.value
};
console.log('保存数据:', data);
showMessage('数据已保存', 'success');
}
function exportData() {
const data = {
areas: deliveryAreas,
exportTime: new Date().toISOString()
};
const text = JSON.stringify(data, null, 2);
// 复制到剪贴板
if (navigator.clipboard) {
navigator.clipboard.writeText(text).then(() => {
showMessage('数据已复制到剪贴板', 'success');
});
} else {
console.log('导出数据:', text);
showMessage('数据已输出到控制台', 'success');
}
}
// 绝对防止页面刷新的事件处理
function handleDrawClick() {
console.log('绘制按钮被点击');
toggleDrawing();
return false;
}
function handleFinishClick() {
console.log('完成按钮被点击');
finishDrawing();
return false;
}
function handleCancelClick() {
console.log('取消按钮被点击');
cancelDrawing();
return false;
}
function handleClearClick() {
console.log('清空按钮被点击');
clearAll();
return false;
}
// 使用最安全的事件绑定方式
drawBtn.onclick = handleDrawClick;
finishBtn.onclick = handleFinishClick;
cancelBtn.onclick = handleCancelClick;
clearBtn.onclick = handleClearClick;
// 额外的保护措施
drawBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
return false;
}, true);
finishBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
return false;
}, true);
cancelBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
return false;
}, true);
clearBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
return false;
}, true);
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function() {
console.log('页面加载完成,开始初始化');
initMap();
});
</script>
</body>
</html>