This commit is contained in:
吴红兵
2026-03-07 12:35:45 +08:00
parent 271710e870
commit b997b3ba48
423 changed files with 79612 additions and 91574 deletions

View File

@@ -1,277 +1,279 @@
<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>
<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'
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 message = useMessage();
const messageBox = useMessageBox();
// 表单引用
const formRef = ref()
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 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 center = reactive({ lng: 0, lat: 0 });
const dictId = ref('');
const form = reactive({
raidus: 0,
})
raidus: 0,
});
const rules = {
raidus: [
{ required: true, message: '住宿半径不能为空', trigger: ["blur", "change"] }
],
}
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)
}
})
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("recruit_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('获取地图配置失败')
})
})
}
visible.value = true;
canSubmit.value = true;
circleShow.value = true;
nextTick(() => {
getDicts('recruit_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 {
// 用户取消
}
}
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
})
init,
});
</script>
<style scoped>
#container {
overflow: hidden;
width: 100%;
height: 700px;
margin: 0;
font-family: "微软雅黑";
margin-top: 15px;
overflow: hidden;
width: 100%;
height: 700px;
margin: 0;
font-family: '微软雅黑';
margin-top: 15px;
}
ul li {
list-style: none;
list-style: none;
}
.dialog-footer {
text-align: right;
text-align: right;
}
</style>
<style>
/* 让地图上的圆形覆盖物不拦截鼠标事件,使地图可以拖拽 */
#container svg path[fill*="#FF"],
#container svg path[stroke*="#FF"],
#container svg path[fill*='#FF'],
#container svg path[stroke*='#FF'],
#container svg circle,
#container canvas {
pointer-events: none !important;
pointer-events: none !important;
}
/* 但保持标记点可点击 */
#container .tdt-marker,
#container img {
pointer-events: auto !important;
pointer-events: auto !important;
}
</style>