feat: 优化上海街道地图展示并添加3D效果
- 将2D地图升级为3D地图展示,增强视觉效果 - 添加渐变炫彩边框样式提升UI美观度 - 修复类型检查错误并优化代码结构 - 更新vite配置允许特定主机访问 - 移除无用导入和注释代码
This commit is contained in:
parent
1241191f38
commit
be85d94ad7
4
.env
4
.env
@ -1,5 +1,5 @@
|
||||
# VITE_MAINURL=http://127.0.0.1:8081/
|
||||
VITE_MAINURL=http://localhost:8081/
|
||||
VITE_MAINURL=http://127.0.0.1:8081/
|
||||
# VITE_MAINURL=https://6k4n616846.goho.co/
|
||||
# VITE_MAINURL=http://192.168.1.12:8081/
|
||||
# VITE_MAINURL=http://6adad28a.r36.cpolar.top
|
||||
# VITE_MAINURL=https://10.86.138.22/shp/
|
BIN
public/image/bg10.png
Normal file
BIN
public/image/bg10.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 503 KiB |
@ -1,4 +1,3 @@
|
||||
import { component } from '@nutui/nutui/dist/types/__VUE/grid/common'
|
||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||
|
||||
const routes = [
|
||||
|
@ -2763,8 +2763,8 @@ const initStreetChart = () => {
|
||||
map: "JiedaoMap", // 使用注册的地图名称
|
||||
geoIndex: 10, // 地理坐标系组件的索引
|
||||
zoom: 0.87, // 地图缩放等级
|
||||
left: streetLeft[districtValue.value], // 距离左侧10%
|
||||
top: streetTop[districtValue.value], //
|
||||
left: (streetLeft as any)[districtValue.value], // 距离左侧10%
|
||||
top: (streetTop as any)[districtValue.value], //
|
||||
// center: ["50%", "50%"], // 地图中心点坐标
|
||||
showLegendSymbol: false, // 不显示图例标记
|
||||
label: {
|
||||
|
@ -318,6 +318,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// @ts-nocheck
|
||||
import VueDraggableResizable from "vue-draggable-resizable/src/components/vue-draggable-resizable.vue";
|
||||
import "vue-draggable-resizable/dist/VueDraggableResizable.css";
|
||||
import { onMounted, reactive, ref, watch, onBeforeUnmount } from "vue";
|
||||
|
@ -9,7 +9,8 @@
|
||||
|
||||
<!-- <div class="w-full h-screen bg-gradient-to-tr from-green-300 via-cyan-500 to-blue-400"
|
||||
:style="{ backgroundColor: basicOptions.backgroundColor }" id="mainContainer"> -->
|
||||
<div class="w-full h-screen bg-gradient-to-b from-blue-800 to-gray-800 relative overflow-hidden" id="mainContainer">
|
||||
<div class="w-full h-screen relative overflow-hidden bg-[url(/image/bg10.png)] m-0 bg-cover bg-no-repeat bg-center"
|
||||
id="mainContainer">
|
||||
<!-- 科技感背景元素 -->
|
||||
<div class="absolute inset-0 w-full h-full overflow-hidden">
|
||||
<div
|
||||
@ -25,9 +26,9 @@
|
||||
class="absolute top-0 right-0 h-full w-[2px] bg-gradient-to-b from-transparent via-cyan-500 to-transparent opacity-70">
|
||||
</div>
|
||||
<!-- 科技感图案 -->
|
||||
<div class="absolute top-10 left-10 w-[200px] h-[200px] border-l-2 border-t-2 border-cyan-500 opacity-20"></div>
|
||||
<div class="absolute bottom-10 right-10 w-[200px] h-[200px] border-r-2 border-b-2 border-cyan-500 opacity-20">
|
||||
</div>
|
||||
<!-- <div class="absolute top-10 left-10 w-[200px] h-[200px] border-l-2 border-t-2 border-cyan-500 opacity-20"></div> -->
|
||||
<!-- <div class="absolute bottom-10 right-10 w-[200px] h-[200px] border-r-2 border-b-2 border-cyan-500 opacity-20">
|
||||
</div> -->
|
||||
<div
|
||||
class="absolute top-0 left-0 w-full h-full bg-[url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMCAwIDQwIDQwIj48ZyBmaWxsPSJub25lIiBzdHJva2U9IiMwYmI3ZmYiIHN0cm9rZS13aWR0aD0iMC4yIiBvcGFjaXR5PSIwLjIiPjxwYXRoIGQ9Ik0yMCAyMCBMMCAyMCBMMCA0MCIvPjxwYXRoIGQ9Ik0yMCAyMCBMNDAgMjAgTDQwIDQwIi8+PHBhdGggZD0iTTIwIDIwIEwwIDIwIEwwIDAiLz48cGF0aCBkPSJNMjAgMjAgTDQwIDIwIEw0MCAwIi8+PC9nPjwvc3ZnPg==')] bg-repeat opacity-5">
|
||||
</div>
|
||||
@ -87,26 +88,30 @@
|
||||
<!-- 左1 -->
|
||||
<vue-draggable-resizable ref="refWoTe1" style="border: none; z-index: 999" :draggable="draggableBoolean"
|
||||
:resizable="resizableBoolean">
|
||||
<div class="flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
||||
<div
|
||||
class="fancy-border flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
||||
ref="main1"></div>
|
||||
</vue-draggable-resizable>
|
||||
<!-- 左2 -->
|
||||
<vue-draggable-resizable ref="refWoTe2" style="border: none; z-index: 999" :draggable="draggableBoolean"
|
||||
:resizable="resizableBoolean">
|
||||
<div class="flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
||||
<div
|
||||
class="fancy-border flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
||||
ref="main2"></div>
|
||||
</vue-draggable-resizable>
|
||||
<!-- 左3 -->
|
||||
<vue-draggable-resizable ref="refWoTe3" style="border: none; z-index: 999" :draggable="draggableBoolean"
|
||||
:resizable="resizableBoolean">
|
||||
<div class="flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
||||
<div
|
||||
class="fancy-border flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
||||
ref="main3"></div>
|
||||
</vue-draggable-resizable>
|
||||
|
||||
<!-- 右1 -->
|
||||
<vue-draggable-resizable ref="refWoTe4" style="border: none; z-index: 999" :draggable="draggableBoolean"
|
||||
:resizable="resizableBoolean">
|
||||
<div class="flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
||||
<div
|
||||
class="fancy-border flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
||||
ref="main4">
|
||||
<div class="flex justify-around text-white">
|
||||
<div class="p-2 flex flex-col font-semibold items-center">
|
||||
@ -142,7 +147,8 @@
|
||||
<!-- 右2 -->
|
||||
<vue-draggable-resizable ref="refWoTe5" style="border: none; z-index: 999;" :draggable="draggableBoolean"
|
||||
:resizable="resizableBoolean">
|
||||
<div class="flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
||||
<div
|
||||
class="fancy-border flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
||||
ref="main5">
|
||||
<div class="scroll-wrapper" v-if="defaultShow">
|
||||
<div class="scroll-header">
|
||||
@ -325,20 +331,20 @@
|
||||
<vue-draggable-resizable ref="refWoTe6" style="border: none; z-index: 999" :draggable="draggableBoolean"
|
||||
:resizable="resizableBoolean" v-show="!relationShow && !isAnimating">
|
||||
<div
|
||||
class="flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500 overflow-hidden"
|
||||
class="fancy-border flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500"
|
||||
ref="main6">
|
||||
|
||||
</div>
|
||||
</vue-draggable-resizable>
|
||||
<!-- 右下角按钮 -->
|
||||
<div ref="fancyBtn"
|
||||
class=" fixed z-[9999] bottom-10 right-7 px-3 py-1 rounded-full bg-gradient-to-r from-blue-500 via-cyan-400 to-purple-500 shadow-lg text-white font-bold text-lg cursor-pointer transition-all duration-300 ease-in-out hover:scale-110 hover:shadow-2xl active:scale-95 active:brightness-90 ring-2 ring-white/30 ring-offset-2 ring-offset-black backdrop-blur-md overflow-hidden"
|
||||
class=" fixed z-[9999] bottom-20 right-7 px-3 py-1 rounded-full bg-gradient-to-r from-blue-500 via-cyan-400 to-purple-500 shadow-lg text-white font-bold text-lg cursor-pointer transition-all duration-300 ease-in-out hover:scale-110 hover:shadow-2xl active:scale-95 active:brightness-90 ring-2 ring-white/30 ring-offset-2 ring-offset-black backdrop-blur-md overflow-hidden"
|
||||
@click="handleFancyClick" style="user-select: none;">
|
||||
关联关系图
|
||||
<span ref="ripple" class="ripple"></span>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500 overflow-hidden z-[999] fixed bottom-10 right-7"
|
||||
class="fancy-border flex items-center justify-center w-96 h-48 border-2 border-dashed rounded border-gray-500 z-[999]"
|
||||
ref="main9" :class="{
|
||||
'animate-popup': isAnimating && relationShow,
|
||||
'animate-shrink': isAnimating && !relationShow,
|
||||
@ -408,6 +414,7 @@ import { router } from "../router";
|
||||
import headMenu from "../components/headMenu.vue";
|
||||
import * as echarts from "echarts";
|
||||
import "echarts-wordcloud";
|
||||
import "echarts-gl";
|
||||
import * as d3 from "d3";
|
||||
|
||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||
@ -1859,7 +1866,7 @@ const echarts3 = () => {
|
||||
const echarts6_old = async () => {
|
||||
var myChart = echarts.init(main6.value);
|
||||
var option: EChartsOption;
|
||||
const timeValueMap = {
|
||||
const timeValueMap: Record<string, number> = {
|
||||
上三个月: -3,
|
||||
上二个月: -2,
|
||||
上一个月: -1,
|
||||
@ -2306,7 +2313,10 @@ const echarts6_old = async () => {
|
||||
// console.log('littlemonth.value', littlemonth.value);
|
||||
// console.log('mockDataSou11', mockDataSou,"222",mockDataSource);
|
||||
console.log("mockDataSou", mockDataSou);
|
||||
const mockData = mockDataSou.timeScores.map((item) => item.scores);
|
||||
if (!mockDataSou) {
|
||||
return;
|
||||
}
|
||||
const mockData = mockDataSou.timeScores.map((item: any) => item.scores);
|
||||
console.log("mockData", mockData);
|
||||
option = {
|
||||
baseOption: {
|
||||
@ -2324,7 +2334,7 @@ const echarts6_old = async () => {
|
||||
"下三个月",
|
||||
],
|
||||
currentIndex: 3,
|
||||
label: { formatter: (s: string) => s },
|
||||
label: { formatter: (value: string | number, index: number) => String(value) },
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
@ -2405,9 +2415,10 @@ const echarts6_old = async () => {
|
||||
myChart.setOption(option);
|
||||
|
||||
// 保留时间轴变化监听
|
||||
myChart.on("timelinechanged", (params) => {
|
||||
const currentName = option.baseOption.timeline.data[params.currentIndex];
|
||||
const clickValue = timeValueMap[currentName];
|
||||
myChart.on("timelinechanged", (params: any) => {
|
||||
const dataArr = ((option as any).baseOption.timeline.data as string[]);
|
||||
const currentName = dataArr[params.currentIndex] as string;
|
||||
const clickValue = timeValueMap[currentName] ?? 0;
|
||||
littlemonth.value = clickValue;
|
||||
});
|
||||
};
|
||||
@ -2741,7 +2752,7 @@ const echartsYibiao = () => {
|
||||
const initTimelineChart = () => {
|
||||
var myChart = echarts.init(timeline.value);
|
||||
var option: EChartsOption;
|
||||
const timeValueMap = {
|
||||
const timeValueMap: Record<string, number> = {
|
||||
上三个月: -3,
|
||||
上二个月: -2,
|
||||
上一个月: -1,
|
||||
@ -2768,8 +2779,8 @@ const initTimelineChart = () => {
|
||||
],
|
||||
currentIndex: 3, // 默认选中第四个时间点
|
||||
label: {
|
||||
formatter: function (s) {
|
||||
return s;
|
||||
formatter: function (value: string | number, index: number) {
|
||||
return String(value);
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -2789,8 +2800,8 @@ const initTimelineChart = () => {
|
||||
type: "shadow",
|
||||
label: {
|
||||
show: true,
|
||||
formatter: function (params) {
|
||||
return params.value.replace("\n", "");
|
||||
formatter: function (params: any) {
|
||||
return String(params.value).replace("\n", "");
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -2807,9 +2818,10 @@ const initTimelineChart = () => {
|
||||
myChart.setOption(option);
|
||||
|
||||
// 监听时间轴的时间点变化事件
|
||||
myChart.on("timelinechanged", (params) => {
|
||||
const currentName = option.baseOption.timeline.data[params.currentIndex];
|
||||
const clickValue = timeValueMap[currentName];
|
||||
myChart.on("timelinechanged", (params: any) => {
|
||||
const dataArr = ((option as any).baseOption.timeline.data as string[]);
|
||||
const currentName = dataArr[params.currentIndex] as string;
|
||||
const clickValue = timeValueMap[currentName] ?? 0;
|
||||
littlemonth.value = clickValue;
|
||||
SelectBlur();
|
||||
});
|
||||
@ -3466,137 +3478,95 @@ const initStreetChart = () => {
|
||||
|
||||
console.log("streetScore", streetScore);
|
||||
|
||||
const streetOption = {
|
||||
//网格布局
|
||||
grid: {
|
||||
right: "100%",
|
||||
top: "10%",
|
||||
// bottom: "10%",
|
||||
width: "20%",
|
||||
left: "12%", // 调整此属性以向右移动柱状图
|
||||
},
|
||||
//区间分数
|
||||
const streetOption3D: any = {
|
||||
visualMap: {
|
||||
pieces: scoreIntervals.map((interval) => ({
|
||||
gte: parseFloat(interval.min.toFixed(1)),
|
||||
lte: parseFloat(interval.max.toFixed(1)),
|
||||
color: interval.color,
|
||||
})),
|
||||
show: true, // 视觉映射控件
|
||||
//定位区间
|
||||
left: "83%", // 距离容器左侧 10%
|
||||
top: "5%", // 垂直居中
|
||||
orient: "vertical", // 垂直方向
|
||||
show: true,
|
||||
left: "83%",
|
||||
top: "5%",
|
||||
orient: "vertical",
|
||||
textStyle: {
|
||||
color: "#dbeafe",
|
||||
fontSize: 12, // 设置字体大小
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: "map", // 图表类型为地图
|
||||
type: "map3D", // 图表类型为三维地图
|
||||
map: "JiedaoMap", // 使用注册的地图名称
|
||||
geoIndex: 10, // 地理坐标系组件的索引
|
||||
zoom: districtValue.value === "上海市" ? 1.2 : 0.9, // 地图缩放等级
|
||||
// left: '18%', // 距离左侧10%
|
||||
// top: '15%', //
|
||||
data: streetScore, // 地图数据,包含各街道的分数
|
||||
shading: "lambert", // 着色方式,lambert为漫反射
|
||||
left: "center",
|
||||
top: districtValue.value === "上海市" ? "12%" : "15%",
|
||||
right: "auto",
|
||||
bottom: "auto",
|
||||
// center: [121.52, 30.94],
|
||||
showLegendSymbol: false, // 不显示图例标记
|
||||
top: districtValue.value === "上海市" ? "-20%" : "0%",
|
||||
height: 'auto',
|
||||
label: {
|
||||
normal: {
|
||||
show: true, // 正常状态下显示标签
|
||||
formatter: function (params: { name: any; data: { value: any } }) {
|
||||
const name = params.name;
|
||||
const value = params.data ? params.data.value : "";
|
||||
return `${name}\n${value}`;
|
||||
show: true, // 是否显示标签
|
||||
// formatter: (p: any) => `${p.name}\n${p?.data?.value ?? ""}`, // 标签内容格式化,显示街道名和分数
|
||||
formatter: (p: any) => {
|
||||
switch (p.name) {
|
||||
case '普陀区':
|
||||
return `普陀\n${p?.data?.value ?? ""}`
|
||||
break;
|
||||
case '静安区':
|
||||
return `静安\n${p?.data?.value ?? ""}`
|
||||
break;
|
||||
case '虹口区':
|
||||
return `虹口\n${p?.data?.value ?? ""}`
|
||||
break;
|
||||
case '杨浦区':
|
||||
return `杨浦\n${p?.data?.value ?? ""}`
|
||||
break;
|
||||
case '长宁区':
|
||||
return `长宁\n${p?.data?.value ?? ""}`
|
||||
break;
|
||||
case '黄浦区':
|
||||
return `黄浦\n${p?.data?.value ?? ""}`
|
||||
break;
|
||||
case '徐汇区':
|
||||
return `徐汇\n${p?.data?.value ?? ""}`
|
||||
break;
|
||||
default:
|
||||
return `${p.name}\n${p?.data?.value ?? ""}`
|
||||
break;
|
||||
}
|
||||
},
|
||||
textStyle: {
|
||||
color: "#fff", // 标签文字颜色
|
||||
fontSize: 11, // 标签文字大小
|
||||
textStyle: { color: "#fff", fontSize: 12, fontWeight: '700' }, // 标签文字样式
|
||||
},
|
||||
itemStyle: {
|
||||
borderWidth: 0.5,
|
||||
borderColor: "#FFFFFF", // 区域边界颜色
|
||||
opacity: 1, // 区域透明度
|
||||
},
|
||||
emphasis: {
|
||||
show: true,
|
||||
textStyle: { color: "#fff" },
|
||||
}, // 高亮状态下不显示标签,文本颜色为白色
|
||||
label: { show: true, textStyle: { color: "#fff" } }, // 高亮时的标签样式
|
||||
},
|
||||
roam: false, // 关闭鼠标缩放和平移漫游
|
||||
itemStyle: {
|
||||
normal: { areaColor: "#031525", borderColor: "#FFFFFF" }, // 正常状态下区域颜色和边界颜色
|
||||
emphasis: { areaColor: "#2B91B7" }, // 高亮状态下区域颜色
|
||||
regionHeight: 5, // 地图区域高度
|
||||
viewControl: {
|
||||
distance: 135, // 视角距离(上海市时稍远一些,看起来更小)
|
||||
alpha: 45, // 视角俯仰角
|
||||
beta: -15, // 视角旋转角
|
||||
panMouseButton: "left", // 平移操作的鼠标按键
|
||||
rotateMouseButton: "right", // 旋转操作的鼠标按键
|
||||
},
|
||||
animation: false, // 关闭动画
|
||||
data: streetScore, // 地图数据
|
||||
},
|
||||
{
|
||||
type: "bar",
|
||||
data: streetScore.map((item) => 0),
|
||||
barWidth: 10, // 设置柱子最大宽度为10px
|
||||
barMaxWidth: 0, // 设置柱子最大宽度为0
|
||||
barMinWidth: 0, // 设置柱子最小宽度为0
|
||||
// 隐藏柱子核心配置
|
||||
itemStyle: {
|
||||
show: false,
|
||||
color: "#dbeafe", //
|
||||
borderColor: "transparent", // 同步隐藏边框
|
||||
},
|
||||
label: {
|
||||
show: false,
|
||||
position: "right",
|
||||
color: "#dbeafe",
|
||||
fontSize: 15,
|
||||
distance: 10,
|
||||
formatter: (params: { dataIndex: number }) =>
|
||||
streetScore[params.dataIndex].value,
|
||||
// 关键修复:强制标签显示
|
||||
overflow: "truncate", // 文本溢出处理
|
||||
// height: 50, // 设置标签最大高度
|
||||
width: 50, // 设置标签最大宽度
|
||||
align: "left", // 左对齐保证位置
|
||||
light: {
|
||||
main: { intensity: 1.2 }, // 主光源强度
|
||||
ambient: { intensity: 0.3 }, // 环境光强度
|
||||
},
|
||||
},
|
||||
],
|
||||
xAxis: {
|
||||
type: "value",
|
||||
position: "top",
|
||||
show: false,
|
||||
// splitLine: { show: false },
|
||||
// axisLabel: { show: false },
|
||||
// axisLine: { show: false },
|
||||
// axisTick: { show: false }
|
||||
},
|
||||
yAxis: {
|
||||
show: false,
|
||||
type: "category",
|
||||
data: streetScore.map((item) => item.name),
|
||||
axisLabel: {
|
||||
color: "#dbeafe", // 设置统一的颜色
|
||||
formatter: function (value: string) {
|
||||
if (value === "上海市奉贤区海湾旅游区") {
|
||||
return "上海...旅游区";
|
||||
} else if (value === "上海海港综合经济开发区") {
|
||||
return "上海...开发区";
|
||||
}
|
||||
return value;
|
||||
},
|
||||
},
|
||||
boundaryGap: true,
|
||||
axisLine: { show: true },
|
||||
axisTick: { show: true },
|
||||
},
|
||||
};
|
||||
|
||||
streetChart.setOption(streetOption);
|
||||
streetChart.setOption(streetOption3D);
|
||||
|
||||
// 监听点击事件
|
||||
streetChart.on("click", function (params) {
|
||||
if (
|
||||
params.componentType === "series" &&
|
||||
params.seriesType === "map" &&
|
||||
params.seriesType === "map3D" &&
|
||||
selectedStreet.value !== params.name
|
||||
) {
|
||||
selectedStreet.value = params.name; // 设置选中的区域名称
|
||||
@ -3606,7 +3576,7 @@ const initStreetChart = () => {
|
||||
// 在这里可以添加更多的逻辑来处理高亮区域
|
||||
} else if (
|
||||
params.componentType === "series" &&
|
||||
params.seriesType === "map" &&
|
||||
params.seriesType === "map3D" &&
|
||||
selectedStreet.value == params.name
|
||||
) {
|
||||
//重复点击某个区块(街道)
|
||||
@ -3637,8 +3607,8 @@ const initRelationshipChart = () => {
|
||||
chartRelationship = echarts.init(chartDom);
|
||||
|
||||
getRelationshipNetwork().then((res) => {
|
||||
let nodes;
|
||||
let links;
|
||||
let nodes: any[];
|
||||
let links: any[];
|
||||
// 处理节点数据,为每个节点设置初始样式
|
||||
if (handleRowValue.value == "") {
|
||||
// 处理连线数据,为每条连线设置初始样式
|
||||
@ -3672,7 +3642,7 @@ const initRelationshipChart = () => {
|
||||
nodes = res.data.nodes
|
||||
// 筛选出存在于任何连线中的节点
|
||||
.filter((node: any) =>
|
||||
links.some(link =>
|
||||
links.some((link: any) =>
|
||||
link.target === node.name || link.source === node.name
|
||||
)
|
||||
)
|
||||
@ -3759,7 +3729,7 @@ const initRelationshipChart = () => {
|
||||
};
|
||||
|
||||
// 渲染图表
|
||||
chartRelationship.setOption(option);
|
||||
chartRelationship!.setOption(option as any);
|
||||
});
|
||||
|
||||
// 窗口变化时自适应
|
||||
@ -3997,8 +3967,8 @@ const zhifaPinfaData = ref([
|
||||
// 新增:品发折线图渲染函数
|
||||
const choujianEchartsPinfa = () => {
|
||||
// 销毁已有实例,防止重复渲染
|
||||
if (main7.value && echarts.getInstanceByDom(main7.value)) {
|
||||
echarts.getInstanceByDom(main7.value).dispose();
|
||||
if (main7.value && echarts.getInstanceByDom(main7.value as HTMLElement)) {
|
||||
echarts.getInstanceByDom(main7.value as HTMLElement)?.dispose();
|
||||
}
|
||||
var myChart = echarts.init(main7.value);
|
||||
const months = ["1月", "2月", "3月", "4月", "5月"];
|
||||
@ -4061,14 +4031,13 @@ const choujianEchartsPinfa = () => {
|
||||
// },
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: function (params) {
|
||||
formatter: function (params: any[]) {
|
||||
let ymonth = "";
|
||||
let result = '';
|
||||
const dataMap = {};
|
||||
const dataMap: Record<string, { value: number | null; prediction: number | null }> = {};
|
||||
|
||||
// 合并实线和虚线数据
|
||||
params.forEach(item => {
|
||||
// console.log(item);
|
||||
params.forEach((item: any) => {
|
||||
const isPrediction = item.seriesName.includes('预测');
|
||||
const baseName = isPrediction ? item.seriesName.replace('预测', '') : item.seriesName;
|
||||
|
||||
@ -4077,22 +4046,20 @@ const choujianEchartsPinfa = () => {
|
||||
}
|
||||
|
||||
if (isPrediction) {
|
||||
dataMap[baseName].prediction = item.value;
|
||||
dataMap[baseName].prediction = item.value as number | null;
|
||||
} else {
|
||||
dataMap[baseName].value = item.value;
|
||||
dataMap[baseName].value = item.value as number | null;
|
||||
}
|
||||
|
||||
ymonth = item.name;
|
||||
// console.log(ymonth);
|
||||
});
|
||||
|
||||
// 构建tooltip内容
|
||||
Object.keys(dataMap).forEach(name => {
|
||||
Object.keys(dataMap).forEach((name: string) => {
|
||||
const item = dataMap[name];
|
||||
if (item.prediction && ymonth == "5月") {
|
||||
if (item.prediction != null && ymonth == "5月") {
|
||||
result += `${name}: (预测: ${item.prediction}%)`;
|
||||
} else {
|
||||
result += `${name}: ${item.value || '0'}%`;
|
||||
result += `${name}: ${item.value ?? 0}%`;
|
||||
}
|
||||
result += '<br/>';
|
||||
});
|
||||
@ -4105,10 +4072,10 @@ const choujianEchartsPinfa = () => {
|
||||
top: 30,
|
||||
textStyle: { color: "#fff" },
|
||||
// 只显示主线legend
|
||||
selected: legendData.reduce((acc, cur) => {
|
||||
selected: legendData.reduce((acc: Record<string, boolean>, cur: string) => {
|
||||
acc[cur] = true;
|
||||
return acc;
|
||||
}, {}),
|
||||
}, {} as Record<string, boolean>),
|
||||
},
|
||||
grid: { left: 45, right: 30, top: 63, bottom: 45 },
|
||||
xAxis: {
|
||||
@ -4130,8 +4097,8 @@ const choujianEchartsPinfa = () => {
|
||||
|
||||
const zhifaEchartsPinfa = () => {
|
||||
// 销毁已有实例,防止重复渲染
|
||||
if (main8.value && echarts.getInstanceByDom(main8.value)) {
|
||||
echarts.getInstanceByDom(main8.value).dispose();
|
||||
if (main8.value && echarts.getInstanceByDom(main8.value as HTMLElement)) {
|
||||
echarts.getInstanceByDom(main8.value as HTMLElement)?.dispose();
|
||||
}
|
||||
var myChart = echarts.init(main8.value);
|
||||
const months = ["1月", "2月", "3月", "4月", "5月"];
|
||||
@ -4195,14 +4162,13 @@ const zhifaEchartsPinfa = () => {
|
||||
// },
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: function (params) {
|
||||
formatter: function (params: any[]) {
|
||||
let ymonth = "";
|
||||
let result = '';
|
||||
const dataMap = {};
|
||||
const dataMap: Record<string, { value: number | null; prediction: number | null }> = {};
|
||||
|
||||
// 合并实线和虚线数据
|
||||
params.forEach(item => {
|
||||
// console.log(item);
|
||||
params.forEach((item: any) => {
|
||||
const isPrediction = item.seriesName.includes('预测');
|
||||
const baseName = isPrediction ? item.seriesName.replace('预测', '') : item.seriesName;
|
||||
|
||||
@ -4211,22 +4177,20 @@ const zhifaEchartsPinfa = () => {
|
||||
}
|
||||
|
||||
if (isPrediction) {
|
||||
dataMap[baseName].prediction = item.value;
|
||||
dataMap[baseName].prediction = item.value as number | null;
|
||||
} else {
|
||||
dataMap[baseName].value = item.value;
|
||||
dataMap[baseName].value = item.value as number | null;
|
||||
}
|
||||
|
||||
ymonth = item.name;
|
||||
// console.log(ymonth);
|
||||
});
|
||||
|
||||
// 构建tooltip内容
|
||||
Object.keys(dataMap).forEach(name => {
|
||||
Object.keys(dataMap).forEach((name: string) => {
|
||||
const item = dataMap[name];
|
||||
if (ymonth == "5月") {
|
||||
result += `${name}: (预测: ${item.prediction}%)`;
|
||||
} else {
|
||||
result += `${name}: ${item.value || '0'}%`;
|
||||
result += `${name}: ${item.value ?? 0}%`;
|
||||
}
|
||||
result += '<br/>';
|
||||
});
|
||||
@ -4239,10 +4203,10 @@ const zhifaEchartsPinfa = () => {
|
||||
top: 30,
|
||||
textStyle: { color: "#fff" },
|
||||
// 只显示主线legend
|
||||
selected: legendData.reduce((acc, cur) => {
|
||||
selected: legendData.reduce((acc: Record<string, boolean>, cur: string) => {
|
||||
acc[cur] = true;
|
||||
return acc;
|
||||
}, {}),
|
||||
}, {} as Record<string, boolean>),
|
||||
},
|
||||
grid: { left: 45, right: 30, top: 63, bottom: 45 },
|
||||
xAxis: {
|
||||
@ -4320,6 +4284,7 @@ const jubaoPinfaData = ref([
|
||||
]);
|
||||
|
||||
const highlightGraphNodeByName = (nodeName: string) => {
|
||||
if (!chartRelationship) return;
|
||||
// 先取消所有高亮
|
||||
chartRelationship.dispatchAction({
|
||||
type: "downplay",
|
||||
@ -4351,8 +4316,8 @@ const handleRowClick = (item: any, index: number) => {
|
||||
const fancyBtn = ref(null)
|
||||
const ripple = ref(null)
|
||||
const handleFancyClick = (e: MouseEvent) => {
|
||||
const btn = fancyBtn.value as HTMLElement
|
||||
const span = ripple.value as HTMLElement
|
||||
const btn = fancyBtn.value as unknown as HTMLElement
|
||||
const span = ripple.value as unknown as HTMLElement
|
||||
if (!btn || !span) return
|
||||
const rect = btn.getBoundingClientRect()
|
||||
const size = Math.max(rect.width, rect.height)
|
||||
@ -4589,4 +4554,70 @@ const handleFancyClick = (e: MouseEvent) => {
|
||||
transform: scale(0) !important;
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.fancy-border {
|
||||
position: relative;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
backdrop-filter: blur(4px);
|
||||
box-shadow:
|
||||
0 8px 24px rgba(0, 0, 0, 0.35),
|
||||
inset 0 0 20px rgba(34, 211, 238, 0.15);
|
||||
}
|
||||
|
||||
.fancy-border::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: -1px;
|
||||
border-radius: inherit;
|
||||
padding: 1px;
|
||||
background: linear-gradient(90deg,
|
||||
rgba(34, 211, 238, 0.6),
|
||||
rgba(59, 130, 246, 0.6),
|
||||
rgba(168, 85, 247, 0.6));
|
||||
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.fancy-border:hover {
|
||||
box-shadow:
|
||||
0 10px 28px rgba(0, 0, 0, 0.45),
|
||||
inset 0 0 26px rgba(34, 211, 238, 0.25);
|
||||
transition: box-shadow 0.25s ease;
|
||||
}
|
||||
|
||||
/*
|
||||
fancy-border 相关 CSS 解释:
|
||||
|
||||
1. .fancy-border
|
||||
- position: relative; // 设为相对定位,为伪元素定位提供参考
|
||||
- border-radius: 12px; // 圆角边框
|
||||
- border: 1px solid rgba(255, 255, 255, 0.15); // 半透明白色边框
|
||||
- background: rgba(255, 255, 255, 0.04); // 非常浅的白色背景,几乎透明
|
||||
- backdrop-filter: blur(4px); // 背景模糊效果,提升玻璃拟态质感
|
||||
- box-shadow:
|
||||
0 8px 24px rgba(0, 0, 0, 0.35), // 外部阴影,增加立体感
|
||||
inset 0 0 20px rgba(34, 211, 238, 0.15); // 内部青色阴影,增加层次感
|
||||
|
||||
2. .fancy-border::before
|
||||
- content: ""; // 生成一个空内容的伪元素
|
||||
- position: absolute; // 绝对定位,覆盖在父元素上
|
||||
- inset: -1px; // 四周扩展1px,确保边框完整
|
||||
- border-radius: inherit; // 继承父元素圆角
|
||||
- padding: 1px; // 内边距1px
|
||||
- background: linear-gradient(90deg, ...); // 渐变色边框,青-蓝-紫
|
||||
- -webkit-mask 与 mask-composite: // 利用遮罩实现只有边框区域显示渐变色,内容区透明
|
||||
- pointer-events: none; // 伪元素不响应鼠标事件
|
||||
|
||||
3. .fancy-border:hover
|
||||
- box-shadow:
|
||||
0 10px 28px rgba(0, 0, 0, 0.45), // 悬浮时外部阴影更深
|
||||
inset 0 0 26px rgba(34, 211, 238, 0.25); // 内部青色阴影更明显
|
||||
- transition: box-shadow 0.25s ease; // 阴影变化有过渡动画
|
||||
|
||||
整体效果:实现了一个带有渐变炫彩边框、玻璃拟态背景、悬浮高亮的美观卡片样式。
|
||||
*/
|
||||
</style>
|
||||
|
@ -6,6 +6,8 @@ export default defineConfig({
|
||||
plugins: [vue()],
|
||||
server: {
|
||||
//host: '0.0.0.0'
|
||||
allowedHosts: ['294a8d70.r23.cpolar.top']
|
||||
|
||||
},
|
||||
})
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user