文章同步更新于我的个人博客:松果猿的博客,欢迎访问获取更多技术分享。
同时,您也可以关注我的微信公众号:松果猿的代码工坊,获取最新文章推送和编程技巧。
前言
通过前一期我们只实现了单车投放区域的查询和定位,下面我们来实现增设投放区域的功能
流程
新建src/components/RegionDialog.vue,用于显示和收集区域信息的表单:
<template>
<div class="dialog-container">
<div class="region-dialog-header">
<el-icon class="close-icon" @click="handleClose"><Close /></el-icon>
</div>
<div class="region-dialog-content">
<el-form :model="form" label-width="auto" style="max-width: 600px">
<el-form-item label="区域类型">
<el-select
@change="handleGeometryChange"
placeholder="请选择区域类型"
>
<el-option label="圆形" value="Circle" />
<el-option label="矩形" value="Box" />
<el-option label="多边形" value="Polygon" />
</el-select>
</el-form-item>
<el-form-item label="区域名称">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="区域容量">
<el-input v-model="form.capacity" />
</el-form-item>
<el-form-item label="区域存量">
<el-input v-model="form.exist" />
</el-form-item>
<el-button @click="handleConfirm">确定</el-button>
</el-form>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import { Close } from "@element-plus/icons-vue";
const form = ref({
geometry: "",
name: "",
capacity: "",
exist: "",
});
const handleConfirm = () => {
};
const handleClose = () => {
};
const handleGeometryChange = async (value) => {
};
</script>
<style lang="scss" scoped>
.dialog-container {
position: absolute;
width: 300px;
height: 270px;
background-color: #fff;
top: 100px;
right: 50px;
border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
padding: 20px;
.region-dialog-header {
margin-bottom: 10px;
text-align: right;
border-bottom: 1px solid #ebeef5;
.close-icon {
cursor: pointer;
font-size: 20px;
transition: all 0.3s;
&:hover {
color: #409eff;
transform: rotate(90deg);
}
}
}
}
</style>
在store/contentStore.ts中添加状态管理,用于控制对话框的显示和隐藏:
在Header.vue中添加必要代码,以便在用户界面中显示和隐藏区域对话框:
在Home.vue中添加:
完成效果如下:
新建@/hooks/useRegionDraw.js,填写如下代码,将绘制的图层转为wkt数据:
import { useMapStore } from "@/stores/mapStore";
import { Vector as VectorSource } from "ol/source";
import { Vector as VectorLayer } from "ol/layer";
import { Draw } from "ol/interaction";
import { ref } from "vue";
import { WKT} from "ol/format";
import { Circle} from "ol/geom";
import { fromCircle } from "ol/geom/Polygon";
import { createBox } from "ol/interaction/Draw";
export function useRegionDraw() {
const mapStore = useMapStore();
const map = mapStore.map;
const source = new VectorSource();
const wktFormat = new WKT();
const vector = new VectorLayer({
source: source,
style: {
"fill-color": "rgba(255, 255, 255, 0.2)",
"stroke-color": "#ffcc33",
"stroke-width": 2,
"circle-radius": 7,
"circle-fill-color": "#ffcc33",
},
});
const draw = ref(null);
const DrawGeometry = (geometry) => {
if (geometry == "Box") {
draw.value = new Draw({
source: source,
type: "Circle",
geometryFunction: createBox(),
});
} else {
draw.value = new Draw({
source: source,
type: geometry,
});
}
map.addLayer(vector);
map.addInteraction(draw.value);
return new Promise((resolve) => {
draw.value.on("drawend", function (event) {
map.removeInteraction(draw.value);
const drawFeature = event.feature;
let drawGeometry = drawFeature.getGeometry();
if (drawGeometry instanceof Circle) {
drawGeometry = fromCircle(drawGeometry);
}
const wkt = wktFormat.writeGeometry(drawGeometry,{
dataProjection: "EPSG:4326",
featureProjection: "EPSG:3857",
});
resolve(wkt);
});
});
};
const deleteDraw = () => {
map.removeInteraction(draw.value);
map.removeLayer(vector);
source.clear();
};
return {
DrawGeometry,
deleteDraw,
};
}
修改RegionDialog.vue,添加必要的hooks函数,:
import { ref } from "vue";
import { useContentStore } from "@/stores/contentStore";
import { useRegionDraw } from "@/hooks/useRegionDraw";
import { Close } from "@element-plus/icons-vue";
import axios from "axios";
const contentStore = useContentStore();
const { DrawGeometry,deleteDraw } = useRegionDraw();
const form = ref({
geometry: "",
name: "",
capacity: "",
exist: "",
});
const addRegion = async () => {
try {
console.log(form.value);
const res = await axios.post(`${import.meta.env.VITE_API_URL}/regions`,form.value);
deleteDraw();
ElMessage.success("添加区域成功");
form.value = {
geometry: "",
name: "",
capacity: "",
exist: "",
};
} catch (error) {
console.error("获取区域数据失败:", error);
ElMessage.error("获取区域数据失败");
}
};
const handleConfirm = () => {
addRegion();
};
const handleClose = () => {
deleteDraw();
contentStore.toggleRegionDialog(false);
};
const handleGeometryChange = async (value) => {
try {
const wkt = await DrawGeometry(value);
form.value.geometry = wkt;
} catch (error) {
console.error('绘制区域失败:', error);
ElMessage.error('绘制区域失败');
}
};
启动后端服务,实现效果如下: