YouKeChuanMei_VUE/src/views/outdoorMedia/index.vue
wangchengming 7fc8d59c06 提交
2025-10-27 09:39:58 +08:00

1216 lines
41 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="app-container">
<div class="searchPanel">
<div class="more-search-pane">
<div class="search-where-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" class="searchPanelForm">
<el-form-item label="城市:">
<el-select v-model="queryParams.provinceCode" placeholder="请选择" @change="getCityList"
clearable style="min-width: 30px">
<el-option v-for="item in province" :key="item.id" :label="item.name"
:value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="">
<el-select v-model="queryParams.cityCode" placeholder="请选择" @change="getCountyList"
clearable style="min-width: 30px">
<el-option v-for="item in city" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="">
<el-select v-model="queryParams.areaCode" placeholder="请选择" @change="getTownList" clearable
style="min-width: 30px">
<el-option v-for="item in county" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="">
<el-select v-model="queryParams.townCode" placeholder="请选择" @change="getbusinessAreaList"
clearable style="min-width: 30px">
<el-option v-for="item in town" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="商圈:">
<el-select v-model="queryParams.businessDistrictId" placeholder="请选择" clearable
style="min-width: 30px;">
<el-option v-for="item in businessAreaList" :key="item.id" :label="item.name"
:value="item.id" />
</el-select>
</el-form-item>
</el-form>
</div>
<div class="search-more-button">
<el-button v-if="!unfoldFlag" text class="foladText" @click="handleFlod">展开
<svg-icon icon-class="unfold" class="ml10" />
</el-button>
<el-button v-else text class="foladText" @click="handleFlod">收起
<svg-icon icon-class="packUp" class="ml10" />
</el-button>
</div>
</div>
</div>
<div class="searchSmallPanel" v-show="unfoldFlag">
<el-form :model="queryParams" ref="queryRef" :inline="true" class="searchSmallPanelForm">
<el-form-item label="媒体类型:">
<el-select v-model="queryParams.mediaType" placeholder="请选择" @change="getMediaTypeTwo" clearable
style="min-width: 30px">
<el-option v-for="item in mediaTypeOne" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="媒体大类:">
<el-select v-model="queryParams.mediaCategory" placeholder="请选择" @change="getMediaTypeThree"
clearable style="min-width: 30px">
<el-option v-for="item in mediaTypeTwo" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="展示形式:">
<el-select v-model="queryParams.displayForm" placeholder="请选择" clearable style="min-width: 30px">
<el-option v-for="item in mediaTypeThree" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</el-form>
</div>
<div class="choseResultPanel">
<el-form :inline="true" class="searchSmallPanelForm">
<el-form-item label="已选媒体:">
<div v-if="multipleChoseArr.length == 0" class="noChoseLabel">未选择媒体</div>
<template v-else>
<el-tag v-for="tag in multipleChoseArr" :key="tag.id" class="choseResultTag"
@close="handleCloseTag(tag)" closable>
{{ tag.mediaName }}
</el-tag>
</template>
</el-form-item>
</el-form>
</div>
<el-card class="mt10">
<el-row :gutter="10" class="my_row">
<el-col :span="8">
<el-form :model="queryParams" ref="queryRef" :inline="true" class="searchInputForm">
<el-form-item label="">
<el-input v-model="queryParams.keyword" @keydown.enter.prevent="handleQuery"
placeholder="请输入媒体名称/媒体编号" :prefix-icon="Search" style="width: 400px;" />
</el-form-item>
</el-form>
</el-col>
<el-col :span="16" style="text-align: right;">
<el-button type="primary" class="primaryBtn" v-hasPermi="['outdoorMedia:query']"
@click="handleQuery">查询</el-button>
<el-button type="primary" class="primaryBtn" v-hasPermi="['outdoorMedia:reset']"
@click="resetQuery">重置</el-button>
<el-button type="primary" class="primaryBtn" v-hasPermi="['outdoorMedia:exportPPTS']"
@click="handleExportMore">PPT批量导出</el-button>
<el-button type="primary" class="primaryBtn" v-hasPermi="['outdoorMedia:clear']"
@click="handleClearChoseMedia">清空所选媒体</el-button>
</el-col>
</el-row>
<el-row :gutter="10" class="my_row" style="margin-bottom: 0;">
<el-col :span="12">
<el-table ref="tableRef" v-loading="loading" :data="outdoorMediaList"
@selection-change="handleSelectionChange"
:min-height="unfoldFlag ? 'calc(100vh - 372px)' : 'calc(100vh - 338px)'">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="实景图片" align="left" prop="mediaFileList" width="170">
<template #default="scope">
<img v-if="scope.row.mediaFileList.length > 0"
:src="baseUrl + scope.row.mediaFileList[0].fileName" fit="fill"
style="width: 138px;height: 78px; border-radius: 4px" />
</template>
</el-table-column>
<el-table-column label="媒体名称" align="left" prop="mediaName" width="150" />
<el-table-column label="商圈" align="left" prop="businessDistrictName" width="150" />
<el-table-column label="媒体大类" align="left" prop="mediaCategoryStr" width="150" />
<el-table-column label="展示形式" align="left" prop="displayFormStr" width="150" />
<el-table-column label="操作" width="58" align="center" fixed="right">
<template #default="scope">
<el-popover popper-class="my_popover" placement="left-start">
<div class="popBtns" @click="handleViewMedia(scope.row.id)"
v-hasPermi="['outdoorMedia:detail']">查看
</div>
<div class="popBtns" @click="handleDownPPT(scope.row)"
v-hasPermi="['outdoorMedia:exportPPT']">下载PPT</div>
<template #reference>
<img style="cursor: pointer;" :src="scope.row.currentImageSrc"
@mouseenter="scope.row.currentImageSrc = hoverImageSrc"
@mouseleave="scope.row.currentImageSrc = defaultImageSrc" />
</template>
</el-popover>
</template>
</el-table-column>
</el-table>
<pagination :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
@pagination="getOutMediaPageList" />
</el-col>
<el-col :span="12">
<div id="mapContainer" class="mapContainer"></div>
</el-col>
</el-row>
</el-card>
<detail ref="detailFormRef" />
</div>
</template>
<script setup name="Post">
import { onMounted, onUnmounted, nextTick, ref } from 'vue';
import { Search } from '@element-plus/icons-vue'
import { sysRegionListByPid } from "@/api/system/administrativeRegion"
import { sysMediaTypeListByPid } from "@/api/system/mediaType"
import { busTradingAreaPage } from "@/api/system/businessArea"
import { outMediaPageList } from "@/api/mediaLibrary"
import { pptTemplatePage } from "@/api/system/pptTemplate"
import { exportMediaPPT } from "@/api/mediaLibrary"
import AMapLoader from "@amap/amap-jsapi-loader"; // 引入地图服务
import optionIcon from '@/assets/images/optionIcon.png'
import optionIconHover from '@/assets/images/optionIconHover.png'
import { useBackgroundStore } from '@/store/modules/background'
import otherbg from '@/assets/images/otherbg.png'
import detail from './detail.vue';
const bgStore = useBackgroundStore()
const { proxy } = getCurrentInstance()
const baseUrl = import.meta.env.VITE_APP_BASE_API
const { apiKey, secretKey } = window._CONFIG
const detailFormRef = ref(null)
// 操作图标
const defaultImageSrc = ref(optionIcon);
const hoverImageSrc = ref(optionIconHover);
// 省、市、县、镇数据
const province = ref([])
const city = ref([])
const county = ref([])
const town = ref([])
// 商圈信息列表
const businessAreaList = ref([])
// 媒体类型数据
const mediaTypeOne = ref([])
const mediaTypeTwo = ref([])
const mediaTypeThree = ref([])
// 媒体多选数据
const multipleChoseArr = ref([])
// 户外媒体数据
const outdoorMediaList = ref([])
// 是否折叠
const unfoldFlag = ref(false)
const loading = ref(true)
const total = ref(0)
const data = reactive({
queryParams: {
pageNum: 1,
pageSize: 10,
keyword: undefined,
mediaType: undefined,
mediaCategory: undefined,
displayForm: undefined,
provinceCode: undefined,
cityCode: undefined,
areaCode: undefined,
townCode: undefined,
businessDistrictId: undefined
}
})
const { queryParams } = toRefs(data)
// map实例
const mapInstance = ref(null)
const massMarks = ref(null)
// 当前激活的工具实例
const activeTool = ref(null)
// 当前地图模式2D/3D
const mapMode = ref('2D')
// 是否全屏状态
const isFullscreen = ref(false)
const geocoder = ref(null)
const geocoderMarker = ref(null)
const provinceName = ref(null)
const ciytName = ref(null)
const countyName = ref(null)
const townName = ref(null)
// 地图数据点
const points = ref([])
// 初始化变量用于存储极值
let minLng = Infinity; // 经度的最小值(最西边)
let minLat = Infinity; // 纬度的最小值(最南边)
let maxLng = -Infinity; // 经度的最大值(最东边)
let maxLat = -Infinity; // 纬度的最大值(最北边)
// 添加表格引用
const tableRef = ref(null)
// 添加一个标志位来区分是用户操作还是程序设置
const isSettingSelection = ref(false)
// 导出提交信息
const exportForm = ref({
mediaIds: undefined,
templateId: undefined,
exportFields: [
'mediaName',
'address',
'mediaSize',
'mediaOrientation',
'businessDistrictName',
'dailyAvgVehicleFlow',
'advantages'
]
})
// 获取PPT模板ID
const getpptTemplatePageList = () => {
pptTemplatePage(queryParams.value).then(res => {
const pptTemplate = res.data.list.filter(item => item.type == 3)
if (pptTemplate.length == 1) exportForm.value.templateId = pptTemplate[0].id
})
}
// 下载ppt
const handleDownPPT = (row) => {
exportForm.value.mediaIds = [row.id]
handleSubmitExportPPT()
}
// 批量下载PPT
const handleExportMore = () => {
if (multipleChoseArr.value.length == 0) {
proxy.$modal.msgWarning("请选择要导出的媒体!!!")
return false
}
exportForm.value.mediaIds = multipleChoseArr.value.map(item => item.id);
handleSubmitExportPPT()
}
// 导出ppt实现代码
const handleSubmitExportPPT = () => {
exportMediaPPT(exportForm.value).then(res => {
const downLoadName = '媒体信息_' + getCurrentTime() + '.pptx'
// 通过a标签打开新页面下载文件
const a = document.createElement('a')
a.href = URL.createObjectURL(res)
// a标签里有download属性可以自定义文件名
a.setAttribute('download', downLoadName)
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
})
}
const getCurrentTime = () => {
//获取当前时间并打印
var getTime = new Date().getTime(); //获取到当前时间戳
var time = new Date(getTime); //创建一个日期对象
var year = time.getFullYear(); // 年
var month = (time.getMonth() + 1).toString().padStart(2, '0'); // 月
var date = time.getDate().toString().padStart(2, '0'); // 日
var hour = time.getHours().toString().padStart(2, '0'); // 时
var minute = time.getMinutes().toString().padStart(2, '0'); // 分
var second = time.getSeconds().toString().padStart(2, '0'); // 秒
var gettime = year + month + date + hour + minute + second
return gettime
}
// 获取一级媒体类型
const getMediaTypeOne = () => {
sysMediaTypeListByPid({ parentId: 0 }).then(res => {
mediaTypeOne.value = res.data
})
}
// 获取二级媒体类型
const getMediaTypeTwo = (value) => {
sysMediaTypeListByPid({ parentId: value }).then(res => {
queryParams.value.mediaTypeTwo = undefined
queryParams.value.mediaTypeThree = undefined
mediaTypeTwo.value = res.data
})
}
// 获取三级媒体类型
const getMediaTypeThree = (value) => {
sysMediaTypeListByPid({ parentId: value }).then(res => {
queryParams.value.mediaTypeThree = undefined
mediaTypeThree.value = res.data
})
}
// 获取省/直辖市数据
const getProvinceList = () => {
sysRegionListByPid({ parentId: '0' }).then(res => {
province.value = res.data
})
}
// 获取地级市/区数据
const getCityList = (value) => {
sysRegionListByPid({ parentId: value }).then(res => {
queryParams.value.cityId = undefined
queryParams.value.countyId = undefined
queryParams.value.townId = undefined
city.value = res.data
})
ciytName.value = undefined
countyName.value = undefined
townName.value = undefined
// 定位到省中心
var choseProvince = province.value.filter(item => item.id == value)[0]
if (choseProvince) {
provinceName.value = choseProvince.name
geocoderCityCenter()
}
getbusinessAreaList()
}
// 获取区/县数据
const getCountyList = (value) => {
sysRegionListByPid({ parentId: value }).then(res => {
queryParams.value.countyId = undefined
queryParams.value.townId = undefined
county.value = res.data
})
countyName.value = undefined
townName.value = undefined
var choseCity = city.value.filter(item => item.id == value)[0]
if (choseCity) {
ciytName.value = choseCity.name
geocoderCityCenter()
}
getbusinessAreaList()
}
// 获取镇数据
const getTownList = (value) => {
sysRegionListByPid({ parentId: value }).then(res => {
queryParams.value.townId = undefined
town.value = res.data
})
townName.value = undefined
var choseCounty = county.value.filter(item => item.id == value)[0]
if (choseCounty) {
countyName.value = choseCounty.name
geocoderCityCenter()
}
getbusinessAreaList()
}
// 依据省市县镇查询商圈
const getbusinessAreaList = (val) => {
const _params = {
pageIndex: 1,
pageSize: 200,
provinceId: queryParams.value.provinceCode,
cityId: queryParams.value.cityCode,
countyId: queryParams.value.areaCode,
townId: queryParams.value.townCode,
}
busTradingAreaPage(_params).then(res => {
if (res.code == 200) {
businessAreaList.value = res.data.list
}
})
var choseTown = town.value.filter(item => item.id == val)[0]
if (choseTown) {
townName.value = choseTown.name
geocoderCityCenter()
}
}
// 查找指定城市中心点,地图移动到中心点 放大视野
const geocoderCityCenter = () => {
// 构建查询地址
var address = provinceName.value;
if (ciytName.value) address += ciytName.value;
if (countyName.value) address += countyName.value;
if (townName.value) address += townName.value;
// 使用地理编码获取坐标
geocoder.value = new AMap.Geocoder({
city: ciytName.value || provinceName.value
});
geocoder.value.getLocation(address, function (status, result) {
if (status === 'complete' && result.geocodes.length > 0) {
var location = result.geocodes[0].location;
// 根据行政级别设置缩放级别
var zoomLevel = getZoomLevel(provinceName.value, ciytName.value, countyName.value, townName.value);
// 平滑移动到新位置
mapInstance.value.setZoomAndCenter(zoomLevel, [location.lng, location.lat], true);
// 添加标记
addMarker([location.lng, location.lat], address);
}
});
}
// 添加标记
const addMarker = (position, title) => {
// 清除现有标记
mapInstance.value.clearMap();
// 添加新标记
geocoderMarker.value = new AMap.Marker({
position: position,
title: title
});
mapInstance.value.add(geocoderMarker.value);
}
// 根据行政级别获取缩放级别
const getZoomLevel = (province, city, county, town) => {
if (town) return 15; // 乡镇级别
if (county) return 13; // 区县级别
if (city) return 11; // 城市级别
return 8; // 省份级别
}
// 折叠展开
const handleFlod = () => {
unfoldFlag.value = !unfoldFlag.value
}
// 获取户外媒介列表数据
const getOutMediaPageList = () => {
loading.value = true
outMediaPageList(queryParams.value).then(res => {
points.value = []
res.data.rows.forEach(itemPoint => {
itemPoint.currentImageSrc = defaultImageSrc.value;
if (itemPoint.mapX && itemPoint.mapX !== '' && itemPoint.mapY && itemPoint.mapY !== '') {
if (itemPoint.dataScopeDeptId == 220) points.value.push({ "lnglat": [itemPoint.mapX, itemPoint.mapY], "name": itemPoint.mediaName, "mediaId": itemPoint.id, "style": 0 })
else if (itemPoint.dataScopeDeptId == 219) points.value.push({ "lnglat": [itemPoint.mapX, itemPoint.mapY], "name": itemPoint.mediaName, "mediaId": itemPoint.id, "style": 1 })
// 同时更新极值
const lng = itemPoint.mapX;
const lat = itemPoint.mapY;
if (lng < minLng) minLng = lng;
if (lat < minLat) minLat = lat;
if (lng > maxLng) maxLng = lng;
if (lat > maxLat) maxLat = lat;
}
});
outdoorMediaList.value = res.data.rows
total.value = res.data.total
loading.value = false
// 数据加载完成后,设置选中状态
nextTick(() => {
setTableSelection()
// 在地图完全加载后执行点数据处理
renderMassMarks();
})
})
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1
getOutMediaPageList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryParams.value = {
pageNum: 1,
pageSize: 10,
keyword: undefined,
mediaType: undefined,
mediaCategory: undefined,
displayForm: undefined,
provinceCode: undefined,
cityCode: undefined,
areaCode: undefined,
townCode: undefined,
businessDistrictId: undefined
}
if (geocoderMarker.value) {
mapInstance.value.remove(geocoderMarker.value);
geocoderMarker.value = null
}
handleQuery()
}
// 选择媒体事件
const handleSelectionChange = (selection) => {
// 如果是程序设置的选中状态,不更新 multipleChoseArr
if (isSettingSelection.value) {
return
}
// 获取当前页所有行的ID
const currentPageIds = outdoorMediaList.value.map(item => item.id)
// 如果当前页没有选中的数据,说明是页面切换导致的清空,不处理
if (selection.length === 0 && currentPageIds.length > 0) {
// 检查当前页是否有应该选中的数据
const shouldHaveSelections = currentPageIds.some(id =>
multipleChoseArr.value.some(item => item.id === id)
)
// 如果当前页有应该选中的数据但selection为空说明是页面切换不处理
if (shouldHaveSelections) {
return
}
}
// 移除当前页中已取消选中的项目
const currentSelectedIds = selection.map(item => item.id)
multipleChoseArr.value = multipleChoseArr.value.filter(item =>
!currentPageIds.includes(item.id) || currentSelectedIds.includes(item.id)
)
// 添加新选中的项目(去重)
selection.forEach(newItem => {
if (!multipleChoseArr.value.some(item => item.id === newItem.id)) {
multipleChoseArr.value.push(newItem)
}
})
}
// 设置表格选中状态 - 完善版本
const setTableSelection = () => {
if (tableRef.value && outdoorMediaList.value.length > 0) {
// 设置标志位,避免触发 handleSelectionChange
isSettingSelection.value = true
// 使用 nextTick 确保DOM已更新
nextTick(() => {
// 先清除所有选中状态
tableRef.value.clearSelection()
// 延迟设置选中状态,确保清除操作完成
setTimeout(() => {
outdoorMediaList.value.forEach(row => {
const isSelected = multipleChoseArr.value.some(item => item.id === row.id)
if (isSelected) {
tableRef.value.toggleRowSelection(row, true)
}
})
// 恢复标志位
setTimeout(() => {
isSettingSelection.value = false
}, 100)
}, 50)
})
}
}
// 移除选择项
const handleCloseTag = (tag) => {
const rowIndex = multipleChoseArr.value.findIndex(item => item.id == tag.id)
multipleChoseArr.value.splice(rowIndex, 1)
// 清除对应行的复选框选中状态
if (tableRef.value) {
// 设置标志位,避免触发 handleSelectionChange
isSettingSelection.value = true
// 找到对应的行数据
const row = outdoorMediaList.value.find(item => item.id === tag.id)
if (row) {
tableRef.value.toggleRowSelection(row, false)
}
// 恢复标志位
setTimeout(() => {
isSettingSelection.value = false
}, 100)
}
}
// 清空已选媒体
const handleClearChoseMedia = () => {
multipleChoseArr.value = []
if (tableRef.value) {
// 设置标志位,避免触发 handleSelectionChange
isSettingSelection.value = true
tableRef.value.clearSelection()
// 恢复标志位
setTimeout(() => {
isSettingSelection.value = false
}, 100)
}
}
// 查看媒体详情
const handleViewMedia = (_mediaId) => {
detailFormRef.value.initMediaDetail(_mediaId)
}
// 初始化地图
const loadMap = () => {
return new Promise((resolve, reject) => {
// 设置安全密钥
window._AMapSecurityConfig = {
securityJsCode: secretKey
};
AMapLoader.load({
key: apiKey,
plugins: ["AMap.Geocoder", "AMap.MouseTool"],
version: '2.0', // 指定API版本
AMapUI: {
plugins: []
}
}).then(AMap => {
// 根据当前模式设置初始参数
const initialPitch = mapMode.value === '3D' ? 65 : 0;
const initialRotation = mapMode.value === '3D' ? -15 : 0;
mapInstance.value = new AMap.Map("mapContainer", {
resizeEnable: true,
pitch: initialPitch, // 倾斜角度决定2D/3D模式
rotation: initialRotation, // 旋转角度
zoom: 16,
zooms: [3, 16],
viewMode: mapMode.value // 启用3D视图
});
// // 先添加基本控件
mapInstance.value.setZoom(16);
// 添加自定义控件容器
addCustomControls(AMap);
// 地图加载完成后隐藏Logo
setTimeout(() => {
hideAmapLogo();
}, 1000);
// 监听地图渲染完成事件
mapInstance.value.on('render', hideAmapLogo);
// 添加缩放变化监听
mapInstance.value.on('zoomchange', handleZoomChange);
//// 在地图完全加载后执行点数据处理
//renderMassMarks();
resolve();
}).catch(e => {
console.log(e, "高德地图加载失败");
reject(e);
});
});
}
// 处理地图缩放事件
const handleZoomChange = () => {
const currentZoomLevel = mapInstance.value.getZoom();
// 如果缩放级别超过16自动调整回16
if (currentZoomLevel > 16) {
mapInstance.value.setZoom(16);
return;
}
}
// 辅助函数:结束当前正在使用的鼠标工具
const stopActiveTool = () => {
if (activeTool.value !== null) {
clearAll()
activeTool.value = null; // 释放引用以便垃圾回收
}
};
// 添加自定义控件
const addCustomControls = (AMap) => {
// 创建控件容器
const controlContainer = document.createElement('div');
controlContainer.className = 'custom-map-controls';
// 2D/3D切换按钮
const toggle2D3DBtn = document.createElement('div');
toggle2D3DBtn.className = mapMode.value === '2D' ? 'map-control-btn map-control-3dbtn' : 'map-control-btn map-control-2dbtn';
toggle2D3DBtn.onclick = toggle2D3DMode;
// 全屏按钮
const fullscreenBtn = document.createElement('div');
fullscreenBtn.className = isFullscreen.value === true ? 'map-control-btn map-full-screen' : 'map-control-btn map-nofull-screen';
fullscreenBtn.onclick = toggleFullscreen;
// 工具箱测距按钮
const toolRangingBtn = document.createElement('div');
toolRangingBtn.className = 'map-control-btn map-ranging';
toolRangingBtn.setAttribute('title', '测距');
toolRangingBtn.onclick = startRuler;
// 工具箱测面积按钮
const toolMeasureAreaBtn = document.createElement('div');
toolMeasureAreaBtn.className = 'map-control-btn map-measureAreaBtn';
toolMeasureAreaBtn.setAttribute('title', '测面积');
toolMeasureAreaBtn.onclick = startMeasureArea;
// 工具箱添加点按钮
const toolPointBtn = document.createElement('div');
toolPointBtn.className = 'map-control-btn map-addPointBtn';
toolPointBtn.setAttribute('title', '绘制点');
toolPointBtn.onclick = startDrawMarker;
// 工具箱添加折线按钮
const toolLineBtn = document.createElement('div');
toolLineBtn.className = 'map-control-btn map-addLineBtn';
toolLineBtn.setAttribute('title', '绘制折线');
toolLineBtn.onclick = startDrawPolyline;
// 工具箱添加圆按钮
const toolCircleBtn = document.createElement('div');
toolCircleBtn.className = 'map-control-btn map-addCircleBtn';
toolCircleBtn.setAttribute('title', '绘制圆');
toolCircleBtn.onclick = startDrawCircle;
// 工具箱添加矩形按钮
const toolRactBtn = document.createElement('div');
toolRactBtn.className = 'map-control-btn map-addRactBtn';
toolRactBtn.setAttribute('title', '绘制矩形');
toolRactBtn.onclick = startDrawRectangle;
// 工具箱清除按钮
const toolClearAllBtn = document.createElement('div');
toolClearAllBtn.className = 'map-control-btn map-clearAllBtn';
toolClearAllBtn.setAttribute('title', '清除');
toolClearAllBtn.onclick = clearAll;
controlContainer.appendChild(toggle2D3DBtn);
controlContainer.appendChild(fullscreenBtn);
controlContainer.appendChild(toolRangingBtn);
controlContainer.appendChild(toolMeasureAreaBtn);
controlContainer.appendChild(toolPointBtn);
controlContainer.appendChild(toolLineBtn);
controlContainer.appendChild(toolCircleBtn);
controlContainer.appendChild(toolRactBtn);
controlContainer.appendChild(toolClearAllBtn);
// 添加到地图容器
document.getElementById('mapContainer').appendChild(controlContainer);
}
// 切换2D/3D模式
const toggle2D3DMode = () => {
if (!mapInstance.value) return;
const currentPitch = mapInstance.value.getPitch();
if (currentPitch === 0) {
// 切换到3D模式
mapInstance.value.setPitch(65);
mapInstance.value.setRotation(-15);
mapMode.value = '3D';
loadMap()
} else {
// 切换到2D模式
mapInstance.value.setPitch(0);
mapInstance.value.setRotation(0);
mapMode.value = '2D';
loadMap()
}
}
// 切换全屏模式
const toggleFullscreen = () => {
const mapContainer = document.getElementById('mapContainer');
if (!document.fullscreenElement) {
// 进入全屏
if (mapContainer.requestFullscreen) {
mapContainer.requestFullscreen().then(() => {
isFullscreen.value = true;
const buttons = document.querySelectorAll('.map-control-btn');
buttons[1].className = 'map-control-btn map-full-screen';
}).catch(err => {
console.error('全屏模式错误:', err);
});
}
} else {
// 退出全屏
if (document.exitFullscreen) {
document.exitFullscreen().then(() => {
isFullscreen.value = false;
const buttons = document.querySelectorAll('.map-control-btn');
buttons[1].className = 'map-control-btn map-nofull-screen';
});
}
}
}
// 测距方法
const startRuler = () => {
if (!mapInstance.value) return;
stopActiveTool();
activeTool.value = new AMap.MouseTool(mapInstance.value);
activeTool.value.rule({
startMarkerOptions: {//可缺省
icon: new AMap.Icon({
size: new AMap.Size(19, 31),//图标大小
imageSize: new AMap.Size(19, 31),
image: "//webapi.amap.com/theme/v1.3/markers/b/start.png"
}),
offset: new AMap.Pixel(-9, -31)
},
endMarkerOptions: {//可缺省
icon: new AMap.Icon({
size: new AMap.Size(19, 31),//图标大小
imageSize: new AMap.Size(19, 31),
image: "//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: "//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
}
});
}
// 测面积方法
const startMeasureArea = () => {
if (!mapInstance.value) return;
stopActiveTool();
activeTool.value = new AMap.MouseTool(mapInstance.value);
activeTool.value.measureArea({
strokeColor: '#80d8ff',
fillColor: '#80d8ff',
fillOpacity: 0.3
//同 Polygon 的 Option 设置
});
}
// 添加点
const startDrawMarker = () => {
if (!mapInstance.value) return;
stopActiveTool();
activeTool.value = new AMap.MouseTool(mapInstance.value);
activeTool.value.marker({
//同Marker的Option设置
});
}
// 添加线
const startDrawPolyline = () => {
if (!mapInstance.value) return;
stopActiveTool();
activeTool.value = new AMap.MouseTool(mapInstance.value);
activeTool.value.polyline({
strokeColor: '#80d8ff'
//同Polyline的Option设置
});
}
// 添加圆
const startDrawCircle = () => {
if (!mapInstance.value) return;
stopActiveTool();
activeTool.value = new AMap.MouseTool(mapInstance.value);
activeTool.value.circle({
fillColor: '#00b0ff',
strokeColor: '#80d8ff'
//同Circle的Option设置
});
}
// 画矩形
const startDrawRectangle = () => {
if (!mapInstance.value) return;
stopActiveTool();
activeTool.value = new AMap.MouseTool(mapInstance.value);
activeTool.value.rectangle({
fillColor: '#00b0ff',
strokeColor: '#80d8ff'
//同Polygon的Option设置
});
}
// 清除
const clearAll = () => {
activeTool.value.close(true)//关闭,并清除覆盖物
}
// 监听全屏变化事件
document.addEventListener('fullscreenchange', () => {
if (!document.fullscreenElement) {
isFullscreen.value = false;
}
});
// 创建自定义点样式
const createPointStyle = (color, size, styleType) => {
const canvas = document.createElement('canvas');
canvas.width = size * 2;
canvas.height = size * 2;
const ctx = canvas.getContext('2d');
// 根据样式类型绘制不同的图形
switch (styleType) {
case 'circle':
ctx.beginPath();
ctx.arc(size, size, size, 0, Math.PI * 2);
ctx.fillStyle = color;
ctx.fill();
break;
case 'ring':
ctx.beginPath();
ctx.arc(size, size, size, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
ctx.fill();
ctx.beginPath();
ctx.arc(size, size, size * 0.7, 0, Math.PI * 2);
ctx.fillStyle = color;
ctx.fill();
break;
case 'square':
ctx.fillStyle = color;
ctx.fillRect(0, 0, size * 2, size * 2);
break;
case 'star':
ctx.fillStyle = color;
ctx.beginPath();
for (let i = 0; i < 5; i++) {
const angle = (i * 2 * Math.PI / 5) - Math.PI / 2;
const x = size + size * Math.cos(angle);
const y = size + size * Math.sin(angle);
if (i === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
const innerAngle = angle + Math.PI / 5;
const innerX = size + size * 0.4 * Math.cos(innerAngle);
const innerY = size + size * 0.4 * Math.sin(innerAngle);
ctx.lineTo(innerX, innerY);
}
ctx.closePath();
ctx.fill();
break;
}
return canvas;
}
// 渲染海量点
const renderMassMarks = () => {
// 清除现有的海量点
if (massMarks.value) {
massMarks.value.clear();
}
// 创建三种不同大小的样式
const styles = [
// 优势媒体颜色-红色
{
url: createPointStyle('#EC1B60', 18, 'circle').toDataURL(),
anchor: new AMap.Pixel(18, 18),
size: new AMap.Size(18, 18)
},
// 网络媒体颜色-蓝色
{
url: createPointStyle('#058DED', 18, 'circle').toDataURL(),
anchor: new AMap.Pixel(18, 18),
size: new AMap.Size(18, 18)
},
];
// 如果有点存在,则创建 MassMarks 实例
if (points.value.length > 0 && mapInstance.value) {
// 创建MassMarks对象
massMarks.value = new AMap.MassMarks(points.value, {
opacity: 1,
zIndex: 111,
cursor: 'pointer',
style: styles
});
// 将海量点添加到地图
massMarks.value.setMap(mapInstance.value);
// 添加点击事件
massMarks.value.on('click', function (e) {
handleViewMedia(e.data.mediaId)
});
// ==================================================
// 新增:计算边界并设置地图视野
// ==================================================
const southWest = new AMap.LngLat(minLng, minLat); // 西南角
const northEast = new AMap.LngLat(maxLng, maxLat); // 东北角
const bounds = new AMap.Bounds(southWest, northEast);
// 设置地图显示范围,会自动适配最佳视图
mapInstance.value.setBounds(bounds);
}
}
// 隐藏Logo的函数
const hideAmapLogo = () => {
const logos = document.querySelectorAll('.amap-logo, .amap-copyright');
logos.forEach(logo => {
logo.style.display = 'none';
logo.style.visibility = 'hidden';
logo.style.opacity = '0';
});
}
onUnmounted(() => {
stopActiveTool()
if (mapInstance.value) {
mapInstance.value.destroy();
}
})
// 初始化
onMounted(() => {
bgStore.setBgImage(otherbg)
loadMap()
// 获取模板id
getpptTemplatePageList()
getOutMediaPageList()
getMediaTypeOne()
getProvinceList()
});
</script>
<style lang="scss">
.noChoseLabel {
height: 24px;
line-height: 24px;
font-family: Microsoft YaHei;
font-weight: 400;
font-size: 16px;
color: #ffffff90;
}
.mapContainer {
width: 100%;
height: 100%;
background: #3f8bff;
}
.custom-map-controls {
position: absolute;
top: 5px;
right: 5px;
z-index: 1000;
display: flex;
flex-direction: column;
gap: 0px;
}
.map-control-btn {
cursor: pointer;
}
.map-control-2dbtn {
width: 40px;
height: 40px;
background: url('../../assets/images/icon-2D-btn.png');
}
.map-control-2dbtn:hover {
background: url('../../assets/images/icon-2D-active-btn.png');
}
.map-control-3dbtn {
width: 40px;
height: 40px;
background: url('../../assets/images/icon-3D-btn.png');
}
.map-control-3dbtn:hover {
background: url('../../assets/images/icon-3D-active-btn.png');
}
.map-nofull-screen {
width: 40px;
height: 40px;
background: url('../../assets/images/icon-full-screen.png');
}
.map-nofull-screen:hover {
background: url('../../assets/images/icon-full-screen-active.png');
}
.map-full-screen {
width: 40px;
height: 40px;
background: url('../../assets/images/icon-map-nofull-screen.png');
}
.map-full-screen:hover {
background: url('../../assets/images/icon-map-nofull-screen-active.png');
}
.map-ranging {
width: 40px;
height: 40px;
background: url('../../assets/images/mapRanging.png');
}
.map-ranging:hover {
width: 40px;
height: 40px;
background: url('../../assets/images/mapRanginghover.png');
}
.map-measureAreaBtn {
width: 40px;
height: 40px;
background: url('../../assets/images/mapArea.png');
}
.map-measureAreaBtn:hover {
background: url('../../assets/images/mapAreaHover.png');
}
.map-addPointBtn {
width: 40px;
height: 40px;
background: url('../../assets/images/mapPoint.png');
}
.map-addPointBtn:hover {
background: url('../../assets/images/mapPointHover.png');
}
.map-addLineBtn {
width: 40px;
height: 40px;
background: url('../../assets/images/mapLine.png');
}
.map-addLineBtn:hover {
background: url('../../assets/images/mapLineHover.png');
}
.map-addCircleBtn {
width: 40px;
height: 40px;
background: url('../../assets/images/mapCircle.png');
}
.map-addCircleBtn:hover {
background: url('../../assets/images/mapCircleHover.png');
}
.map-addRactBtn {
width: 40px;
height: 40px;
background: url('../../assets/images/mapRect.png');
}
.map-addRactBtn:hover {
background: url('../../assets/images/mapRectHover.png');
}
.map-clearAllBtn {
width: 40px;
height: 40px;
background: url('../../assets/images/mapClearAll.png');
}
.map-clearAllBtn:hover {
background: url('../../assets/images/mapClearAllHover.png');
}
/* 全屏样式 */
.mapContainer:-webkit-full-screen {
width: 100% !important;
height: 100% !important;
}
.mapContainer:-moz-full-screen {
width: 100% !important;
height: 100% !important;
}
.mapContainer:-ms-fullscreen {
width: 100% !important;
height: 100% !important;
}
.mapContainer:fullscreen {
width: 100% !important;
height: 100% !important;
}
</style>