Files
dm-manage-web/src/views/sch/place/index.vue
2023-09-13 15:31:45 +08:00

747 lines
24 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="amap-page-container">
<div id="map" class="amap-cavans" />
<el-input id="search" v-model="searchBody" class="search-body" placeholder="请输入..." @keyup.enter.native="submitSearch">
<el-button slot="append" icon="el-icon-search" @click="submitSearch" />
</el-input>
<div class="asider" :class="showSchool ? '' : 'hidden-school'">
<el-card class="box-card" :body-style="{ flex: 1, 'overflow-y': 'scroll', padding: 0 }">
<div slot="header" class="clearfix">
<div class="map-card-title">驾校列表</div>
</div>
<div v-for="school in schoolList" :key="school.schoolId" style="margin:10px;" :class="currentdeptId == school.schoolId ? 'actived-school' : ''">
<el-card :body-style="{ padding: '10px' }">
<div slot="header" class="clearfix">
<div class="map-card-title">{{ school.schoolName }}</div>
<el-switch v-model="school.showInMap" v-hasPermi="['sch:place:edit']" class="add-icon" active-text="展示" inactive-text="隐藏" @change="changeSchoolStatus(school)" />
</div>
<el-button @click="handleClickSchool(school)">{{ `数据管理(${getCount(school.schoolId)})` }}</el-button>
<el-tooltip v-hasPermi="['sch:place:add']" content="新增场地" placement="left" effect="dark">
<el-button icon="el-icon-plus" class="add-place-btn" @click="handleInsertPlace(school.schoolId)" />
</el-tooltip>
</el-card>
</div>
</el-card>
<div class="asider-sub">
<el-tooltip content="放大" placement="left" effect="dark">
<el-button icon="el-icon-plus" class="is-circle" :disabled="zomm >= 18" @click="bigger" />
</el-tooltip>
<el-tooltip content="缩小" placement="left" effect="dark">
<el-button icon="el-icon-minus" class="is-circle" :disabled="zomm <= 8" @click="smaller" />
</el-tooltip>
<div class="mt10">
<el-tooltip content="驾校" placement="left" effect="dark">
<el-button icon="el-icon-school" class="is-circle" @click="toggleSchool" />
</el-tooltip>
<el-tooltip content="定位" placement="left" effect="dark">
<el-button icon="el-icon-help" class="is-circle" @click="geolocation" />
</el-tooltip>
<el-tooltip content="测距" placement="left" effect="dark">
<el-button icon="el-icon-thumb" class="is-circle" @click="ranging" />
</el-tooltip>
<el-tooltip content="分享" placement="left" effect="dark">
<el-button icon="el-icon-share" class="is-circle" />
</el-tooltip>
</div>
</div>
</div>
<el-card v-if="placeDialogShow" class="place-dialog" :body-style="{ padding: '10px' }">
<div slot="header" class="clearfix">
<div class="map-card-title">场地设置</div>
<el-tooltip content="取点" placement="right" effect="dark">
<el-button icon="el-icon-location" class="add-icon" @click="getPoint" />
</el-tooltip>
</div>
<el-form ref="placeForm" :model="placeForm" label-width="70px">
<el-form-item label="所属驾校" prop="schoolId">
<el-select v-model="placeForm.schoolId" placeholder="请选择" clearable>
<el-option v-for="dict in schoolList" :key="dict.schoolId" :label="dict.schoolName" :value="dict.schoolId" />
</el-select>
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input v-model="placeForm.name" placeholder="输入名称" />
</el-form-item>
<el-form-item label="旗子颜色" prop="flagColor">
<el-radio-group v-model="placeForm.flagColor">
<el-radio v-for="(item, index) in colorOptions" :key="index" :label="item">
<img :src="require(`@/assets/images/place/flag_${item}.png`)" width="20px">
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="地址" prop="address">
<el-input v-model="placeForm.address" placeholder="输入地址" />
</el-form-item>
<el-form-item label="经度" prop="lng">
<el-input v-model="placeForm.lng" placeholder="输入经度" />
</el-form-item>
<el-form-item label="纬度" prop="lat">
<el-input v-model="placeForm.lat" placeholder="输入纬度" />
</el-form-item>
<el-form-item label="所属区域" prop="area">
<el-select v-model="placeForm.area" placeholder="请选择" clearable size="small">
<el-option v-for="dict in areaOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
</el-select>
</el-form-item>
<el-form-item label="电话" prop="phone">
<el-input v-model="placeForm.phone" placeholder="输入电话" />
</el-form-item>
<el-form-item label="负责人" prop="contact">
<el-input v-model="placeForm.contact" placeholder="输入负责人" />
</el-form-item>
<el-form-item label="是否推荐" prop="contact">
<el-radio v-model="placeForm.recommend" :label="true"></el-radio>
<el-radio v-model="placeForm.recommend" :label="false"></el-radio>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="placeForm.remark" placeholder="输入备注" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }" />
</el-form-item>
<el-form-item style="text-align:right;">
<el-button v-hasPermi="['sch:place:edit']" type="primary" @click="onSubmit">保存</el-button>
<el-button @click="closePlaceDialog">取消</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card :class="placeListDialogShow ? '' : 'hidden-place-list'" class="place-list-dialog" :style="{ right: showSchool ? '300px' : '0', top: fullScreenPlaceList ? '0px' : '420px' }" :body-style="{ padding: '10px', height: 'calc(100% - 52px)' }">
<div slot="header" class="clearfix">
<div class="map-card-title">
{{ placeListDialogTitle }}
<el-input v-model="tableSearch" placeholder="请输入搜索的内容" clearable />
</div>
<el-tooltip content="全屏" placement="top" effect="dark">
<el-button icon="el-icon-full-screen" class="add-icon" @click="fullScreenPlaceList = !fullScreenPlaceList" />
</el-tooltip>
<el-tooltip content="关闭" placement="top" effect="dark">
<el-button icon="el-icon-close" class="add-icon" @click="() => { placeListDialogShow = false; fullScreenPlaceList = false }" />
</el-tooltip>
</div>
<el-table :data="placeTableData" border stripe class="place-table-list" height="100%">
<el-table-column label="序号" type="index" fixed="left" width="50" />
<el-table-column prop="name" label="名称" min-width="100" />
<el-table-column prop="phone" label="电话" width="120" />
<el-table-column prop="contact" label="负责人" width="120" />
<el-table-column prop="address" label="地址" min-width="100" />
<el-table-column prop="lng" label="经度" width="110" />
<el-table-column prop="lat" label="纬度" width="110" />
<el-table-column prop="area" label="所属区域" width="110" />
<el-table-column label="展示" width="100">
<template slot-scope="scope">
<el-switch v-model="scope.row.showInMap" v-hasPermi="['sch:place:edit']" @change="changePlaceStatus(scope.row)" />
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template slot-scope="scope">
<el-tooltip v-hasPermi="['sch:place:edit']" content="编辑" placement="top" effect="dark">
<el-button icon="el-icon-edit" type="primary" style="padding: 4px 8px;" @click="handleEditPlace(scope.row)" />
</el-tooltip>
</template>
</el-table-column>
</el-table>
</el-card>
<div v-if="isPointing || isRanging" class="map-tip" :style="{ transform: 'translate3D(' + (tipPostion.x + 15) + 'px,' + (tipPostion.y - 10) + 'px, 0)' }">{{ mapHelpText }}</div>
<i v-if="isPointing" class="el-icon-s-flag circle" :style="{ transform: 'translate3D(' + tipPostion.x + 'px,' + tipPostion.y + 'px, 0)' }" />
</div>
</template>
<!-- eslint-disable no-undef -->
<script>
import { getMapData, addPlace, updatePlace, updateSchoolStatus } from '@/api/sch/place';
export default {
name: 'Place',
data() {
return {
aMap: null,
zomm: 12,
showSchool: true,
isRanging: false,
aMapLocation: null,
aMouseTool: null,
searchBody: '',
placeSearch: null,
placeDialogShow: false,
isPointing: false,
placeForm: {
lat: undefined,
lng: undefined,
name: undefined,
address: undefined,
remark: undefined,
phone: undefined,
flagColor: 'red'
},
colorOptions: ['red', 'yellow', 'blue', 'green', 'purple', 'black'],
mapHelpText: '',
tipPostion: {
x: 0,
y: 0
},
geocoder: null,
locationMarker: null,
selectMarker: null,
placeListDialogShow: false,
placeListDialogTitle: '',
fullScreenPlaceList: false,
tableSearch: '',
tableData: [],
schoolList: [],
currentdeptId: undefined,
placeMarkerList: [],
areaOptions: []
};
},
computed: {
placeTableData: function () {
if (this.tableSearch) {
return this.tableData.filter((dataNews) => {
return (
dataNews.schoolId === this.currentdeptId &&
Object.keys(dataNews).some((key) => {
return String(dataNews[key]).toLowerCase().indexOf(this.tableSearch) > -1;
})
);
});
}
return this.tableData.filter((dataNews) => dataNews.schoolId === this.currentdeptId);
}
},
mounted() {
this.initMap();
this.getDicts('dm_area').then((response) => {
this.areaOptions = response.data;
});
},
methods: {
initMap() {
window.onLoad = () => {
this.aMap = new AMap.Map('map', {
zoom: this.zomm,
center: [117.226095, 31.814372],
zooms: [8, 18]
});
// 监听缩放
this.aMap.on('zoomend', () => {
this.zomm = this.aMap.getZoom();
this.$message('当前缩放等级:' + this.zomm);
});
// 监听点击
this.aMap.on('click', (ev) => {
if (this.isPointing) {
this.placeForm.lat = ev.lnglat.lat;
this.placeForm.lng = ev.lnglat.lng;
this.regeoCode();
if (this.selectMarker) {
this.selectMarker.setPosition([this.placeForm.lng, this.placeForm.lat]);
} else {
this.locationMarker.setPosition([this.placeForm.lng, this.placeForm.lat]);
this.aMap.add(this.locationMarker);
}
this.isPointing = false;
}
});
// 监听移动
this.aMap.on('mousemove', (ev) => {
if (this.isRanging) {
this.mapHelpText = '左键单击选点,双击/右键单击完成选点,再次点击测距按钮可退出测距模式,并清除测距结果';
this.tipPostion = {
x: ev.pixel.x,
y: ev.pixel.y
};
} else if (this.isPointing) {
this.mapHelpText = '点击地图添加标注';
this.tipPostion = {
x: ev.pixel.x,
y: ev.pixel.y
};
}
});
// 添加地图插件
AMap.plugin(['AMap.Scale', 'AMap.Geolocation', 'AMap.MouseTool', 'AMap.PlaceSearch', 'AMap.Autocomplete', 'AMap.Geocoder'], () => {
this.aMap.addControl(new AMap.Scale());
const geoLoca = new AMap.Geolocation({
showButton: false
});
this.aMapLocation = geoLoca;
this.aMap.addControl(geoLoca);
this.aMouseTool = new AMap.MouseTool(this.aMap);
const auto = new AMap.Autocomplete({
input: 'search' // 前端搜索框
});
this.placeSearch = new AMap.PlaceSearch({
map: this.aMap
});
AMap.event.addListener(auto, 'select', this.select);
this.geocoder = new AMap.Geocoder();
this.locationMarker = new AMap.Marker({
icon: require(`@/assets/images/place/flag_red.png`)
});
});
this.getPageData();
};
this.importMap();
},
// 导入地图
importMap() {
const url = 'https://webapi.amap.com/maps?v=1.4.15&key=0e62be0896c6b8d27d453445f0fb8bc4&callback=onLoad';
var jsapi = document.createElement('script');
jsapi.charset = 'utf-8';
jsapi.src = url;
document.head.appendChild(jsapi);
},
toggleSchool() {
this.showSchool = !this.showSchool;
},
// 经纬度 -> 地址
regeoCode() {
this.geocoder.getAddress([this.placeForm.lng, this.placeForm.lat], (status, result) => {
if (status === 'complete' && result.regeocode) {
this.placeForm.address = result.regeocode.formattedAddress;
} else {
console.log('根据经纬度查询地址失败');
}
});
},
// 定位
geolocation() {
this.aMapLocation.getCurrentPosition();
},
// 测距
ranging() {
this.isPointing = false;
this.isRanging = !this.isRanging;
if (this.isRanging) {
this.aMap.setDefaultCursor('crosshair');
this.drawLine();
} else {
this.aMap.setDefaultCursor('default');
this.aMouseTool.close(true);
}
},
// 画线
drawLine() {
this.aMouseTool.rule({
startMarkerOptions: {
// 可缺省
icon: new AMap.Icon({
size: new AMap.Size(19, 31), // 图标大小
imageSize: new AMap.Size(19, 31),
image: 'https://webapi.amap.com/theme/v1.3/markers/b/start.png'
})
},
endMarkerOptions: {
// 可缺省
icon: new AMap.Icon({
size: new AMap.Size(19, 31), // 图标大小
imageSize: new AMap.Size(19, 31),
image: 'https://webapi.amap.com/theme/v1.3/markers/b/end.png'
}),
offset: new AMap.Pixel(-9, -31)
},
midMarkerOptions: {
// 可缺省
icon: new AMap.Icon({
size: new AMap.Size(19, 31), // 图标大小
imageSize: new AMap.Size(19, 31),
image: 'https://webapi.amap.com/theme/v1.3/markers/b/mid.png'
}),
offset: new AMap.Pixel(-9, -31)
},
lineOptions: {
// 可缺省
strokeStyle: 'solid',
strokeColor: '#FF33FF',
strokeOpacity: 1,
strokeWeight: 2
},
tmpLineOptions: {
strokeStyle: 'dashed',
strokeColor: '#FF33FF',
strokeOpacity: 1,
strokeWeight: 2
}
});
},
// 选择查询结果
select(e) {
this.placeSearch.setCity(e.poi.adcode);
this.placeSearch.search(e.poi.name); // 关键字查询查询
},
// 查询按钮/回车事件
submitSearch() {
this.placeSearch.search(this.searchBody);
},
// 缩放
bigger() {
this.zomm++;
this.aMap.setZoom(this.zomm);
},
smaller() {
this.zomm--;
this.aMap.setZoom(this.zomm);
},
// 点击数据管理
handleClickSchool(item) {
this.placeListDialogShow = true;
this.placeListDialogTitle = `数据管理 [${item.schoolName}]`;
this.currentdeptId = item.schoolId;
},
// 新增场地
handleInsertPlace(schoolId) {
if (this.selectMarker) {
this.selectMarker.setAnimation('AMAP_ANIMATION_NONE');
this.selectMarker = null;
}
this.placeDialogShow = true;
this.aMap.setDefaultCursor('default');
this.isRanging = false;
this.placeForm = {
lat: undefined,
lng: undefined,
name: undefined,
address: undefined,
remark: undefined,
phone: undefined,
schoolId: schoolId,
showInMap: true,
flagColor: 'red'
};
},
// 编辑场地
handleEditPlace(item) {
this.placeDialogShow = true;
this.aMap.setDefaultCursor('default');
if (this.selectMarker) {
this.selectMarker.setAnimation('AMAP_ANIMATION_NONE');
}
this.isRanging = false;
this.placeForm = Object.assign({}, item);
this.selectMarker = this.placeMarkerList.filter((marker) => marker.getExtData().placeId === item.placeId)[0];
this.selectMarker && this.selectMarker.setAnimation('AMAP_ANIMATION_BOUNCE');
this.aMap.setCenter([item.lng, item.lat]);
},
getPoint() {
this.isPointing = !this.isPointing;
},
// 保存
async onSubmit() {
// 保存接口
if (this.checkPlaceFormValidate()) {
// 先访问接口返回id插入placeForm
const resp = this.savePlace(this.placeForm);
if (resp.code != 200) {
return;
} else {
this.$message.success('操作成功');
}
if (!this.placeForm.placeId && resp.data) {
this.$set(this.placeForm, 'placeId', resp.data);
}
// 移除选点用 的标记
this.aMap.remove(this.locationMarker);
// 根据form创建新marker 并添加到地图上
const tmpMarker = new AMap.Marker({
map: this.aMap,
position: [this.placeForm.lng, this.placeForm.lat],
icon: require(`@/assets/images/place/flag_${this.placeForm.flagColor}.png`),
label: {
content: this.placeForm.name,
direction: 'right'
},
extData: this.placeForm
});
// 新marker事件
tmpMarker.on('click', this.handleClickMarker);
// 如果当前选择的marker点存在编辑
if (this.selectMarker) {
// 地图上 移除选择的点
this.aMap.remove(this.selectMarker);
this.selectMarker = null;
}
// 关闭场地弹窗
this.placeDialogShow = false;
this.isPointing = false;
// 场地列表 移除原列表中操作的场地数据
const tmpArr = this.tableData.filter((item) => item.placeId !== this.placeForm.placeId);
// 新增新的场地
tmpArr.push(this.placeForm);
// 重置场地数组
this.tableData = tmpArr;
// 地图marker列表 移除操作的原marker 添加新marker进数组
const tmpArr1 = this.placeMarkerList.filter((item) => item.getExtData().placeId !== this.placeForm.placeId);
tmpArr1.push(tmpMarker);
this.placeMarkerList = tmpArr1;
}
},
async savePlace(item) {
if (item.placeId) {
return updatePlace(item);
} else {
return addPlace(item);
}
},
checkPlaceFormValidate() {
const valid = [];
if (!this.placeForm.name) {
valid.push('名称');
}
if (!this.placeForm.address) {
valid.push('地址');
}
if (!this.placeForm.lng) {
valid.push('经度');
}
if (!this.placeForm.lat) {
valid.push('纬度');
}
if (!this.placeForm.phone) {
valid.push('电话');
}
if (valid.length == 0) {
return true;
} else {
this.$message.error(`请将以下填写完整: ${valid.join(',')}`);
return false;
}
},
// 关闭场地弹窗
closePlaceDialog() {
this.placeDialogShow = false;
this.isPointing = false;
this.aMap.remove(this.locationMarker);
if (this.selectMarker) {
this.selectMarker.setAnimation('AMAP_ANIMATION_NONE');
this.selectMarker = null;
}
},
handleClickMarker(ev) {
if (this.selectMarker) {
this.selectMarker.setAnimation('AMAP_ANIMATION_NONE');
}
this.placeForm = ev.target.getExtData();
this.placeDialogShow = true;
ev.target.setAnimation('AMAP_ANIMATION_BOUNCE');
this.selectMarker = ev.target;
},
getPageData() {
getMapData().then((resp) => {
if (resp.code == 200) {
this.schoolList = resp.data.schoolList;
this.tableData = resp.data.placeList;
this.currentdeptId = this.schoolList[0].schoolId;
this.createMarkersInMap();
}
});
},
getCount(schoolId) {
return this.tableData.filter((item) => item.schoolId === schoolId).length;
},
// 重置markers
resetMarkers() {
this.aMap.clearMap();
this.createMarkersInMap();
},
// 生成markers
createMarkersInMap() {
for (let i = 0; i < this.tableData.length; i++) {
const element = this.tableData[i];
const tempSchool = this.schoolList.filter((item) => item.schoolId === element.schoolId)[0];
if (!element.schoolShow || !element.showInMap) {
continue;
}
const tmpMarker = new AMap.Marker({
map: this.aMap,
position: [element.lng, element.lat],
icon: require(`@/assets/images/place/flag_${element.flagColor}.png`),
label: {
content: element.name,
direction: 'right'
},
extData: element
});
tmpMarker.on('click', this.handleClickMarker);
this.placeMarkerList.push(tmpMarker);
}
},
// 修改驾校状态
changeSchoolStatus(item) {
// 访问接口成功后重置markers
updateSchoolStatus(item).then((resp) => {
if (resp.code == 200) {
this.$message.success('操作成功');
// this.aMap.clearMap()
// this.getPageData()
this.resetMarkers();
}
});
},
// 修改场地状态
async changePlaceStatus(item) {
const resp = await updatePlace(item);
if (resp.code == 200) {
this.resetMarkers();
}
}
}
};
</script>
<style scoped>
.amap-page-container {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.amap-cavans {
width: 100%;
height: 100%;
}
.asider {
position: absolute;
right: 0;
top: 0;
width: 300px;
height: 100%;
transition: 0.3s;
z-index: 9;
}
.box-card {
display: flex;
flex-direction: column;
height: 100%;
}
::v-deep .el-card__header {
padding: 10px 15px;
}
.clearfix {
display: flex;
}
.clearfix .map-card-title {
flex: 1;
line-height: 30px;
}
.clearfix .add-icon {
width: auto;
height: 30px;
}
.asider-sub {
position: absolute;
top: 40px;
left: -45px;
padding: 10px 10px 0 0;
z-index: 900;
}
.asider-sub .is-circle {
display: block;
margin: 0;
padding: 10px;
color: #464646;
border-radius: 0;
font-size: 16px;
box-shadow: 2px 2px 2px rgba(80, 80, 80, 0.67);
}
.mt10 {
margin-top: 10px;
}
.hidden-school {
transform: translateX(300px);
}
.search-body {
position: absolute;
top: 20px;
left: 20px;
width: 400px;
}
.add-place-btn {
float: right;
border: none;
font-size: 16px;
color: #409eff;
}
::v-deep .place-dialog {
position: absolute;
left: 20px;
top: 60px;
width: 350px;
}
.map-tip {
position: absolute;
left: 0;
top: 0;
max-width: 150px;
padding: 5px;
border-radius: 2px;
background: #000;
color: #fff;
opacity: 0.7;
font-size: 12px;
transition-duration: 1ms;
}
.circle {
position: absolute;
left: -8px;
top: -25px;
font-size: 24px;
color: red;
transition-duration: 1ms;
}
.place-dialog .el-form .el-form-item {
margin-bottom: 8px;
}
.place-list-dialog {
position: absolute;
top: 420px;
left: 0;
bottom: 0;
transition: 0.3s;
z-index: 151;
background: #e2e5ea;
}
.place-list-dialog .add-icon {
font-size: 18px;
border: none;
}
.hidden-place-list {
transform: translateY(100%);
}
.place-list-dialog .clearfix .map-card-title {
font-weight: bold;
}
.place-list-dialog .clearfix .map-card-title .el-input {
margin-left: 20px;
width: 240px;
}
.actived-school {
border: 2px solid #409eff !important;
}
::v-deep .el-radio__label {
vertical-align: middle;
}
</style>