240 lines
5.4 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="china-map-container">
<div ref="chartRef" class="chart-container"></div>
<el-empty v-if="!loading && data.length === 0" description="暂无省份分布数据" />
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, watch, onUnmounted } from 'vue'
import type { EChartsOption } from 'echarts'
import echarts from '@/plugins/echarts'
import { registerChinaMap } from '@/plugins/echarts'
import { ProvinceChartVO } from '@/api/prison/dashboard'
import { debounce } from 'lodash-es'
defineOptions({ name: 'ChinaMap' })
interface Props {
data: ProvinceChartVO[]
loading?: boolean
}
const props = withDefaults(defineProps<Props>(), {
loading: false
})
const chartRef = ref<HTMLDivElement>()
let chartInstance: echarts.ECharts | null = null
// 省份编码到名称的映射(支持 2 位和 6 位 adcode
const provinceCodeMap: Record<string, string> = {
// 2位编码
'11': '北京市',
'12': '天津市',
'13': '河北省',
'14': '山西省',
'15': '内蒙古自治区',
'21': '辽宁省',
'22': '吉林省',
'23': '黑龙江省',
'31': '上海市',
'32': '江苏省',
'33': '浙江省',
'34': '安徽省',
'35': '福建省',
'36': '江西省',
'37': '山东省',
'41': '河南省',
'42': '湖北省',
'43': '湖南省',
'44': '广东省',
'45': '广西壮族自治区',
'46': '海南省',
'50': '重庆市',
'51': '四川省',
'52': '贵州省',
'53': '云南省',
'54': '西藏自治区',
'61': '陕西省',
'62': '甘肃省',
'63': '青海省',
'64': '宁夏回族自治区',
'65': '新疆维吾尔自治区',
'71': '台湾省',
'81': '香港特别行政区',
'82': '澳门特别行政区',
// 6位 adcode
'110000': '北京市',
'120000': '天津市',
'130000': '河北省',
'140000': '山西省',
'150000': '内蒙古自治区',
'210000': '辽宁省',
'220000': '吉林省',
'230000': '黑龙江省',
'310000': '上海市',
'320000': '江苏省',
'330000': '浙江省',
'340000': '安徽省',
'350000': '福建省',
'360000': '江西省',
'370000': '山东省',
'410000': '河南省',
'420000': '湖北省',
'430000': '湖南省',
'440000': '广东省',
'450000': '广西壮族自治区',
'460000': '海南省',
'500000': '重庆市',
'510000': '四川省',
'520000': '贵州省',
'530000': '云南省',
'540000': '西藏自治区',
'610000': '陕西省',
'620000': '甘肃省',
'630000': '青海省',
'640000': '宁夏回族自治区',
'650000': '新疆维吾尔自治区',
'710000': '台湾省',
'810000': '香港特别行政区',
'820000': '澳门特别行政区'
}
// 获取省份名称
const getProvinceName = (code: string | number): string => {
const codeStr = String(code)
// 优先尝试完整匹配6位 adcode
if (provinceCodeMap[codeStr]) {
return provinceCodeMap[codeStr]
}
// 如果是2位编码尝试匹配
const shortCode = codeStr.padStart(2, '0')
return provinceCodeMap[shortCode] || codeStr
}
// 格式化数据为 ECharts 地图数据格式
const formatMapData = (data: ProvinceChartVO[]) => {
return data.map((item) => ({
name: getProvinceName(item.provinceCode),
value: item.count
}))
}
// 获取最大值
const getMaxValue = (data: ProvinceChartVO[]): number => {
if (data.length === 0) return 100
return Math.max(...data.map((item) => item.count), 100)
}
// 更新图表
const updateChart = () => {
if (!chartInstance || !chartRef.value) return
const mapData = formatMapData(props.data)
const maxValue = getMaxValue(props.data)
const option: EChartsOption = {
tooltip: {
trigger: 'item',
formatter: (params: any) => {
if (params.value === undefined) {
return `${params.name}: 暂无数据`
}
return `${params.name}: ${params.value}`
}
},
visualMap: {
min: 0,
max: maxValue,
left: 'left',
top: 'bottom',
text: ['高', '低'],
calculable: true,
inRange: {
color: ['#e0f3f8', '#91c7ae', '#c23531']
}
},
series: [
{
name: '籍贯分布',
type: 'map',
map: 'china',
roam: true,
zoom: 1.2,
scaleLimit: {
min: 0.5,
max: 3
},
label: {
show: true,
fontSize: 10,
color: '#333'
},
emphasis: {
label: {
show: true,
fontSize: 12,
fontWeight: 'bold'
},
itemStyle: {
areaColor: '#ffd700'
}
},
data: mapData
}
]
}
chartInstance.setOption(option)
}
// 初始化图表
const initChart = () => {
if (!chartRef.value) return
chartInstance = echarts.init(chartRef.value)
updateChart()
}
// 监听数据变化
watch(
() => props.data,
() => {
updateChart()
},
{ deep: true }
)
// 响应式调整
const resizeHandler = debounce(() => {
chartInstance?.resize()
}, 100)
onMounted(async () => {
// 注册中国地图
await registerChinaMap()
// 初始化图表
initChart()
window.addEventListener('resize', resizeHandler)
})
onUnmounted(() => {
window.removeEventListener('resize', resizeHandler)
chartInstance?.dispose()
})
</script>
<style lang="scss" scoped>
.china-map-container {
width: 100%;
height: 500px;
position: relative;
.chart-container {
width: 100%;
height: 100%;
}
}
</style>