This commit is contained in:
2023-07-24 17:31:15 +08:00
parent 6a14f15880
commit e692cd9fc8
10 changed files with 483 additions and 40 deletions

View File

@ -9,13 +9,14 @@
<link href="/favicon.ico" rel="icon">
<script type="text/javascript">
window._AMapSecurityConfig = {
securityJsCode: '7d1b758db4876389af608259c4c99832',
securityJsCode: '2b65e7751cb17e4605f4c4cdccf885f6',
// securityJsCode: '7d1b758db4876389af608259c4c99832',
}
</script>
<script src='//webapi.amap.com/maps?v=1.4.15&key=bfc7224388e835679ffe74cfbd28c8d6' type="text/javascript"></script>
<script src="https://webapi.amap.com/maps?v=1.4.11&key=bfc7224388e835679ffe74cfbd28c8d6&plugin=AMap.DistrictSearch"
type="text/javascript"></script>
<script src="//webapi.amap.com/ui/1.0/main.js?v=1.0.11"></script>
<!-- <script src='//webapi.amap.com/maps?v=1.4.15&key=bfc7224388e835679ffe74cfbd28c8d6' type="text/javascript"></script>-->
<!-- <script src="https://webapi.amap.com/maps?v=1.4.11&key=bfc7224388e835679ffe74cfbd28c8d6&plugin=AMap.DistrictSearch"-->
<!-- type="text/javascript"></script>-->
<!-- <script src="//webapi.amap.com/ui/1.0/main.js?v=1.0.11"></script>-->
<title>中科云</title>
<!--[if lt IE 11]>
<script>window.location.href = '/html/ie.html';</script><![endif]-->

View File

@ -16,16 +16,19 @@
"url": "https://gitee.com/y_project/RuoYi-Vue.git"
},
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
"@element-plus/icons-vue": "1.1.4",
"@vueuse/core": "8.5.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"animejs": "^3.2.1",
"axios": "0.26.1",
"echarts": "^5.4.0",
"echarts-extension-amap": "^1.10.1",
"element-plus": "2.1.8",
"file-saver": "2.0.5",
"fuse.js": "6.5.3",
"html2canvas": "^1.4.1",
"js-cookie": "3.0.1",
"js-md5": "^0.7.3",
"jsencrypt": "3.2.1",

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 B

View File

@ -0,0 +1,11 @@
<script setup>
</script>
<template>
</template>
<style scoped lang="scss">
</style>

View File

@ -1,31 +1,33 @@
<template>
<div class="paging">
<el-icon
class="prev"
:style="{
cursor: page === 1 ? 'not-allowed' : 'pointer',
color: page === 1 ? '#999' : '#4f93ed',
}"
class="prev"
@click="prev"
>
<ArrowLeftBold />
<ArrowLeftBold/>
</el-icon>
<div class="page-num">{{ page }}</div>
<el-icon
class="next"
:style="{
cursor: Math.ceil(total / 5) <= page ? 'not-allowed' : 'pointer',
color: Math.ceil(total / 5) <= page ? '#999' : '#4f93ed',
}"
class="next"
@click="next"
>
<ArrowRightBold />
<ArrowRightBold/>
</el-icon>
</div>
</template>
<script setup>
import { toRefs } from "vue";
import {toRefs} from "vue";
import {ArrowLeftBold, ArrowRightBold} from "@element-plus/icons-vue";
const emit = defineEmits(["update:page"]);
const props = defineProps({
total: {
@ -37,10 +39,10 @@ const props = defineProps({
required: true,
},
});
const { total, page } = toRefs(props);
const {total, page} = toRefs(props);
const prev = () => {
if (page.value == 1) return;
if (page.value === 1) return;
emit("update:page", page.value - 1);
};
const next = () => {
@ -50,6 +52,7 @@ const next = () => {
</script>
<style lang="scss" scoped>
.paging {
display: flex;
width: 100px;
z-index: 9999;
position: absolute;
@ -58,6 +61,7 @@ const next = () => {
transform: translateX(-50%);
justify-content: space-between;
align-items: center;
.prev,
.next {
user-select: none;
@ -66,5 +70,9 @@ const next = () => {
width: 30px;
height: 30px;
}
.page-num {
color: white;
}
}
</style>

View File

@ -0,0 +1,413 @@
<script setup>
import AMapLoader from '@amap/amap-jsapi-loader';
import {computed, onMounted, ref, shallowRef} from "vue";
import {init, registerMap} from "echarts";
import {
countAchievementByArea,
countAchievementByCity,
countAchievementByProvince,
countDemandByProvince,
countEnterpriseByArea,
countEnterpriseByCity,
countEnterpriseByProvince,
countExpertByArea,
countExpertByCity,
countExpertByProvince
} from "@/api/website/home";
import backBtnPng from '@/assets/images/map_back.png'
import RegionPagine from "@/views/website/home/comp/RegionPagine.vue";
import html2canvas from "html2canvas";
import anime from "animejs";
const leftBoxPageNum = ref(1)
const mapRef = ref(null);
const districtSearch = shallowRef(null)
const myEcharts = shallowRef(null)
const map = shallowRef(null)
const mapData = ref([])
const methods = [
{
name: "expert",
title: "专家分布地图",
byProvince: countExpertByProvince,
byCity: countExpertByCity,
byArea: countExpertByArea
},
{
name: "technology",
title: "技术分布地图",
byProvince: countAchievementByProvince,
byCity: countAchievementByCity,
byArea: countAchievementByArea
},
{
name: "demand",
title: "需求分布地图",
byProvince: countDemandByProvince,
byCity: countDemandByProvince,
byArea: countDemandByProvince
},
{
name: "enterprise",
title: "企业分布地图",
byProvince: countEnterpriseByProvince,
byCity: countEnterpriseByCity,
byArea: countEnterpriseByArea
},
]
const methodIndex = ref(0)
const areaCount = ref([]) // 按行政区划统计
const industryCount = ref([]) // 按领域统计
const areaCountPaged = computed(() => areaCount.value.slice((leftBoxPageNum.value - 1) * 5, leftBoxPageNum.value * 5))
const options = {
// nameProperty: 'adcode',
visualMap: {
type: "piecewise",
left: "center", //组件离容器左侧的距离,'left', 'center', 'right','20%'
bottom: "30",
orient: "horizontal", //图例排列方向
padding: 5,
pieces: [
{gte: 0, lte: 99, label: "99", color: "#CAE9FD"},
{gte: 100, lte: 299, label: "100-299", color: "#7ED2F7"},
{gte: 300, lte: 499, label: "299-499", color: "#039DDD"},
{gte: 500, label: "500", color: "#0D4884"},
],
textStyle: {
color: "#fff",
},
visibility: "off",
},
tooltip: {
//提示框信息
trigger: "item",
formatter: "{b}\n{c}人",
},
series: [
{
type: "map",
name: "中国",
map: "map",
data: []
},
],
}
const loadAMap = async () => {
const AMap = await AMapLoader.load({
"key": "377d7c36dd385e2a722f29d4c6e1ffbf", // 申请好的Web端开发者Key首次调用 load 时必填
"version": "2.0", // 指定要加载的 JS API 的版本,缺省时默认为 1.4.15
"plugins": ["AMap.DistrictSearch", "AMap.DistrictExplorer"], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
"AMapUI": {
// 是否加载 AMapUI缺省不加载
version: '1.1', // AMapUI 缺省 1.1
plugins: [], // 需要加载的 AMapUI ui插件
},
})
map.value = new AMap.Map("container", {
zoom: 4, //级别
center: [108.946609, 34.262324], //中心点坐标
// viewMode: '3D' //使用3D视图
});
map.value.on("click", mapClick)
districtSearch.value = new AMap.DistrictSearch({
level: 'province',
extensions: 'all',
subdistrict: 1,
showbiz: false,
})
}
const loading = ref(false)
const loadDistrict = (adcode) => {
loading.value = true
AMapUI.loadUI(["geo/DistrictExplorer"], (DistrictExplorer) => {
const districtExplorer = new DistrictExplorer({
map: map //关联的地图实例
});
districtExplorer.loadAreaNode(adcode, async (error, areaNode) => {
if (error) {
console.error(error);
loading.value = false
return;
}
const parentAdcode = areaNode.getAdcode()
// 绘制载入的区划节点
const geoJSON = {
type: 'FeatureCollection',
features: areaNode.getSubFeatures(),
}
const level = getLevel(adcode)
let result
try {
if (level === 0) {
result = await methods[methodIndex.value]['byProvince']()
} else if (level === 1) {
result = await methods[methodIndex.value]['byCity'](adcode)
} else if (level === 2) {
result = await methods[methodIndex.value]['byArea'](adcode)
}
} catch (e) {
loading.value = false
return
}
industryCount.value = result.industry
areaCount.value = result.count
mapData.value = geoJSON.features.map(el => {
const areaProp = el.properties
return {
adcode: areaProp.adcode,
name: areaProp.name,
value: result.count.find(el => el.code == areaProp.adcode)?.count ?? 0
}
})
registerMap("map", {geoJSON, specialAreas: {}})
options.series[0].data = mapData.value
myEcharts.value.setOption(
options
)
loading.value = false
});
})
}
// 返回地图上一级
const backMap = () => {
// loadDistrict(parentAdcode)
loadDistrict("100000")
}
onMounted(async () => {
await loadAMap()
myEcharts.value = init(mapRef.value)
myEcharts.value.on('click', mapClick)
loadDistrict("100000")
})
/**
* 根据adcode判断省市区级别
* @param adcode
* @return {number} 国家: 0 省: 1 市: 2 区: 3
*/
const getLevel = (adcode) => {
adcode = adcode.toString()
if (adcode === '100000') {
return 0
}
const splitPattern = /(\d{2})(\d{2})(\d{2})/;
const resultArray = adcode.match(splitPattern).slice(1);
// 国家: 0 省: 1 市: 2 区: 3
let result = resultArray.indexOf("00")
if (result === -1) {
result = 3
}
return result
}
const mapClick = (ev) => {
const level = getLevel(ev.data.adcode)
if (level === 3) {
return
}
loadDistrict(ev.data.adcode)
}
const handleScroll = (ev) => {
let direction = ev.deltaY > 0 ? 'down' : 'up'
// 判断滚轮滚动方向
if (direction === 'down' && methodIndex.value < methods.length - 1) {
methodIndex.value++
} else if (direction === 'up' && methodIndex.value > 0) {
methodIndex.value--
} else {
return
}
ev.preventDefault()
ev.stopPropagation()
const pageWrap = document.querySelector('.page-wrap')
const rootWrap = document.querySelector('.root-container')
html2canvas(pageWrap).then(canvas => {
if (direction === 'down') {
rootWrap.insertBefore(canvas, pageWrap)
} else if (direction === 'up') {
rootWrap.appendChild(canvas)
rootWrap.style.transform = 'translateY(-100%)'
}
anime({
targets: rootWrap,
translateY: direction === 'down' ? "-100%" : "0",
duration: 300,
easing: 'linear',
complete: () => {
rootWrap.removeChild(canvas)
rootWrap.style.transform = 'translateY(0%)'
}
})
})
loadDistrict("100000")
}
</script>
<template>
<div class="root-wrap">
<div class="root-container">
<div class="page-wrap" @wheel="handleScroll">
<div class="title">{{
methods[methodIndex].title
}}
</div>
<div v-if="loading" class="loading-modal">
</div>
<!-- 返回上一级按钮 -->
<div class="back-btn" @click="backMap">
<img :src="backBtnPng" alt="back"/>
</div>
<!-- 人数表格 -->
<div class="people-count">
<div class="table">
<div class="head">
<div class="th">
<div class="title">地区</div>
<div class="count">人数</div>
</div>
</div>
<div class="body">
<div v-for="item in areaCountPaged"
:key="item.adcode" class="tr">
<div class="title">{{ item.name }}</div>
<div class="count">{{ item.count }}</div>
</div>
</div>
</div>
<RegionPagine v-model:page="leftBoxPageNum" :total="areaCount.length"/>
</div>
<div id="map-container" ref="mapRef"></div>
<div
id="container"
style="width: 100%; height: 100%; background-color: rgb(0, 0, 0); display: none"
>
</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.scroll-to-top {
animation: 1s linear infinite page-scroll;
}
.root-wrap {
width: 100%;
height: 100%;
overflow: hidden;
.root-container {
width: 100%;
height: 100%;
> canvas {
transition: all 0.3s linear;
}
.page-wrap {
width: 100%;
height: 100%;
//top: 0;
//left: 0;
position: relative;
//transition: all 0.3s linear;
//animation: 1s linear forwards page-scroll;
.loading-modal {
position: absolute;
left: 0;
top: 0;
background: #f0f2f5;
}
#map-container {
width: 100%;
height: 100%;
background: linear-gradient(0deg, #010101, #041744);
}
> .title {
position: absolute;
top: 75px;
width: 100%;
text-align: center;
font-size: 36px;
font-family: Source Han Sans CN, sans-serif;
font-weight: 300;
color: #ffffff;
z-index: 101;
}
.back-btn {
position: absolute;
left: 120px;
top: 120px;
z-index: 99;
cursor: pointer;
}
.people-count {
position: absolute;
top: 300px;
left: 120px;
z-index: 101;
.table {
border: 1px solid #0054ff;
.head, .body {
.tr, .th {
display: flex;
color: white;
.title, .count {
width: 100px;
padding: 8px 12px;
text-align: center;
}
.title {
border-right: 1px solid #0054ff;
}
}
.th {
border-bottom: 1px solid #0054ff;
}
.tr {
color: rgb(161, 192, 255);
}
}
}
.pagination {
display: flex;
}
}
}
}
}
//@keyframes page-scroll {
// 0% {
// transform: translateY(0);
// }
// 100% {
// transform: translateY(-100%);
// }
//}
</style>

View File

@ -146,7 +146,7 @@ const testEnter = (ev) => {
console.log("rere");
};
const queryParams = reactive({
queryType: undefined,
// queryType: undefined,
keyword: "",
queryType: "2",
});

View File

@ -469,7 +469,7 @@ function loadMap(mapName, data) {
width: 100%;
text-align: center;
font-size: 36px;
font-family: Source Han Sans CN;
font-family: Source Han Sans CN,sans-serif;
font-weight: 300;
color: #ffffff;
}

View File

@ -58,6 +58,7 @@ import {
onUnmounted,
computed,
} from "vue";
import index0 from "./comp/index0.vue"
import index1 from "./comp/index1.vue";
import index2 from "./comp/index2.vue";
import index3 from "./comp/index3.vue";
@ -152,41 +153,47 @@ let state = reactive({
},
showBox: 0,
boxList: [
{
comp: shallowRef(index1),
zIndex: 1,
title: "index1",
},
{
comp: shallowRef(index0),
zIndex: 1,
title: "index1",
},
// {
// comp: shallowRef(index2),
// zIndex: 1,
// title: "index2",
// },
{
comp: shallowRef(index3),
zIndex: 1,
title: "index3",
},
// {
// comp: shallowRef(index3),
// zIndex: 1,
// title: "index3",
// },
// {
// comp: shallowRef(index4),
// zIndex: 1,
// title: "index4",
// },
{
comp: shallowRef(index5),
zIndex: 1,
title: "index5",
},
{
comp: shallowRef(index6),
zIndex: 1,
title: "index6",
},
{
comp: shallowRef(index7),
zIndex: 1,
title: "index7",
},
// {
// comp: shallowRef(index5),
// zIndex: 1,
// title: "index5",
// },
// {
// comp: shallowRef(index6),
// zIndex: 1,
// title: "index6",
// },
// {
// comp: shallowRef(index7),
// zIndex: 1,
// title: "index7",
// },
{
comp: shallowRef(index8),
zIndex: 1,

View File

@ -32,8 +32,8 @@ export default defineConfig(({ mode, command }) => {
// https://cn.vitejs.dev/config/#server-proxy
"/dev-api": {
// target: "http://101.34.131.16:1618",
// target: "http://101.34.131.16:1618",
target: "http://192.168.0.201:1618",
target: "http://101.34.131.16:1618",
// target: "http://192.168.0.201:1618",
// target: 'http://172.18.3.127:1618',
changeOrigin: true,
rewrite: (p) => p.replace(/^\/dev-api/, ""),