Commit bb62e826 by 陈永辉

初始化

parent f4f1fe48
......@@ -15,6 +15,11 @@
"js-message": "1.0.7"
}
},
"@amap/amap-jsapi-loader": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@amap/amap-jsapi-loader/-/amap-jsapi-loader-1.0.1.tgz",
"integrity": "sha512-nPyLKt7Ow/ThHLkSvn2etQlUzqxmTVgK7bIgwdBRTg2HK5668oN7xVxkaiRe3YZEzGzfV2XgH5Jmu2T73ljejw=="
},
"@ampproject/remapping": {
"version": "2.2.1",
"resolved": "https://registry.npmmirror.com/@ampproject/remapping/-/remapping-2.2.1.tgz",
......
......@@ -7,6 +7,7 @@
"build": "vue-cli-service build"
},
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"ant-design-vue": "^4.0.3",
"axios": "^1.5.0",
"core-js": "^3.8.3",
......
......@@ -6,6 +6,19 @@
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<script>
AMapUI_DIY_Load = function () {
try {
document.head.removeChild(document.querySelector('#AMapUI_DIY_Load'))
} catch (e) {
}
const _script = document.createElement('script')
_script.src = '//webapi.amap.com/ui/1.1/main.js'
_script.id = 'AMapUI_DIY_Load'
document.head.append(_script)
}
</script>
</head>
<body>
<noscript>
......
......@@ -18,9 +18,7 @@
<a-breadcrumb style="margin: 16px 0">
<a-breadcrumb-item v-for="item in breadcrumbList" :key="item.path">{{ item.meta.title }}</a-breadcrumb-item>
</a-breadcrumb>
<div :style="{ padding: '24px', background: '#fff', minHeight: '360px' }">
----{{ isCollapsed }}
===={{ asideWidth }}
<div>
<router-view/>
</div>
</a-layout-content>
......
......@@ -2,25 +2,31 @@
import {
MenuFoldOutlined,
RedoOutlined,
UserOutlined,
MenuUnfoldOutlined
} from '@ant-design/icons-vue'
import { useSystemStore } from '@/store/modules/system'
import { useSystem} from "@/hooks/useSystem";
import {computed} from "vue";
const { asideWidth, isCollapsed } = useSystem()
const systemStore = useSystemStore()
const handleClick = () => {
systemStore.setCollapsed(!systemStore.collapsed)
}
</script>
<template>
<div class="fix-header">
<div class="fix-header" :style="{left: `${asideWidth}px`}">
<div @click="handleClick">
<MenuFoldOutlined style="font-size: 20px"/>
<component :is="isCollapsed ? MenuUnfoldOutlined : MenuFoldOutlined" style="font-size: 20px"/>
</div>
<div>
<a-dropdown>
<div class="ant-dropdown-link" @click.prevent>
Hover me
<UserOutlined />
<span>管理员</span>
</div>
<template #overlay>
<a-menu>
......@@ -42,7 +48,19 @@ const handleClick = () => {
position: fixed;
top: 0;
right: 0;
left: 200px;
background: #fff;
padding: 0 20px;
display: flex;
align-items: center;
justify-content: space-between;
transition: 0.2s all;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
.ant-dropdown-link{
color: rgba(0, 0, 0, 0.5);
cursor: pointer;
span{
padding-left: 10px;
}
}
}
</style>
\ No newline at end of file
......@@ -4,7 +4,7 @@
<div class="menu-logo">
<img src="https://ebike-saas-prod.oss-cn-shenzhen.aliyuncs.com/frontend/res/1.logo.png"/>
</div>
<div class="menu-title" :style="{opacity: isCollapsed ? 0 : 1}">
<div class="menu-title" v-if="!isCollapsed" :style="{opacity: isCollapsed ? 0 : 1}">
<h1>小安电驴共享</h1>
<p>小安电驴共享</p>
</div>
......
import {
bxAnaalyse,
UserInfo,
ReportStatistics,
vehicle,
DataStatistics,
permission,
ProductionInfo,
MarketingActivities,
BackendConfig,
OperationLog,
screenRevenue,
Performance,
FinanicalServer,
businessScreen
} from '@/core/icons'
export default {
setup() {
return () => {
return <svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title></title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="导航栏" transform="translate(-1482.000000, -1189.000000)">
<g id="编组-8备份-2" transform="translate(1470.000000, 691.000000)">
<g id="编组-30" transform="translate(12.000000, 498.000000)">
<rect id="矩形" x="0" y="0" width="20" height="20"></rect>
<path d="M10.003343,2.5 L10.003343,9.99665701 L17.5,9.99665701 C17.5,11.1332084 17.2470792,12.2106861 16.7944504,13.1758772 L16.7717707,13.2223049 C15.5767777,15.7702863 12.9884044,17.5351014 9.98829953,17.5351014 C5.85301984,17.5351014 2.5,14.1820816 2.5,10.0468019 C2.5,9.70340802 2.52312125,9.36540837 2.5678917,9.03427496 C3.04027811,5.34845685 6.18915959,2.5 10.003343,2.5 L10.003343,2.5 Z M11.1232449,2.5 C14.6016269,2.5 17.4214397,5.31981279 17.4214397,8.79819478 L17.4214397,8.79819478 L11.5411188,8.79819478 C11.3104524,8.79819478 11.1232449,8.6109873 11.1232449,8.38032093 L11.1232449,8.38032093 Z M12.193002,3.68007577 L12.193002,7.72843771 L16.2413639,7.72843771 C16.1728326,7.39915311 16.0725429,7.07655449 15.9404948,6.76398485 C15.6763985,6.14218854 15.2986405,5.58223758 14.8189213,5.10251839 C14.3392021,4.6211277 13.7792512,4.24336973 13.1574549,3.98094495 C12.8448852,3.84889681 12.5222866,3.74860709 12.193002,3.68007577 L12.193002,3.68007577 Z" id="形状结合" fill="currentColor"></path>
</g>
</g>
</g>
</g>
</svg>
}
}
}
\ No newline at end of file
<script setup>
import { loadMap, theLoadMap } from "@/components/AMap/hooks/load";
import {computed, onMounted, ref, shallowRef, watch} from "vue";
import mapProps from '@/components/AMap/props/MarkerProps'
import { useProviderGaoDeMap } from "@/components/AMap/hooks/useGaoDeMap";
import { useProviderMap} from "@/components/AMap/hooks/useMap";
import Cluster from "@/components/AMap/Cluster.vue";
import Polyline from "@/components/AMap/Polyline.vue";
import Marker from "@/components/AMap/Marker.vue";
import Polygon from "@/components/AMap/Polygon.vue";
// 父组件传递来的参数
const theProps = defineProps(mapProps)
//
const amapEmits = defineEmits(['polygonChange', 'mapClick'])
const theGaoDeMap = ref(null)
const theMap = ref(null)
const isMapReady = ref(false)
const mapId = ref(`AMap2_${Number(Math.random().toString().substring(2, 6) + Date.now()).toString(36)}`)
const mapCanClick = ref(true)
const initMap = async () => {
if (theLoadMap.value) {
renderMap(theLoadMap.value);
}else{
await loadMap()
}
}
const renderMap = (AMap) => {
console.log(mapId.value)
theGaoDeMap.value = AMap;
theMap.value = new AMap.Map(mapId.value, {
resizeEnable: true, // 是否监控地图容器尺寸变化
zoom: 11, // 初始地图级别
center: [116.368904,39.913423]
});
theMap.value.on('click', (res) => {
mapClick({
lat: res.lnglat.lat,
lng: res.lnglat.lng,
})
})
theMap.value.on('complete', () => {
isMapReady.value = true
});
}
// 多边形编辑
const polygonChange = (e) => {
amapEmits('polygonChange', e)
}
const mapClick = ({ lat, lng, source = 'mapClick', sourceData }) => {
if (!mapCanClick.value) { return false }
amapEmits('mapClick',{ lat, lng, source, sourceData })
mapCanClick.value = false
setTimeout(() => {
mapCanClick.value = true
})
}
watch(
() => theLoadMap.value,
() => {
if (theLoadMap.value) {
renderMap(theLoadMap.value);
}
},
)
const conversionCenter = computed(() => isMapReady.value && theProps.center)
watch(() => conversionCenter, () => {
if(theProps.center && theMap.value){
theMap.value.setCenter([theProps.center.lng, theProps.center.lat])
}
}, { deep: true, immediate: true})
useProviderMap(theMap)
useProviderGaoDeMap(theGaoDeMap)
onMounted(initMap)
</script>
<template>
<div class="map-container">
<div class="map-content" ref="mapId"></div>
<Polyline :polylines="polylines"/>
<Marker :markers="markers" @markerClick="mapClick"/>
<Polygon :polygons="polygons" @polygonChange="polygonChange" @polygonClick="mapClick"/>
<Cluster :massMarker="massMarker" @clusterClick="mapClick"/>
<slot/>
</div>
</template>
<style scoped lang="scss">
.map-content, .map-container{
width: 100%;
height: 100%;
}
</style>
\ No newline at end of file
<script setup>
import {useInjectMap} from '@/components/AMap/hooks/useMap'
import {useInjectGaoDeMap} from "@/components/AMap/hooks/useGaoDeMap";
import {onMounted, reactive, watch} from "vue";
const theProps = defineProps({
massMarker: {
type: Object,
default: () => ({})
}
})
const clusterEmits = defineEmits(['clusterClick'])
const theCluster = reactive({
overlayMassLabelMarker: null,
massLabelMarkerPath: [], // 海量标注集合
massMarker: null,
massMarkerPath: [], // 普通海量点集合
clusterMarker: null,
clusterMarkerPath: [], // 聚合海量点
})
const theMap = useInjectMap()
const theGaoDeMap = useInjectGaoDeMap()
// 初始化海量点
const initCluster = () => {
if (theMap.value && theGaoDeMap.value) {
console.log(`start marker`)
const {renderMode = 'labelCluster'} = theProps.massMarker
switch (renderMode) {
case 'labelCluster':
theCluster.massLabelMarker = new theGaoDeMap.value.LabelsLayer({
zooms: [3, 20],
zIndex: 1000,
allowCollision: true,// 设置 allowCollision:true,可以让标注避让用户的标注
});
theMap.value.add(theCluster.massLabelMarker)
renderLabelMarkerCluster()
break;
case 'massMarker':
renderMassMarker()
break;
case 'cluster':
renderCluster()
break
}
}
}
const renderLabelMarkerCluster = () => {
const {
labelClusterMode = 'text',
paths = [],
zooms = [3, 20] // 显示级别范围
} = theProps.massMarker
const massLabelMarker = paths.map((el, index) => {
const {position} = el
const labelClusterConfig = {
position: [position.lng, position.lat],
zIndex: index,
icon: el.icon,
text: {
content: el.text.content || '',
direction: el.text.direction || 'right',
offset: el.text.offset || [-20, -5]
},
extData: el
}
return new theGaoDeMap.value.LabelMarker(labelClusterConfig)
})
theCluster.massLabelMarker.add(massLabelMarker)
}
const renderMassMarker = () => {
const {paths = []} = theProps.massMarker
const massPoints = paths.map(el => {
const {position} = el
return {
lnglat: [position.lng, position.lat],
info: el.info || {},
offset: el.info && el.info.offset ? el.info.offset : [0, 0],
style: el.style || 0,
click: el.clickOptions || {},
timestamp: el.timestamp || '',
originData: {...el} // 原始数据
}
})
theCluster.massMarker = new theGaoDeMap.value.MassMarks(massPoints, {
opacity: 0.8,
zIndex: 111,
cursor: 'pointer',
style: [{
url: 'https://webapi.amap.com/images/mass/mass2.png',
anchor: new theGaoDeMap.value.Pixel(6, 6),
size: new theGaoDeMap.value.Size(11, 11),
zIndex: 3,
}]
})
theCluster.massMarker.on('click', (e) => {
const {lnglat, originData} = e.data
clusterClick({lnglat, originData})
})
theCluster.massMarker.setMap(theMap.value)
renderInfoWindow()
}
const renderCluster = () => {
const {paths = []} = theProps.massMarker
const clusterPoints = paths.map(point => {
const {position} = point
return {
lnglat: [position.lng, position.lat],
extData: {
...point,
info: point.info || {},
offset: point.info && point.info.offset ? point.info.offset : [0, 0],
click: point.clickOptions ? (point.clickOptions || {}) : (point.click || {}),
timestamp: point.timestamp || '',
originData: {...point} // 原始数据
}
}
})
theCluster.clusterMarker = new theGaoDeMap.value.MarkerCluster(theMap.value, clusterPoints, {
gridSize: 60,
})
theCluster.clusterMarker.on('click', (e) => {
const { cluster, clusterData } = e
const markerArr = cluster.M || [] // M 是下一个聚合层级中的所有点
/**
* 非聚合点,不进行地图放大操作
* 当地图未到最大比例,却有未聚合的单点时,此时 clusterData 不为空数组,需要根据 _amapMarker 判断当前点是否为单点
*/
const count = markerArr[0] ? markerArr[0][0]._amapMarker.count || 0 : 0
console.log(count)
if (!clusterData || !clusterData.length || (clusterData.length === 1 && count === 1)) {
return
}
// 获取当前聚合点下的第一个聚合点,
const center = markerArr[0][0].lnglat
theMap.value.setZoomAndCenter(theMap.value.getZoom() + 1, [center.lng, center.lat])
})
}
const renderInfoWindow = () => {
const marker = new theGaoDeMap.value.Marker({
content: ' ',
map: theMap.value,
anchor: 'bottom-center',
offset: [0, -15],
});
theCluster.massMarker.on('mouseover', (e) => {
marker.setPosition(e.data.lnglat);
marker.setContent(`<div style="background: #fff; width: 100px">${e.data.originData.name}</div>`)
})
}
const clusterClick = (e) => {
const [lng, lat] = e.lnglat
clusterEmits('clusterClick', {
lat,
lng,
source: 'clusterClick',
sourceData: e.originData
})
}
watch(() => theMap.value, initCluster)
watch(() => theProps.massMarker, initCluster, {immediate: true, deep: true})
</script>
<template>
</template>
<style scoped lang="scss">
</style>
\ No newline at end of file
<script setup>
import { useInjectGaoDeMap } from "@/components/AMap/hooks/useGaoDeMap";
import { useInjectMap } from "@/components/AMap/hooks/useMap";
import { reactive, watch } from "vue";
const theMarkerProps = defineProps({
markers: {
type: Array,
default: () => []
}
})
const markerEmits = defineEmits(['markerClick'])
const theMap = useInjectMap()
const theGaoDeMap = useInjectGaoDeMap()
const theMarker = reactive({
markers: [],
overlayMarker: null,
})
const initMarker = () => {
if(theMap.value && theGaoDeMap.value) {
console.log(`start marker`)
theMarker.markers = theMarkerProps.markers.map(marker => {
const { icon, position, offset, content } = marker
const markerConfig = {
content,
icon: icon || '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png',
position: [position.lng, position.lat],
offset: offset ? new theGaoDeMap.value.Pixel(offset[0], offset[1]) : new theGaoDeMap.value.Pixel(-10, -33),
extData: marker
}
const markerItem = new theGaoDeMap.value.Marker(markerConfig)
markerItem.off('click')
markerItem.on('click', (res) => {
// 对父组件AMap暴露点击的marker点数据
markerEmits('markerClick', {
lat: res.lnglat.lat,
lng: res.lnglat.lng,
source: 'markerClick',
sourceData: res.target._opts.extData
})
})
return markerItem
})
console.log(`end marker`)
theMarker.overlayMarker = new theGaoDeMap.value.OverlayGroup(theMarker.markers)
theMap.value.add(theMarker.overlayMarker)
}
}
watch(() => theMap.value, initMarker)
watch(() => theMarkerProps.markers, initMarker, { immediate: true, deep:true })
</script>
<template>
</template>
\ No newline at end of file
<script setup>
import { useInjectGaoDeMap } from "@/components/AMap/hooks/useGaoDeMap";
import { useInjectMap } from "@/components/AMap/hooks/useMap";
import {reactive, watch} from "vue";
import {useTools} from "@/components/xMap/hooks/useTools";
const { covertPoint } = useTools()
const emits = defineEmits(['polygonChange', 'polygonClick']);
const theProps = defineProps({
polygons: {
type: Array,
default: () => []
}
})
const thePolygon = reactive({
polygons: [],
polygonEditor: null,
overlayPolygon: null,
})
const theMap = useInjectMap()
const theGaoDeMap = useInjectGaoDeMap()
const initPolygon = () => {
if(theMap.value && theGaoDeMap.value) {
if(thePolygon.overlayPolygon){
theMap.value.remove(thePolygon.overlayPolygon)
}
const polygonArr = theProps.polygons.map(each => {
const polygon = {
path: covertPoint(each.path),
name: 'Park',
strokeStyle: 'solid',
strokeColor: '#1788FF',
fillColor: '#69a8ff',
fillOpacity: 0.3,
strokeOpacity: 1,
strokeWeight: 4,
extData: each
}
const polygonInstance = new theGaoDeMap.value.Polygon(polygon)
polygonInstance.off('click')
polygonInstance.on('click', polygonClick)
if(each.editable) {
renderPolygonEditor(polygonInstance)
}
return polygonInstance
})
thePolygon.overlayPolygon = new theGaoDeMap.value.OverlayGroup(polygonArr)
theMap.value.add(thePolygon.overlayPolygon)
}
}
const renderPolygonEditor = (polygonInstance) => {
const extData = polygonInstance.getExtData()
if(thePolygon.polygonEditor){
thePolygon.polygonEditor.close()
theMap.value.remove(thePolygon.polygonEditor)
}
thePolygon.polygonEditor = new theGaoDeMap.value.PolygonEditor(theMap.value, polygonInstance)
thePolygon.polygonEditor.on('addnode', polygonChange)
thePolygon.polygonEditor.on('adjust', polygonChange)
thePolygon.polygonEditor.on('removenode', polygonChange)
thePolygon.polygonEditor.open()
}
const polygonChange = (res) => {
const path = (res.target.getPath() || []).map(el => ({ lat: el.lat, lng: el.lng }))
emits('polygonChange', path)
}
const polygonClick = (res) => {
emits('polygonClick', {
lat: res.lnglat.lat,
lng: res.lnglat.lng,
source: 'polygonClick',
sourceData: res.target._opts.extData
})
}
watch(() => theMap.value, initPolygon)
watch(() => theProps.polygons, initPolygon, { immediate: true, deep:true })
</script>
<template>
</template>
<style scoped lang="scss">
</style>
\ No newline at end of file
<script setup>
import {reactive, watch} from "vue";
import {useInjectMap} from "@/components/AMap/hooks/useMap";
import {useInjectGaoDeMap} from "@/components/AMap/hooks/useGaoDeMap";
const theProps = defineProps({
polylines: {
type: Array,
default: () => ([])
}
})
const thePolyline = reactive({
overlayPolyline: null
})
const theMap = useInjectMap()
const theGaoDeMap = useInjectGaoDeMap()
const initPolyline = () => {
if(theMap.value && theGaoDeMap.value) {
const { polylines = [] } = theProps
if (!polylines.length) return
const polyline = polylines.map(line => {
const {options = {}, paths = []} = line
return new theGaoDeMap.value.Polyline({
zIndex: 99,
map: theMap.value,
path: (paths || []).map(p => (new theGaoDeMap.value.LngLat(p.lng, p.lat))),
...options
})
})
thePolyline.overlayPolyline = new theGaoDeMap.value.OverlayGroup(polyline)
theMap.value.add(thePolyline.overlayPolyline)
}
}
watch(() => theMap.value, initPolyline)
watch(() => theProps.polylines, initPolyline, { immediate: true, deep:true })
</script>
<template>
</template>
<style scoped lang="scss">
</style>
\ No newline at end of file
import {ref} from "vue";
import AMapLoader from "@amap/amap-jsapi-loader";
export const theLoadMap = ref(null)
export const loadMap = () => {
return new Promise((resolve) => {
AMapLoader.load({
key: '0650fbe85c708dc3388fe803d0e5d861',
version: '2.0',
plugins: [
'AMap.Scale',
'AMap.OverView',
'AMap.ToolBar',
'AMap.MapType',
'AMap.Polyline',
'AMap.PolygonEditor',
'AMap.MarkerCluster',
'AMap.MoveAnimation',
'AMapUI'
]
}).then(AMap => {
theLoadMap.value = AMap
}).catch(err => {
console.log(err)
})
})
}
\ No newline at end of file
import {computed, inject, provide} from "vue";
const gaoDeMapProvider = Symbol('GaoDeMapProvider')
const useProviderGaoDeMap = (theGaoDeMap) => {
const gaoDeMap = computed(() => theGaoDeMap.value)
provide(gaoDeMapProvider, gaoDeMap)
return gaoDeMap
}
const useInjectGaoDeMap = () => {
return inject(gaoDeMapProvider, computed(() => null))
}
export {
useProviderGaoDeMap,
useInjectGaoDeMap
}
import {computed, inject, provide} from "vue";
const mapProvider = Symbol('MapProvider')
const useProviderMap = (theMap) => {
const map = computed(() => theMap.value)
provide(mapProvider, map)
return map
}
const useInjectMap = () => {
return inject(mapProvider, computed(() => null))
}
export {
useProviderMap,
useInjectMap
}
export default {
center: {
type: Object,
default: () => ({})
},
markers: {
type: Array,
default: () => []
},
polylines: {
type: Array,
default: () => ([])
},
massMarker: {
type: Object,
default: () => ({})
},
polygons: {
type: Array,
default: () => []
}
}
\ No newline at end of file
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
<script>
import {
onBeforeUnmount, defineComponent, h, Comment, watch, computed,
} from 'vue';
import { useInjectMap } from './useMapState';
export default {
setup() {
}
}
</script>
<template>
</template>
<style scoped lang="scss">
</style>
\ No newline at end of file
import {computed, reactive, shallowReactive, watch} from "vue";
const mapState = shallowReactive({
AMap: null,
map: null
})
export const useMapState = () => {
const setMapState = (AMap, map) => {
mapState.AMap = AMap
mapState.map = map
// console.log(mapState)
}
const getMapState = () => {
// console.log(mapState)
return mapState//computed(() => mapState)
}
return {
setMapState,
getMapState
}
}
\ No newline at end of file
import { useMapState } from "@/components/xMap/components/useMapState";
import {computed, shallowReactive, watch} from "vue";
import { useAMap } from '@/store/modules/AMap'
export const usePolygon = (props, mapState) => {
const AMapStore = useAMap()
const _Amap = computed(() => mapState.AMap)
watch(
() => mapState,
(val) => {
console.log('--->' ,val)
}
)
const polygonState = shallowReactive({
overlayPolygon: null, // 矩形覆盖物群组
})
const setPolygon = () => {
console.log('--->', _Amap)
const { AMap, map } = AMapStore.getMapState
if(polygonState.overlayPolygon){
map.remove(polygonState.overlayPolygon)
}
const polygonArr = props.polygons.map(each => {
const polygonInstance = renderPolygon(each)
console.log(polygonInstance)
return polygonInstance
})
polygonState.overlayPolygon = new _Amap.OverlayGroup(polygonArr)
map.add(polygonState.overlayPolygon)
}
const renderPolygon = (each) => {
const { AMap, map } = AMapStore.getMapState
const polygon = {
path: covertPoint(each.path),
name: 'Park',
strokeStyle: 'solid',
strokeColor: '#1788FF',
fillColor: '#69a8ff',
fillOpacity: 0.3,
strokeOpacity: 1,
strokeWeight: 4,
extData: each
}
const polygonInstance = new AMap.Polygon(polygon)
polygonInstance.off('click', (e) => console.log('click1', e))
polygonInstance.on('click', (e) => console.log('click2', e))
// const
return polygonInstance
}
const covertPoint = (pointList) => pointList.map(el =>([el.lng, el.lat]))
return {
renderPolygon,
setPolygon
}
}
\ No newline at end of file
export const useTools = () => {
const covertPoint = (pointList) => pointList.map(el =>([el.lng, el.lat]))
return {
covertPoint
}
}
\ No newline at end of file
export default {
center: {
type: Object,
default: () => ({ lat: 0, lng: 0 })
},
polygons: {
type: Array,
default: () => []
},
markers: {
type: Array,
default: () => []
},
massMarkers: {
type: Object,
default: () => ({})
},
infoWindow: {
type: Object,
default: () => (null)
}
}
\ No newline at end of file
......@@ -131,7 +131,7 @@ export const asyncRouterMap = [
component: () => import('@/views/Tenant/CreateTenant'),
meta: {
title: '新建租户',
// permission: [9999]
permission: [999]
},
}
]
......@@ -167,5 +167,10 @@ export const constantRouterMap = [
title: '404',
},
component: () => import(/* webpackChunkName: "fail" */ '@/views/Exception/404')
}
},
{
path: '/:pathMatch(.*)*',
component: async () => await import('@/views/Exception/404.vue'),
meta: { hideMenu: true, title: '404' },
},
]
\ No newline at end of file
......@@ -7,6 +7,15 @@ router.beforeEach(async (to, from, next) => {
const permission = usePermissionStore()
const user = useUser()
to.meta && to.meta.title && setDocumentTitle(`${to.meta.title}-喜安`)
const redirect = decodeURIComponent(from.query.redirect || to.path)
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect }
const token = 'token'
if(!token && to.path === '/login'){
next()
return
}
if (permission.getIsDynamicAddedRoute) {
next();
return;
......@@ -16,9 +25,6 @@ router.beforeEach(async (to, from, next) => {
routes.forEach((item) => {
router.addRoute(item);
})
const redirect = decodeURIComponent(from.query.redirect || to.path)
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect }
permission.setDynamicAddedRoute(true);
next(nextData);
next()
})
\ No newline at end of file
import { defineStore } from "pinia"
export const useAMap = defineStore({
id: 'AMap',
state: () => ({
AMap: null,
map: null,
}),
getters: {
getMapState () {
return {
AMap: this.AMap,
map: this.map
}
}
},
actions: {
setMapState (AMap, map) {
this.AMap = AMap
this.map = map
}
}
})
\ No newline at end of file
export const setDocumentTitle = (title) => {
document.querySelector('[rel="icon"]').setAttribute('href', 'https://ebike-saas-prod.oss-cn-shenzhen.aliyuncs.com/frontend/res/508.logo.png')
document.title = title
const ua = navigator.userAgent
const regex = /\bMicroMessenger\/([\d\.]+)/
......@@ -11,6 +13,6 @@ export const setDocumentTitle = (title) => {
i.remove()
}, 9)
}
document.body.appendChild(i)
document.body.appendChild(i)
}
}
\ No newline at end of file
<template>
<div class="test">
车辆管理
<a-button @click="submit">submit</a-button>
<a-button @click="submit2">submit2</a-button>
<a-button @click="submit3">生成mass点(图标)</a-button>
<AMap
:center="state.mapCenter"
:polylines="state.polylines"
:markers="state.markers"
:polygons="state.polygons"
:massMarker="state.massMarker"
@polygonChange="polygonChange"
@mapClick="mapClick"
>
</AMap>
</div>
</template>
<script>
export default {
<script setup>
import AMap from "@/components/AMap/AMap.vue";
import Marker from "@/components/AMap/Marker.vue";
import Polygon from "@/components/AMap/Polygon.vue";
import Cluster from "@/components/AMap/Cluster.vue";
import {reactive} from "vue";
import Polyline from "@/components/AMap/Polyline.vue";
const styleObjectArr = [
{
anchor: [0, 0],
url: `https://xinmaiadmin.xiaoantech.com/img/car.png`,
size: [40, 40]
},
{
url: 'https://xinmaiadmin.xiaoantech.com/img/parking.png',
size: [40, 40],
anchor: [20, 30]
}
]
const icon = {
// 图标类型,现阶段只支持 image 类型
type: 'image',
// 图片 url
image: 'https://a.amap.com/jsapi_demos/static/demo-center/marker/express2.png',
// 图片尺寸
size: [64, 30],
// 图片相对 position 的锚点,默认为 bottom-center
anchor: 'center',
};
const state = reactive({
markers: [
{
icon: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-red.png',
offset: [0, 0],
position: {
lng: 116.72,
lat: 40.10
},
}
],
polygons: [],
massMarker: {},
mapCenter: {
lat: 40.14,
lng: 114.45
}
})
const submit = () => {
state.markers.push({
icon: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-red.png',
offset: [0, 0],
position: {
lng: 116.04,
lat: 39.82
},
})
state.polygons = [
{
editable: false,
path: [
{
lng: 115.25,
lat: 38.99,
},
{
lng: 115.63,
lat: 38.71,
},
{
lng: 115.63,
lat: 38.70,
},
{
lng: 115.63,
lat: 38.96,
}
]
},
{
editable: true,
path: [
{
lng: 114.83,
lat: 41.04
},
{
lng: 115.14,
lat: 39.55,
},
{
lng: 117.75,
lat: 39.54,
},
{
lng: 117.95,
lat: 40.68,
}
]
},
]
console.log(state)
}
const submit2 = () => {
// state.polygons[0].editable = true
// state.polygons[1].editable = false
}
const submit3 = () => {
state.massMarker = {
renderMode: 'cluster',
styleObjectArr,
paths: [
{
"name": "自提点1",
"position": {"lng": 116.461009, "lat": 39.991443},
"zooms": [10, 20],
"opacity": 1,
"zIndex": 10,
"fold": true,
"icon": {
"type": "image",
"image": "https://a.amap.com/jsapi_demos/static/demo-center/marker/express2.png",
"size": [64, 30],
"anchor": "center"
},
"text": {
"content": "中邮速递易",
"customerRender": '',
"direction": "right",
"offset": [-20, -5],
"style": {
"fontSize": 12,
"fillColor": "#22886f",
"strokeColor": "#fff",
"strokeWidth": 2,
"fold": true,
"padding": "2, 5"
}
}
}, {
"name": "自提点2",
"position": {"lng": 116.466994, "lat": 39.984904},
"zooms": [10, 20],
"opacity": 1,
"zIndex": 16,
"icon": {
"type": "image",
"image": "https://a.amap.com/jsapi_demos/static/demo-center/marker/express2.png",
"size": [64, 30],
"anchor": "center"
},
"text": {"content": "丰巢快递柜-花家地北里", "direction": "right", "offset": [-20, -5]}
}, {
"name": "自提点3",
"position": {"lng": 116.472914, "lat": 39.987093},
"zooms": [10, 20],
"opacity": 1,
"zIndex": 8,
"icon": {
"type": "image",
"image": "https://a.amap.com/jsapi_demos/static/demo-center/marker/express2.png",
"size": [64, 30],
"anchor": "center"
},
"text": {"content": "丰巢快递柜-中环南路11号院", "direction": "right", "offset": [-20, -5]}
}, {
"name": "自提点4",
"position": {"lng": 116.471814, "lat": 39.995856},
"zooms": [10, 20],
"opacity": 1,
"zIndex": 23,
"icon": {
"type": "image",
"image": "https://a.amap.com/jsapi_demos/static/demo-center/marker/express2.png",
"size": [64, 30],
"anchor": "center"
},
"text": {"content": "丰巢快递柜-合生麒麟社", "direction": "right", "offset": [-20, -5]}
}, {
"name": "自提点5",
"position": {"lng": 116.469639, "lat": 39.986889},
"zooms": [10, 20],
"opacity": 1,
"zIndex": 6,
"icon": {
"type": "image",
"image": "https://a.amap.com/jsapi_demos/static/demo-center/marker/express2.png",
"size": [64, 30],
"anchor": "center"
},
"text": {"content": "速递易快递柜-望京大厦", "direction": "right", "offset": [-20, -5]}
}, {
"name": "自提点6",
"position": {"lng": 116.467361, "lat": 39.996361},
"zooms": [10, 20],
"opacity": 1,
"zIndex": 5,
"icon": {
"type": "image",
"image": "https://a.amap.com/jsapi_demos/static/demo-center/marker/express2.png",
"size": [64, 30],
"anchor": "center"
},
"text": {"content": "E栈快递柜-夏都家园", "direction": "right", "offset": [-20, -5]}
}, {
"name": "自提点7",
"position": {"lng": 116.462327, "lat": 39.996071},
"zooms": [10, 20],
"opacity": 1,
"zIndex": 4,
"icon": {
"type": "image",
"image": "https://a.amap.com/jsapi_demos/static/demo-center/marker/express2.png",
"size": [64, 30],
"anchor": "center"
},
"text": {"content": "丰巢自提柜-圣馨大地家园", "direction": "right", "offset": [-20, -5]}
}, {
"name": "自提点8",
"position": {"lng": 116.462349, "lat": 39.996067},
"zooms": [10, 20],
"opacity": 1,
"zIndex": 3,
"icon": {
"type": "image",
"image": "https://a.amap.com/jsapi_demos/static/demo-center/marker/express2.png",
"size": [64, 30],
"anchor": "center"
},
"text": {"content": "丰巢快递-圣馨大地家园", "direction": "right", "offset": [-20, -5]}
}, {
"name": "自提点9",
"position": {"lng": 116.456474, "lat": 39.991563},
"zooms": [10, 20],
"zIndex": 2,
"opacity": 1,
"icon": {
"type": "image",
"image": "https://a.amap.com/jsapi_demos/static/demo-center/marker/express2.png",
"size": [64, 30],
"anchor": "center"
},
"text": {"content": "E栈快递柜-南湖渠西里", "direction": "right", "offset": [-20, -5]}
}]
}
state.polylines = [
{
paths: [{"lng": 116.362209, "lat": 39.887487}, {"lng": 116.422897, "lat": 39.878002}, {
"lng": 116.372105,
"lat": 39.90651
}, {"lng": 116.428945, "lat": 39.89663}],
options: {
isOutline: true,
outlineColor: '#ffeeff',
borderWeight: 3,
strokeColor: "#3366FF",
strokeOpacity: 1,
strokeWeight: 6,
// 折线样式还支持 'dashed'
strokeStyle: "dashed",
// strokeStyle是dashed时有效
strokeDasharray: [15, 5],
lineJoin: 'round',
lineCap: 'round',
zIndex: 50,
}
},
{
paths: [{"lng": 116.32873535156249, "lat": 40.01499435375046}, {
"lng": 116.52099609375,
"lat": 40.019201307686785
}, {"lng": 116.49902343749999, "lat": 40.12849105685408}],
options: {
isOutline: true,
outlineColor: '#ffeeff',
borderWeight: 3,
strokeColor: "#0f0f0f",
strokeOpacity: 1,
strokeWeight: 6,
// 线样式还支持 'dashed'
strokeStyle: "solid",
// strokeStyle是dashed时有效
strokeDasharray: [10, 10],
lineJoin: 'round',
lineCap: 'round',
zIndex: 50,
}
}
]
}
const polygonChange = (path) => {
console.log(path)
}
const mapClick = (res) => {
state.mapCenter = {
lat: res.lat,
lng: res.lng
}
console.log(res)
}
</script>
<style lang="scss" scoped>
// .test{
// color: blue;
// }
.test {
color: blue;
height: 600px;
}
</style>
\ No newline at end of file
......@@ -5,12 +5,10 @@
<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
export default {
name: 'HomeView',
components: {
HelloWorld
}
}
</script>
......@@ -45,6 +45,7 @@
</div>
</template>
<script>
export default {
data() {
return {
......@@ -52,6 +53,8 @@ export default {
password: "",
};
},
mounted() {
},
methods: {
adds() {
this.add();
......
......@@ -69,7 +69,7 @@
import { defineComponent, onMounted, reactive, ref, toRefs } from "vue";
import { DownOutlined, UpOutlined } from "@ant-design/icons-vue";
// import Table from "@/components/Table/Table.vue";
// import { useLoading } from "@/hooks/useLoading";
// import { useLoading } from "@/components/useLoading";
export default defineComponent({
components: {
......
<template>
<div >
asdr
<SvgIcon name="businessScreen" :size="50" color="#ff00ff" />
<div class="map">
<a-button @click="click">submit</a-button>
<AMap
:markers="state.markers"
:polygons="state.polygons"
:massMarker="state.massMarker"
@mapClick="mapClick"
>
</AMap>
</div>
</div>
</template>
<script>
import XMap from "@/components/xMap/xMap.vue";
import AMap from "@/components/AMap/AMap.vue";
import {reactive, toRefs} from "vue";
export default {
setup () {
const state = reactive({
center: { lat: 0, lng: 0 },
polygons: [
{
editable: false,
path: [
{
lng: 115.25,
lat: 38.99,
},
{
lng: 115.63,
lat: 38.71,
},
{
lng: 115.63,
lat: 38.70,
},
{
lng: 115.63,
lat: 38.96,
}
]
},
],
markers: [
{
icon: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-red.png',
offset: [0 , 0],
position: {
lng: 116.72,
lat: 40.10
},
}
],
infoWindow: {},
massMarkers: {
styleObjectArr: [
{
anchor: [0, 0],
url: `https://xinmaiadmin.xiaoantech.com/img/parking.png`,
size: [40, 40]
},
],
}
})
const click= () => {
state.polygons[0].editable = true
// state.polygons[1].editable = true
state.infoWindow = {
isCustom: true,
content: '<div style="background: #fff">哈哈哈哈哈哈你店家啦</div>',
position: {
lng: 116.527519,
lat: 40.031821,
}
}
state.infoWindow.opened=true
console.warn(state)
}
const mapClick = (e) => {
const { source, lat, lng } = e
console.log(source)
if(source === 'marker' || source === 'polygon'){
state.infoWindow.content = '222'
// state.infoWindow = {
// isCustom: true,
// opened: true,
// content: '<div style="background: #fff">哈哈哈哈哈哈你店家啦</div>',
// position: {
// lng,
// lat,
// }
// }
console.warn(state.infoWindow)
}
}
return {
click,
mapClick,
state,
// ...toRefs(state)
}
},
components: {
XMap,
AMap
}
}
</script>
<style lang="scss" scoped>
.map{
width: 100%;
height: 600px;
}
</style>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment