829 行
29 KiB
HTML
829 行
29 KiB
HTML
<!--[1.8.50]-->
|
|
<!-- 引入Vue.js -->
|
|
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script>
|
|
<!-- 引入Element UI -->
|
|
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
|
|
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
|
|
<!-- 引入jQuery -->
|
|
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
|
|
<!-- 引入腾讯地图组件 -->
|
|
<script charset="utf-8" type="text/javascript" src="/Public/js/get-position-map-tencent.js?v=1.0.2"></script>
|
|
|
|
<style type="text/css">
|
|
.fence-container {
|
|
padding: 20px;
|
|
}
|
|
|
|
.fence-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.fence-table {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.fence-status {
|
|
display: inline-block;
|
|
padding: 2px 8px;
|
|
border-radius: 4px;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.fence-status.active {
|
|
background-color: #e7f5e7;
|
|
color: #67c23a;
|
|
}
|
|
|
|
.fence-status.inactive {
|
|
background-color: #fef0f0;
|
|
color: #f56c6c;
|
|
}
|
|
|
|
.fence-type-tag {
|
|
display: inline-block;
|
|
padding: 2px 8px;
|
|
border-radius: 4px;
|
|
font-size: 12px;
|
|
background-color: #f0f9ff;
|
|
color: #409eff;
|
|
}
|
|
|
|
.map-container {
|
|
border: 1px solid #dcdfe6;
|
|
border-radius: 4px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.drawing-tools {
|
|
padding: 10px;
|
|
background-color: #f5f7fa;
|
|
border-bottom: 1px solid #dcdfe6;
|
|
}
|
|
|
|
.drawing-tools .el-button {
|
|
margin-right: 10px;
|
|
}
|
|
|
|
.fence-form .el-form-item {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.coordinates-display {
|
|
max-height: 200px;
|
|
overflow-y: auto;
|
|
background-color: #f9f9f9;
|
|
padding: 10px;
|
|
border-radius: 4px;
|
|
font-family: monospace;
|
|
font-size: 12px;
|
|
}
|
|
</style>
|
|
|
|
<div id="fenceManager" class="fence-container">
|
|
<!-- 页面标题和操作按钮 -->
|
|
<div class="fence-header">
|
|
<h2>电子围栏管理</h2>
|
|
<el-button type="primary" @click="showAddDialog">新增围栏</el-button>
|
|
</div>
|
|
|
|
<!-- 围栏列表 -->
|
|
<div class="fence-table">
|
|
<el-table :data="fenceList" border stripe>
|
|
<el-table-column prop="id" label="ID" width="80"></el-table-column>
|
|
<el-table-column prop="fence_name" label="围栏名称" min-width="150"></el-table-column>
|
|
<el-table-column prop="fence_type" label="围栏类型" width="100">
|
|
<template slot-scope="scope">
|
|
<span class="fence-type-tag">
|
|
{{ scope.row.fence_type == 1 ? '多边形' : '圆形' }}
|
|
</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="is_active" label="状态" width="80">
|
|
<template slot-scope="scope">
|
|
<span :class="['fence-status', scope.row.is_active == 1 ? 'active' : 'inactive']">
|
|
{{ scope.row.is_active == 1 ? '启用' : '禁用' }}
|
|
</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="create_time" label="创建时间" width="180">
|
|
<template slot-scope="scope">
|
|
{{ formatTime(scope.row.create_time) }}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="操作" width="200">
|
|
<template slot-scope="scope">
|
|
<el-button size="mini" @click="editFence(scope.row)">编辑</el-button>
|
|
<el-button size="mini" type="warning" @click="toggleFenceStatus(scope.row)">
|
|
{{ scope.row.is_active == 1 ? '禁用' : '启用' }}
|
|
</el-button>
|
|
<el-button size="mini" type="danger" @click="deleteFence(scope.row)">删除</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<!-- 分页 -->
|
|
<el-pagination
|
|
@size-change="handleSizeChange"
|
|
@current-change="handleCurrentChange"
|
|
:current-page="pagination.page"
|
|
:page-sizes="[10, 20, 50, 100]"
|
|
:page-size="pagination.size"
|
|
layout="total, sizes, prev, pager, next, jumper"
|
|
:total="pagination.total">
|
|
</el-pagination>
|
|
</div>
|
|
|
|
<!-- 新增/编辑围栏对话框 -->
|
|
<el-dialog
|
|
:title="dialogTitle"
|
|
:visible.sync="dialogVisible"
|
|
width="80%"
|
|
:close-on-click-modal="false"
|
|
@close="resetForm">
|
|
|
|
<el-form :model="fenceForm" :rules="fenceRules" ref="fenceForm" label-width="100px" class="fence-form">
|
|
<el-row :gutter="20">
|
|
<el-col :span="12">
|
|
<el-form-item label="围栏名称" prop="fence_name">
|
|
<el-input v-model="fenceForm.fence_name" placeholder="请输入围栏名称"></el-input>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="围栏类型" prop="fence_type">
|
|
<el-radio-group v-model="fenceForm.fence_type" @change="onFenceTypeChange">
|
|
<el-radio :label="1">多边形围栏</el-radio>
|
|
<el-radio :label="2">圆形围栏</el-radio>
|
|
</el-radio-group>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="是否启用" prop="is_active">
|
|
<el-switch v-model="fenceForm.is_active" :active-value="1" :inactive-value="0"></el-switch>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="坐标数据" v-if="fenceForm.fence_data">
|
|
<div class="coordinates-display">
|
|
{{ formatCoordinates(fenceForm.fence_data) }}
|
|
</div>
|
|
</el-form-item>
|
|
</el-col>
|
|
|
|
<el-col :span="12">
|
|
<!-- 地图绘制区域 -->
|
|
<div class="map-container">
|
|
<div class="drawing-tools">
|
|
<el-button
|
|
size="small"
|
|
:type="drawingMode === 'polygon' ? 'primary' : 'default'"
|
|
@click="startDrawing('polygon')"
|
|
:disabled="fenceForm.fence_type !== 1">
|
|
绘制多边形
|
|
</el-button>
|
|
<el-button
|
|
size="small"
|
|
:type="drawingMode === 'circle' ? 'primary' : 'default'"
|
|
@click="startDrawing('circle')"
|
|
:disabled="fenceForm.fence_type !== 2">
|
|
绘制圆形
|
|
</el-button>
|
|
<el-button size="small" @click="clearDrawing">清除绘制</el-button>
|
|
<el-button size="small" type="success" @click="completeDrawing" :disabled="!currentDrawing">完成绘制</el-button>
|
|
</div>
|
|
<div ref="fenceMap" style="height: 400px; width: 100%;"></div>
|
|
</div>
|
|
</el-col>
|
|
</el-row>
|
|
</el-form>
|
|
|
|
<div slot="footer" class="dialog-footer">
|
|
<el-button @click="dialogVisible = false">取消</el-button>
|
|
<el-button type="primary" @click="saveFence" :loading="saving">保存</el-button>
|
|
</div>
|
|
</el-dialog>
|
|
</div>
|
|
|
|
<script type="text/javascript">
|
|
var fenceManager = new Vue({
|
|
el: "#fenceManager",
|
|
data() {
|
|
return {
|
|
// 围栏列表数据
|
|
fenceList: [],
|
|
|
|
// 分页数据
|
|
pagination: {
|
|
page: 1,
|
|
size: 10,
|
|
total: 0
|
|
},
|
|
|
|
// 对话框控制
|
|
dialogVisible: false,
|
|
dialogTitle: '新增围栏',
|
|
saving: false,
|
|
|
|
// 围栏表单数据
|
|
fenceForm: {
|
|
id: 0,
|
|
fence_name: '',
|
|
fence_type: 1, // 1=多边形,2=圆形
|
|
fence_data: '',
|
|
is_active: 1
|
|
},
|
|
|
|
// 表单验证规则
|
|
fenceRules: {
|
|
fence_name: [
|
|
{ required: true, message: '请输入围栏名称', trigger: 'blur' },
|
|
{ min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
|
|
],
|
|
fence_type: [
|
|
{ required: true, message: '请选择围栏类型', trigger: 'change' }
|
|
]
|
|
},
|
|
|
|
// 地图相关
|
|
fenceMap: null,
|
|
drawingMode: '', // 'polygon' | 'circle' | ''
|
|
currentDrawing: null, // 当前绘制的图形
|
|
polygonPoints: [], // 多边形点集合
|
|
circleCenter: null, // 圆心
|
|
circleRadius: 0, // 半径
|
|
|
|
// 门店信息
|
|
storeId: 0,
|
|
merchantId: 0
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
// 初始化数据
|
|
async init() {
|
|
await this.getStoreInfo();
|
|
await this.loadFenceList();
|
|
},
|
|
|
|
// 获取门店信息
|
|
async getStoreInfo() {
|
|
try {
|
|
// 这里需要根据实际情况获取门店ID和商户ID
|
|
// 可以从URL参数或全局变量中获取
|
|
this.storeId = window.storeId || 1;
|
|
this.merchantId = window.merchantId || 1;
|
|
} catch (error) {
|
|
console.error('获取门店信息失败:', error);
|
|
}
|
|
},
|
|
|
|
// 加载围栏列表
|
|
async loadFenceList() {
|
|
try {
|
|
const response = await this.request('/Retail/Xcx/getFenceList', {
|
|
store_id: this.storeId,
|
|
page: this.pagination.page,
|
|
size: this.pagination.size
|
|
});
|
|
|
|
if (response.code === 200) {
|
|
this.fenceList = response.data.list || [];
|
|
this.pagination.total = response.data.total || 0;
|
|
} else {
|
|
this.$message.error(response.msg || '加载围栏列表失败');
|
|
}
|
|
} catch (error) {
|
|
console.error('加载围栏列表失败:', error);
|
|
this.$message.error('加载围栏列表失败');
|
|
}
|
|
},
|
|
|
|
// 显示新增对话框
|
|
showAddDialog() {
|
|
this.dialogTitle = '新增围栏';
|
|
this.dialogVisible = true;
|
|
this.resetForm();
|
|
this.$nextTick(() => {
|
|
this.initFenceMap();
|
|
});
|
|
},
|
|
|
|
// 编辑围栏
|
|
editFence(fence) {
|
|
this.dialogTitle = '编辑围栏';
|
|
this.fenceForm = { ...fence };
|
|
this.dialogVisible = true;
|
|
this.$nextTick(() => {
|
|
this.initFenceMap();
|
|
this.loadFenceOnMap(fence.fence_data);
|
|
});
|
|
},
|
|
|
|
// 切换围栏状态
|
|
async toggleFenceStatus(fence) {
|
|
try {
|
|
const response = await this.request('/Retail/Xcx/updateFenceStatus', {
|
|
id: fence.id,
|
|
is_active: fence.is_active == 1 ? 0 : 1
|
|
});
|
|
|
|
if (response.code === 200) {
|
|
this.$message.success('状态更新成功');
|
|
this.loadFenceList();
|
|
} else {
|
|
this.$message.error(response.msg || '状态更新失败');
|
|
}
|
|
} catch (error) {
|
|
console.error('状态更新失败:', error);
|
|
this.$message.error('状态更新失败');
|
|
}
|
|
},
|
|
|
|
// 删除围栏
|
|
deleteFence(fence) {
|
|
this.$confirm('确定要删除这个围栏吗?', '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
}).then(async () => {
|
|
try {
|
|
const response = await this.request('/Retail/Xcx/deleteFence', {
|
|
id: fence.id
|
|
});
|
|
|
|
if (response.code === 200) {
|
|
this.$message.success('删除成功');
|
|
this.loadFenceList();
|
|
} else {
|
|
this.$message.error(response.msg || '删除失败');
|
|
}
|
|
} catch (error) {
|
|
console.error('删除失败:', error);
|
|
this.$message.error('删除失败');
|
|
}
|
|
});
|
|
},
|
|
|
|
// 保存围栏
|
|
saveFence() {
|
|
this.$refs.fenceForm.validate(async (valid) => {
|
|
if (!valid) return;
|
|
|
|
if (!this.fenceForm.fence_data) {
|
|
this.$message.error('请先绘制围栏区域');
|
|
return;
|
|
}
|
|
|
|
this.saving = true;
|
|
try {
|
|
const url = this.fenceForm.id ? '/Retail/Xcx/updateFence' : '/Retail/Xcx/addFence';
|
|
const data = {
|
|
...this.fenceForm,
|
|
store_id: this.storeId,
|
|
merchant_id: this.merchantId
|
|
};
|
|
|
|
const response = await this.request(url, data);
|
|
|
|
if (response.code === 200) {
|
|
this.$message.success('保存成功');
|
|
this.dialogVisible = false;
|
|
this.loadFenceList();
|
|
} else {
|
|
this.$message.error(response.msg || '保存失败');
|
|
}
|
|
} catch (error) {
|
|
console.error('保存失败:', error);
|
|
this.$message.error('保存失败');
|
|
} finally {
|
|
this.saving = false;
|
|
}
|
|
});
|
|
},
|
|
|
|
// 重置表单
|
|
resetForm() {
|
|
this.fenceForm = {
|
|
id: 0,
|
|
fence_name: '',
|
|
fence_type: 1,
|
|
fence_data: '',
|
|
is_active: 1
|
|
};
|
|
this.clearDrawing();
|
|
if (this.$refs.fenceForm) {
|
|
this.$refs.fenceForm.resetFields();
|
|
}
|
|
},
|
|
|
|
// 围栏类型改变
|
|
onFenceTypeChange() {
|
|
this.clearDrawing();
|
|
},
|
|
|
|
// 初始化围栏地图
|
|
async initFenceMap() {
|
|
if (this.fenceMap) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// 等待腾讯地图API加载
|
|
await this.waitForTMapLoad();
|
|
|
|
// 创建地图实例
|
|
this.fenceMap = new TMap.Map(this.$refs.fenceMap, {
|
|
center: new TMap.LatLng(39.915, 116.404),
|
|
zoom: 15,
|
|
viewMode: '2D',
|
|
mapStyleId: 'style1'
|
|
});
|
|
|
|
console.log('围栏地图初始化成功');
|
|
} catch (error) {
|
|
console.error('围栏地图初始化失败:', error);
|
|
this.$message.error('地图初始化失败');
|
|
}
|
|
},
|
|
|
|
// 等待腾讯地图API加载
|
|
waitForTMapLoad() {
|
|
return new Promise((resolve, reject) => {
|
|
if (window.TMap) {
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
let checkCount = 0;
|
|
const checkInterval = setInterval(() => {
|
|
checkCount++;
|
|
if (window.TMap) {
|
|
clearInterval(checkInterval);
|
|
resolve();
|
|
} else if (checkCount > 50) {
|
|
clearInterval(checkInterval);
|
|
reject(new Error('腾讯地图API加载超时'));
|
|
}
|
|
}, 100);
|
|
});
|
|
},
|
|
|
|
// 开始绘制
|
|
startDrawing(mode) {
|
|
if (!this.fenceMap) {
|
|
this.$message.error('地图未初始化');
|
|
return;
|
|
}
|
|
|
|
this.clearDrawing();
|
|
this.drawingMode = mode;
|
|
|
|
if (mode === 'polygon') {
|
|
this.startPolygonDrawing();
|
|
} else if (mode === 'circle') {
|
|
this.startCircleDrawing();
|
|
}
|
|
},
|
|
|
|
// 开始多边形绘制
|
|
startPolygonDrawing() {
|
|
this.polygonPoints = [];
|
|
this.$message.info('点击地图绘制多边形,双击完成绘制');
|
|
|
|
// 监听地图点击事件
|
|
this.fenceMap.on('click', this.onPolygonClick);
|
|
this.fenceMap.on('dblclick', this.onPolygonComplete);
|
|
},
|
|
|
|
// 多边形点击事件
|
|
onPolygonClick(evt) {
|
|
if (this.drawingMode !== 'polygon') return;
|
|
|
|
const latLng = evt.latLng;
|
|
this.polygonPoints.push([latLng.lng, latLng.lat]);
|
|
|
|
// 绘制临时点
|
|
this.drawTempPoints();
|
|
},
|
|
|
|
// 完成多边形绘制
|
|
onPolygonComplete() {
|
|
if (this.drawingMode !== 'polygon' || this.polygonPoints.length < 3) {
|
|
this.$message.error('多边形至少需要3个点');
|
|
return;
|
|
}
|
|
|
|
this.drawPolygon();
|
|
this.fenceMap.off('click', this.onPolygonClick);
|
|
this.fenceMap.off('dblclick', this.onPolygonComplete);
|
|
},
|
|
|
|
// 开始圆形绘制
|
|
startCircleDrawing() {
|
|
this.$message.info('点击地图设置圆心,拖拽设置半径');
|
|
|
|
this.fenceMap.on('click', this.onCircleClick);
|
|
},
|
|
|
|
// 圆形点击事件
|
|
onCircleClick(evt) {
|
|
if (this.drawingMode !== 'circle') return;
|
|
|
|
const latLng = evt.latLng;
|
|
this.circleCenter = [latLng.lng, latLng.lat];
|
|
|
|
// 开始拖拽设置半径
|
|
this.fenceMap.off('click', this.onCircleClick);
|
|
this.fenceMap.on('mousemove', this.onCircleMouseMove);
|
|
this.fenceMap.on('click', this.onCircleRadiusSet);
|
|
},
|
|
|
|
// 圆形鼠标移动事件
|
|
onCircleMouseMove(evt) {
|
|
if (!this.circleCenter) return;
|
|
|
|
const latLng = evt.latLng;
|
|
const distance = this.calculateDistance(
|
|
this.circleCenter[1], this.circleCenter[0],
|
|
latLng.lat, latLng.lng
|
|
);
|
|
|
|
this.circleRadius = distance;
|
|
this.drawTempCircle();
|
|
},
|
|
|
|
// 设置圆形半径
|
|
onCircleRadiusSet() {
|
|
if (!this.circleCenter || this.circleRadius <= 0) {
|
|
this.$message.error('请设置有效的圆形区域');
|
|
return;
|
|
}
|
|
|
|
this.drawCircle();
|
|
this.fenceMap.off('mousemove', this.onCircleMouseMove);
|
|
this.fenceMap.off('click', this.onCircleRadiusSet);
|
|
},
|
|
|
|
// 绘制多边形
|
|
drawPolygon() {
|
|
if (this.currentDrawing) {
|
|
this.currentDrawing.setMap(null);
|
|
}
|
|
|
|
const paths = this.polygonPoints.map(point => new TMap.LatLng(point[1], point[0]));
|
|
|
|
this.currentDrawing = new TMap.MultiPolygon({
|
|
map: this.fenceMap,
|
|
styles: {
|
|
'polygon-style': new TMap.PolygonStyle({
|
|
color: 'rgba(255, 0, 0, 0.3)',
|
|
strokeColor: '#ff0000',
|
|
strokeWidth: 2
|
|
})
|
|
},
|
|
geometries: [{
|
|
id: 'fence-polygon',
|
|
styleId: 'polygon-style',
|
|
paths: [paths]
|
|
}]
|
|
});
|
|
|
|
this.fenceForm.fence_data = JSON.stringify({
|
|
type: 'polygon',
|
|
coordinates: [this.polygonPoints]
|
|
});
|
|
|
|
this.$message.success('多边形绘制完成');
|
|
},
|
|
|
|
// 绘制圆形
|
|
drawCircle() {
|
|
if (this.currentDrawing) {
|
|
this.currentDrawing.setMap(null);
|
|
}
|
|
|
|
this.currentDrawing = new TMap.MultiCircle({
|
|
map: this.fenceMap,
|
|
styles: {
|
|
'circle-style': new TMap.CircleStyle({
|
|
color: 'rgba(0, 0, 255, 0.3)',
|
|
strokeColor: '#0000ff',
|
|
strokeWidth: 2
|
|
})
|
|
},
|
|
geometries: [{
|
|
id: 'fence-circle',
|
|
styleId: 'circle-style',
|
|
center: new TMap.LatLng(this.circleCenter[1], this.circleCenter[0]),
|
|
radius: this.circleRadius
|
|
}]
|
|
});
|
|
|
|
this.fenceForm.fence_data = JSON.stringify({
|
|
type: 'circle',
|
|
center: this.circleCenter,
|
|
radius: this.circleRadius
|
|
});
|
|
|
|
this.$message.success('圆形绘制完成');
|
|
},
|
|
|
|
// 绘制临时点
|
|
drawTempPoints() {
|
|
// 清除之前的临时点
|
|
if (this.tempPoints) {
|
|
this.tempPoints.setMap(null);
|
|
}
|
|
|
|
const geometries = this.polygonPoints.map((point, index) => ({
|
|
id: `temp-point-${index}`,
|
|
styleId: 'point-style',
|
|
position: new TMap.LatLng(point[1], point[0])
|
|
}));
|
|
|
|
this.tempPoints = new TMap.MultiMarker({
|
|
map: this.fenceMap,
|
|
styles: {
|
|
'point-style': new TMap.MarkerStyle({
|
|
width: 8,
|
|
height: 8,
|
|
anchor: { x: 4, y: 4 },
|
|
color: '#ff0000'
|
|
})
|
|
},
|
|
geometries: geometries
|
|
});
|
|
},
|
|
|
|
// 绘制临时圆形
|
|
drawTempCircle() {
|
|
if (this.tempCircle) {
|
|
this.tempCircle.setMap(null);
|
|
}
|
|
|
|
this.tempCircle = new TMap.MultiCircle({
|
|
map: this.fenceMap,
|
|
styles: {
|
|
'temp-circle-style': new TMap.CircleStyle({
|
|
color: 'rgba(0, 0, 255, 0.1)',
|
|
strokeColor: '#0000ff',
|
|
strokeWidth: 1,
|
|
strokeDashArray: [5, 5]
|
|
})
|
|
},
|
|
geometries: [{
|
|
id: 'temp-circle',
|
|
styleId: 'temp-circle-style',
|
|
center: new TMap.LatLng(this.circleCenter[1], this.circleCenter[0]),
|
|
radius: this.circleRadius
|
|
}]
|
|
});
|
|
},
|
|
|
|
// 清除绘制
|
|
clearDrawing() {
|
|
this.drawingMode = '';
|
|
this.polygonPoints = [];
|
|
this.circleCenter = null;
|
|
this.circleRadius = 0;
|
|
|
|
if (this.currentDrawing) {
|
|
this.currentDrawing.setMap(null);
|
|
this.currentDrawing = null;
|
|
}
|
|
|
|
if (this.tempPoints) {
|
|
this.tempPoints.setMap(null);
|
|
this.tempPoints = null;
|
|
}
|
|
|
|
if (this.tempCircle) {
|
|
this.tempCircle.setMap(null);
|
|
this.tempCircle = null;
|
|
}
|
|
|
|
// 移除所有事件监听
|
|
if (this.fenceMap) {
|
|
this.fenceMap.off('click', this.onPolygonClick);
|
|
this.fenceMap.off('dblclick', this.onPolygonComplete);
|
|
this.fenceMap.off('click', this.onCircleClick);
|
|
this.fenceMap.off('mousemove', this.onCircleMouseMove);
|
|
this.fenceMap.off('click', this.onCircleRadiusSet);
|
|
}
|
|
},
|
|
|
|
// 完成绘制
|
|
completeDrawing() {
|
|
if (this.drawingMode === 'polygon' && this.polygonPoints.length >= 3) {
|
|
this.onPolygonComplete();
|
|
} else if (this.drawingMode === 'circle' && this.circleCenter && this.circleRadius > 0) {
|
|
this.drawCircle();
|
|
} else {
|
|
this.$message.error('请先完成围栏绘制');
|
|
}
|
|
},
|
|
|
|
// 在地图上加载围栏
|
|
loadFenceOnMap(fenceData) {
|
|
if (!fenceData || !this.fenceMap) return;
|
|
|
|
try {
|
|
const data = JSON.parse(fenceData);
|
|
|
|
if (data.type === 'polygon') {
|
|
this.polygonPoints = data.coordinates[0];
|
|
this.drawPolygon();
|
|
} else if (data.type === 'circle') {
|
|
this.circleCenter = data.center;
|
|
this.circleRadius = data.radius;
|
|
this.drawCircle();
|
|
}
|
|
} catch (error) {
|
|
console.error('加载围栏数据失败:', error);
|
|
}
|
|
},
|
|
|
|
// 计算两点间距离(米)
|
|
calculateDistance(lat1, lng1, lat2, lng2) {
|
|
const R = 6371000; // 地球半径(米)
|
|
const dLat = (lat2 - lat1) * Math.PI / 180;
|
|
const dLng = (lng2 - lng1) * Math.PI / 180;
|
|
const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
|
|
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
|
|
Math.sin(dLng/2) * Math.sin(dLng/2);
|
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
|
|
return R * c;
|
|
},
|
|
|
|
// 格式化坐标数据显示
|
|
formatCoordinates(fenceData) {
|
|
if (!fenceData) return '';
|
|
|
|
try {
|
|
const data = JSON.parse(fenceData);
|
|
if (data.type === 'polygon') {
|
|
return `多边形坐标点 (${data.coordinates[0].length}个点):\n` +
|
|
data.coordinates[0].map((point, index) =>
|
|
`${index + 1}. 经度: ${point[0].toFixed(6)}, 纬度: ${point[1].toFixed(6)}`
|
|
).join('\n');
|
|
} else if (data.type === 'circle') {
|
|
return `圆形围栏:\n` +
|
|
`圆心: 经度: ${data.center[0].toFixed(6)}, 纬度: ${data.center[1].toFixed(6)}\n` +
|
|
`半径: ${data.radius.toFixed(2)} 米`;
|
|
}
|
|
} catch (error) {
|
|
return '坐标数据格式错误';
|
|
}
|
|
|
|
return '';
|
|
},
|
|
|
|
// 格式化时间
|
|
formatTime(timestamp) {
|
|
if (!timestamp) return '';
|
|
const date = new Date(timestamp * 1000);
|
|
return date.toLocaleString('zh-CN');
|
|
},
|
|
|
|
// 分页处理
|
|
handleSizeChange(size) {
|
|
this.pagination.size = size;
|
|
this.pagination.page = 1;
|
|
this.loadFenceList();
|
|
},
|
|
|
|
handleCurrentChange(page) {
|
|
this.pagination.page = page;
|
|
this.loadFenceList();
|
|
},
|
|
|
|
// HTTP请求封装
|
|
async request(url, data = {}) {
|
|
return new Promise((resolve, reject) => {
|
|
$.ajax({
|
|
url: url,
|
|
type: 'POST',
|
|
data: data,
|
|
dataType: 'json',
|
|
success: function(response) {
|
|
resolve(response);
|
|
},
|
|
error: function(xhr, status, error) {
|
|
reject(error);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
},
|
|
|
|
mounted() {
|
|
this.init();
|
|
},
|
|
|
|
beforeDestroy() {
|
|
// 清理地图资源
|
|
if (this.fenceMap) {
|
|
this.fenceMap.destroy();
|
|
}
|
|
}
|
|
});
|
|
</script> |