278 lines
8.5 KiB
Vue
278 lines
8.5 KiB
Vue
<template>
|
||
<el-dialog
|
||
title="请设置住宿范围"
|
||
append-to-body
|
||
:close-on-click-modal="false"
|
||
v-model="visible"
|
||
width="90%">
|
||
<div>
|
||
<el-form :model="form" :rules="rules" ref="formRef" class="demo-ruleForm">
|
||
<el-form-item label="住宿半径(米)" prop="raidus">
|
||
<el-input-number v-model="form.raidus" :min="0" style="width: 100%"></el-input-number>
|
||
</el-form-item>
|
||
</el-form>
|
||
<div id="container"></div>
|
||
</div>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<el-button @click="visible = false">取消</el-button>
|
||
<el-button type="primary" @click="dataFormSubmit">确定</el-button>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, reactive, watch, nextTick } from 'vue'
|
||
import { useMessage, useMessageBox } from '/@/hooks/message'
|
||
import { loadTiandituMap } from "/@/api/recruit/recruitstudentsignup"
|
||
import { editDormrange } from "/@/api/admin/dict"
|
||
import { getDicts } from "/@/api/admin/dict"
|
||
import { TIANDITU_TOKEN } from '/@/config/map'
|
||
|
||
// 消息提示 hooks
|
||
const message = useMessage()
|
||
const messageBox = useMessageBox()
|
||
|
||
// 表单引用
|
||
const formRef = ref()
|
||
|
||
// 响应式数据
|
||
const tk = TIANDITU_TOKEN // 天地图的token(在 src/config/map.ts 中配置)
|
||
const visible = ref(false)
|
||
const canSubmit = ref(false)
|
||
const circleShow = ref(false)
|
||
const circle = ref<any>(null)
|
||
const map = ref<any>(null)
|
||
|
||
// 地址信息
|
||
const center = reactive({ lng: 0, lat: 0 })
|
||
const dictId = ref("")
|
||
|
||
const form = reactive({
|
||
raidus: 0,
|
||
})
|
||
|
||
const rules = {
|
||
raidus: [
|
||
{ required: true, message: '住宿半径不能为空', trigger: ["blur", "change"] }
|
||
],
|
||
}
|
||
|
||
// 监听半径变化
|
||
watch(() => form.raidus, (newVal) => {
|
||
if (newVal !== 0 && newVal !== undefined && circle.value && map.value) {
|
||
// 移除旧圆形
|
||
map.value.removeOverLay(circle.value)
|
||
// 创建新圆形(确保数据类型正确)
|
||
// @ts-ignore
|
||
const newCircle = new window.T.Circle(
|
||
// @ts-ignore
|
||
new window.T.LngLat(
|
||
// @ts-ignore
|
||
parseFloat(center.lng),
|
||
// @ts-ignore
|
||
parseFloat(center.lat)
|
||
),
|
||
// @ts-ignore
|
||
parseFloat(newVal), // 确保半径是数字类型
|
||
{
|
||
color: '#FF0000', // 边框颜色:鲜红色
|
||
weight: 4, // 边框粗细:4像素
|
||
opacity: 0.9, // 边框不透明度:90%
|
||
fillColor: '#FF4444', // 填充颜色:亮红色
|
||
fillOpacity: 0.12 // 填充透明度:12%
|
||
}
|
||
)
|
||
map.value.addOverLay(newCircle)
|
||
circle.value = newCircle
|
||
|
||
// 让新圆形也不拦截鼠标事件
|
||
setTimeout(() => {
|
||
const circleElements = document.querySelectorAll('.tdt-circle, [class*="circle"]')
|
||
circleElements.forEach((el: any) => {
|
||
el.style.pointerEvents = 'none'
|
||
})
|
||
}, 100)
|
||
}
|
||
})
|
||
|
||
// 初始化
|
||
const init = () => {
|
||
visible.value = true
|
||
canSubmit.value = true
|
||
circleShow.value = true
|
||
nextTick(() => {
|
||
getDicts("dorm_jw").then((data: any) => {
|
||
const arr = data.data
|
||
arr.forEach((e: any) => {
|
||
if (e.label == 'bj') {
|
||
form.raidus = e.value
|
||
dictId.value = e.id
|
||
} else if (e.label == 'lng') {
|
||
center.lng = e.value
|
||
} else if (e.label == 'lat') {
|
||
center.lat = e.value
|
||
}
|
||
})
|
||
|
||
// 等待对话框渲染完成后再加载地图
|
||
setTimeout(() => {
|
||
// 调试信息:打印配置数据
|
||
// eslint-disable-next-line no-console
|
||
console.log('地图配置:', { lng: center.lng, lat: center.lat, radius: form.raidus, token: tk })
|
||
|
||
loadTiandituMap(tk).then((T: any) => {
|
||
// eslint-disable-next-line no-console
|
||
console.log('天地图API加载成功', T)
|
||
|
||
// 清除之前的地图实例(如果存在)
|
||
if (map.value) {
|
||
map.value.clearOverLays()
|
||
}
|
||
|
||
// 创建地图实例
|
||
map.value = new T.Map("container")
|
||
// 创建点坐标(确保经纬度是数字类型)
|
||
// @ts-ignore
|
||
const point = new T.LngLat(
|
||
// @ts-ignore
|
||
parseFloat(center.lng),
|
||
// @ts-ignore
|
||
parseFloat(center.lat)
|
||
)
|
||
|
||
// 根据半径自动计算合适的缩放级别
|
||
// @ts-ignore
|
||
const radius = parseFloat(form.raidus)
|
||
let zoomLevel = 12 // 默认缩放级别
|
||
|
||
// 根据半径动态调整缩放级别
|
||
if (radius <= 1000) {
|
||
zoomLevel = 15 // 1公里以内 - 非常近
|
||
} else if (radius <= 3000) {
|
||
zoomLevel = 14 // 3公里以内 - 近距离
|
||
} else if (radius <= 5000) {
|
||
zoomLevel = 13 // 5公里以内 - 中等距离
|
||
} else if (radius <= 10000) {
|
||
zoomLevel = 12 // 10公里以内 - 较远
|
||
} else if (radius <= 20000) {
|
||
zoomLevel = 11 // 20公里以内 - 远距离
|
||
} else {
|
||
zoomLevel = 10 // 20公里以上 - 超远距离
|
||
}
|
||
|
||
// 初始化地图,设置中心点坐标和地图级别
|
||
map.value.centerAndZoom(point, zoomLevel)
|
||
|
||
// eslint-disable-next-line no-console
|
||
console.log('地图缩放级别:', zoomLevel, '(半径:', radius, '米)')
|
||
|
||
// 添加地图类型切换控件(让用户可以切换卫星图/普通图)
|
||
const ctrl = new T.Control.MapType()
|
||
map.value.addControl(ctrl)
|
||
|
||
// 默认使用矢量地图(普通地图),用户可通过右上角控件切换到卫星图
|
||
|
||
// 绘制圆形覆盖物(使用前面已计算好的 radius 变量)
|
||
// eslint-disable-next-line no-console
|
||
console.log('绘制圆形:', { center: point, radius: radius, radiusType: typeof radius })
|
||
|
||
circle.value = new T.Circle(point, radius, {
|
||
color: '#FF0000', // 边框颜色:鲜红色,更醒目
|
||
weight: 4, // 边框粗细:4像素,更明显
|
||
opacity: 0.9, // 边框不透明度:90%,清晰可见
|
||
fillColor: '#FF4444', // 填充颜色:亮红色
|
||
fillOpacity: 0.12 // 填充透明度:12%,轻盈不遮挡地图
|
||
})
|
||
map.value.addOverLay(circle.value)
|
||
|
||
// 让圆形不拦截鼠标事件,使地图可以在圆圈内拖拽
|
||
// 通过 CSS 设置 pointer-events 为 none
|
||
setTimeout(() => {
|
||
const circleElements = document.querySelectorAll('.tdt-circle, [class*="circle"]')
|
||
circleElements.forEach((el: any) => {
|
||
el.style.pointerEvents = 'none'
|
||
})
|
||
}, 100)
|
||
|
||
// 添加中心点标记(更明显地标识中心位置)
|
||
const marker = new T.Marker(point)
|
||
map.value.addOverLay(marker)
|
||
|
||
// eslint-disable-next-line no-console
|
||
console.log('地图初始化完成 - 圆形已添加')
|
||
}).catch((error: any) => {
|
||
// eslint-disable-next-line no-console
|
||
console.error('天地图加载失败:', error)
|
||
message.error('地图加载失败,请检查网络连接或Token配置')
|
||
})
|
||
}, 200)
|
||
}).catch(() => {
|
||
message.error('获取地图配置失败')
|
||
})
|
||
})
|
||
}
|
||
|
||
// 表单提交
|
||
const dataFormSubmit = async () => {
|
||
try {
|
||
await messageBox.confirm('是否确认保存住宿半径')
|
||
formRef.value?.validate((valid: boolean) => {
|
||
if (valid) {
|
||
canSubmit.value = false
|
||
editDormrange({ id: dictId.value, value: form.raidus }).then(() => {
|
||
message.success('修改成功')
|
||
visible.value = false
|
||
canSubmit.value = true
|
||
}).catch(() => {
|
||
canSubmit.value = true
|
||
})
|
||
}
|
||
})
|
||
} catch {
|
||
// 用户取消
|
||
}
|
||
}
|
||
|
||
// 暴露方法给父组件
|
||
defineExpose({
|
||
init
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
#container {
|
||
overflow: hidden;
|
||
width: 100%;
|
||
height: 700px;
|
||
margin: 0;
|
||
font-family: "微软雅黑";
|
||
margin-top: 15px;
|
||
}
|
||
|
||
ul li {
|
||
list-style: none;
|
||
}
|
||
|
||
.dialog-footer {
|
||
text-align: right;
|
||
}
|
||
</style>
|
||
|
||
<style>
|
||
/* 让地图上的圆形覆盖物不拦截鼠标事件,使地图可以拖拽 */
|
||
#container svg path[fill*="#FF"],
|
||
#container svg path[stroke*="#FF"],
|
||
#container svg circle,
|
||
#container canvas {
|
||
pointer-events: none !important;
|
||
}
|
||
|
||
/* 但保持标记点可点击 */
|
||
#container .tdt-marker,
|
||
#container img {
|
||
pointer-events: auto !important;
|
||
}
|
||
</style>
|