右侧模块增加

This commit is contained in:
王兴凯 2026-05-12 14:34:58 +08:00
parent 48262cc162
commit 67f022d156
5 changed files with 976 additions and 10 deletions

View File

@ -0,0 +1,286 @@
<!-- SidePanelItem.vue -->
<template>
<SidePanelItem title="植物园情况介绍">
<div class="container" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
<!-- 跑马灯轨道容器 -->
<div class="carousel-track" :class="{ 'no-transition': isTransitioning }"
:style="{ transform: `translateX(-${currentIndex * 100}%)` }">
<!-- 遍历所有媒体项包含克隆项 -->
<div v-for="(item, index) in renderMediaData" :key="index" class="carousel-item">
<!-- 图片 -->
<img :src="item.url" alt="" />
<!-- 说明文字随媒体项移动 -->
<div class="text">{{ item.text }}</div>
</div>
</div>
<!-- 面板指示器固定在底部右侧 -->
<div class="pagination-dots-fixed">
<span
v-for="(dot, index) in originalMediaData"
:key="index"
class="dot"
:class="{ active: getCurrentRealIndex() === index }"
@click="goToSlide(index)"
></span>
</div>
</div>
<!-- 独立的文字说明区域随跑马灯切换而变化 -->
<div class="description-text">
{{ currentDescription }}
</div>
</SidePanelItem>
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted, computed } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
// 便
defineOptions({
name: 'zengZhiZhanJieShaoMod'
});
//
interface MediaItem {
type: 'image' | 'video';
url: string;
text: string;
description: string;
}
// 3
const originalMediaData = ref<MediaItem[]>([
{
type: 'image',
url: 'https://211.99.26.225:12125/?20230814205611342377136845462200&view=jpg&token=bearer c2e76c28-14db-4a0f-9ff2-10cc3f835920',
text: '松岗鱼类增殖站',
description: '松岗鱼类增殖放流站位于四川省阿坝藏族羌族自治州马尔康市松岗镇,主要服务于大渡河上游的双江口和金川两座水电站,同时还承担多种珍稀特有鱼类的救护和科研任务,实现工程建设与生态环境共同推进、相互促进。'
},
{
type: 'video',
url: 'https://211.99.26.225:12125/?20230805205848575430105387253710&view=jpg&token=bearer c2e76c28-14db-4a0f-9ff2-10cc3f835920', // URL
text: '猴子岩鱼类增殖站',
description: '猴子岩水电站鱼类增殖放流站位于猴子岩水电站坝址下游约7.0km(业主营地下游约1.5km)大渡河左岸桃花渣场顶部平台上紧邻枢纽桃花大桥下游侧占地面积47.3亩其中一期工程27.0亩预留二期工程用地20.3亩(二期工程目前为丹巴、巴底水电站预留工程)增殖放流站工作流程为:亲鱼收集购买、亲鱼驯养培育、人工催产和授精、人工孵化、苗种培育和放流。 猴子岩鱼类增殖放流站近期放流对象中齐口裂腹鱼、重口裂腹鱼、大渡软刺裸裂尻鱼增殖放流技术水平已趋于熟化,中期放流对象大渡软刺裸裂尻鱼人工繁殖技术逐渐趋于熟化'
},
{
type: 'image',
url: 'https://211.99.26.225:12125/?20230805205924378504010675106305&view=jpg&token=bearer c2e76c28-14db-4a0f-9ff2-10cc3f835920',
text: '黑马鱼类增殖站',
description: '大渡河黑马鱼类增殖放流站位于四川省甘洛县黑马乡黑马业主营地内距离甘洛县城45km,区域交通路况较好。主要承担瀑布沟、深溪沟、大岗山、枕头坝一级、沙坪二级等五座水电站鱼类增殖放流的重任。放流鱼类包含:齐口裂腹鱼、重口裂腹鱼、鲈鲤、长薄鳅、白甲鱼、中华倒刺、长吻脆、稀有鮊鲫、华鲮、侧沟爬岩鳅等10个种类共计约918.07万尾珍稀特有鱼苗。'
}
]);
//
// [, ..., ]
const renderMediaData = ref<MediaItem[]>([]);
// renderMediaData
const currentIndex = ref(1); // 1
//
let timer: any = null;
//
const isHovering = ref(false);
// transition
const isTransitioning = ref(false);
//
const initRenderData = () => {
const length = originalMediaData.value.length;
if (length === 0) return;
renderMediaData.value = [
originalMediaData.value[length - 1], //
...originalMediaData.value, //
originalMediaData.value[0] //
];
};
//
const startAutoPlay = () => {
if (timer) clearInterval(timer);
timer = setInterval(() => {
if (!isHovering.value && !isTransitioning.value) {
nextSlide();
}
}, 4000);
};
//
const nextSlide = () => {
currentIndex.value++;
//
setTimeout(() => {
checkSeamlessJump();
}, 500); // transition
};
//
const checkSeamlessJump = () => {
const realLength = originalMediaData.value.length;
// = realLength + 1
if (currentIndex.value >= realLength + 1) {
// 1.
isTransitioning.value = true;
// 2. 1
currentIndex.value = 1;
// 3. DOM
requestAnimationFrame(() => {
requestAnimationFrame(() => {
isTransitioning.value = false;
});
});
}
};
//
const handleMouseEnter = () => {
isHovering.value = true;
};
//
const handleMouseLeave = () => {
isHovering.value = false;
};
//
const currentDescription = computed(() => {
const realIndex = getCurrentRealIndex();
return originalMediaData.value[realIndex]?.description || '';
});
//
onMounted(() => {
initRenderData();
startAutoPlay();
});
//
onUnmounted(() => {
if (timer) clearInterval(timer);
});
//
const getCurrentRealIndex = () => {
const realLength = originalMediaData.value.length;
let realIndex = currentIndex.value - 1; //
//
if (realIndex < 0) realIndex = realLength - 1;
if (realIndex >= realLength) realIndex = 0;
return realIndex;
};
//
const goToSlide = (targetIndex: number) => {
if (isTransitioning.value) return;
//
currentIndex.value = targetIndex + 1;
};
</script>
<style lang="scss" scoped>
.container {
width: 100%;
height: 228px;
// border: 1px solid #7fd6ff;
// border-radius: 5px;
position: relative;
overflow: hidden; //
//
.carousel-track {
display: flex; //
width: 100%;
height: 100%;
transition: transform 0.5s ease-in-out; // 0.5
//
&.no-transition {
transition: none;
}
//
.carousel-item {
min-width: 100%; //
height: 100%;
position: relative;
flex-shrink: 0; //
img,
video {
width: 100%;
height: 100%;
object-fit: cover; //
}
.text {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 22px;
line-height: 22px;
background: rgba(0, 0, 0, 0.1);
color: #fff;
padding-left: 10px;
}
}
}
//
.pagination-dots-fixed {
position: absolute;
bottom: 10px;
right: 10px;
display: flex;
gap: 6px;
z-index: 10; //
.dot {
width: 5px;
height: 5px;
border-radius: 50%;
background-color: #D8D8D8;
cursor: pointer;
transition: background-color 0.3s ease;
&.active {
background-color: #005293;
}
&:hover {
opacity: 0.8;
}
}
}
}
//
.description-text {
// padding: 8px 12px;
font-size: 14px;
line-height: 1.5;
// min-height: 40px;
transition: all 0.3s ease;
margin-bottom: 20px;
//
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-word;
}
</style>

View File

@ -0,0 +1,203 @@
<!-- SidePanelItem.vue -->
<template>
<div>
<SidePanelItem title="生态流量限值沿程变化" :select="select" :datetimePicker="datetimePicker" >
<!-- 图表容器 -->
<div ref="chartRef" style="width: 100%; height: 400px;"></div>
</SidePanelItem>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, computed, watch, onBeforeUnmount } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
import * as echarts from 'echarts';
import type { EChartsOption } from 'echarts';
//
defineOptions({
name: 'xieFangFenBu'
});
const select = ref({
show: true,
value: undefined,
options: [
]
});
const datetimePicker = ref({
show: true,
value: undefined,
format: 'YYYY-MM', //YYYY-MM-DD HH
picker: 'month' //date | week | month | quarter | year
});
//
const chartData = ref([
{ stnm: '站点A001', qecLimit: 120.5 },
{ stnm: '站点B002', qecLimit: 135.8 },
{ stnm: '站点C003', qecLimit: 98.3 },
{ stnm: '站点D004', qecLimit: 142.6 },
{ stnm: '站点E005', qecLimit: 115.2 },
{ stnm: '站点F006', qecLimit: 128.9 },
{ stnm: '站点G007', qecLimit: 105.4 },
{ stnm: '站点H008', qecLimit: 138.7 },
{ stnm: '站点I009', qecLimit: 122.1 },
{ stnm: '站点J010', qecLimit: 145.3 },
{ stnm: '站点K011', qecLimit: 110.6 },
{ stnm: '站点L012', qecLimit: 132.4 },
{ stnm: '站点M013', qecLimit: 118.9 },
{ stnm: '站点N014', qecLimit: 140.2 },
{ stnm: '站点O015', qecLimit: 125.7 }
]);
//
const flowUnit = ref('m³/s');
//
const generateModerateColor = () => {
const hue = Math.floor(Math.random() * 360);
const saturation = 50 + Math.floor(Math.random() * 30); // 50-80%
const lightness = 45 + Math.floor(Math.random() * 20); // 45-65%
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
};
//
const chartOption = computed<EChartsOption>(() => {
const dataLength = chartData.value.length;
return {
legend: {
data: ['生态流量限值'],
center: true,
icon: 'rect',
itemHeight: 3
},
grid: {
top: 40,
left: 40,
right: 20,
bottom: 60
},
tooltip: {
trigger: 'axis',
confine: true,
formatter: function (params: any) {
if (!params || params.length === 0) return '';
const value = params[0].value ?? '-';
return `<h3 style="color:#FFF">${params[0].name}</h3>
<div>${params[0].marker}生态流量限值: &nbsp;&nbsp;&nbsp;&nbsp;<span style="float:right">${value} ${flowUnit.value}</span></div>`;
},
axisPointer: {
type: 'line'
}
},
xAxis: {
type: 'category',
data: chartData.value.map((item: any) => item.stnm),
axisLabel: {
interval: dataLength > 12 ? 2 : 0,
rotate: 0,
formatter: (value: string, index: number) => {
const displayText = value.substring(0, 6) + (value.length > 6 ? '...' : '');
if (dataLength === 2) {
return `{a|${displayText}}`;
} else if (index % 2 !== 0) {
//
return `{a|${displayText}}`;
} else {
//
return '\n{b|}' + `{b|${displayText}}`;
}
},
rich: {
a: {
height: 20,
align: 'center'
},
b: {
height: 30,
align: 'center'
}
}
},
axisTick: {
show: false
}
},
yAxis: [{
type: 'value',
name: `流量(${flowUnit.value})`
}],
dataZoom: [
{
type: 'inside',
show: false
},
{
type: 'slider',
show: false
}
],
series: [
{
name: '生态流量限值',
type: 'line',
data: chartData.value.map((item: any) => item.qecLimit),
smooth: false,
showSymbol: true,
symbolSize: 6
}
],
color: [generateModerateColor()]
};
});
//
let chartInstance: echarts.ECharts | null = null;
const chartRef = ref<HTMLDivElement>();
//
const initChart = () => {
if (!chartRef.value) {
console.warn('图表容器未找到');
return;
}
console.log('开始初始化图表...');
chartInstance = echarts.init(chartRef.value);
chartInstance.setOption(chartOption.value);
console.log('图表初始化完成');
//
window.addEventListener('resize', handleResize);
};
//
const handleResize = () => {
chartInstance?.resize();
};
//
watch(chartOption, (newOption) => {
if (chartInstance) {
chartInstance.setOption(newOption, true);
}
});
onMounted(() => {
initChart();
});
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize);
chartInstance?.dispose();
chartInstance = null;
});
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,479 @@
<!-- SidePanelItem.vue -->
<template>
<SidePanelItem title="沿程水质变化" :datetimePicker="datetimePicker">
<div class="chart-container" ref="chartRef"></div>
</SidePanelItem>
</template>
<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue';
import * as echarts from 'echarts';
import type { EChartsOption } from 'echarts';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
// 便
defineOptions({
name: 'waterQuality'
});
// ==================== ====================
const chartRef = ref<HTMLElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
// 8:00
const now = new Date();
const todayAtEightAM = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 8, 0, 0);
const defaultValue = `${todayAtEightAM.getFullYear()}-${String(todayAtEightAM.getMonth() + 1).padStart(2, '0')}-${String(todayAtEightAM.getDate()).padStart(2, '0')} ${String(todayAtEightAM.getHours()).padStart(2, '0')}:${String(todayAtEightAM.getMinutes()).padStart(2, '0')}`;
const datetimePicker = ref({
show: true,
value: defaultValue,
format: 'YYYY-MM-DD hh:mm',
picker: 'date',
options: []
});
// ==================== 2====================
const visibleSeriesQueue = ref<string[]>([]);
// ==================== ====================
const generateMockData = () => {
const stations = [
{ stnm: '两河口', stcd: 'ST001', type: '0' },
{ stnm: '锦屏一级', stcd: 'ST002', type: '1' },
{ stnm: '桐子林', stcd: 'ST003', type: '0' },
{ stnm: '溪洛渡', stcd: 'ST004', type: '0' },
{ stnm: '向家坝', stcd: 'ST005', type: '1' },
{ stnm: '三峡', stcd: 'ST006', type: '0' },
{ stnm: '葛洲坝', stcd: 'ST007', type: '0' }
];
const tm = '2024-01-15 08:00:00';
return stations.map((station, index) => ({
...station,
tm,
SORT: index + 1,
ph: 7.2 + Math.random() * 0.8,
dox: 6.5 + Math.random() * 2.5,
codmn: 1.5 + Math.random() * 2.0,
nh3n: 0.15 + Math.random() * 0.35,
tp: 0.05 + Math.random() * 0.15,
tn: 0.8 + Math.random() * 1.2
}));
};
const mockData = ref(generateMockData());
// ==================== ====================
const indicatorConfig = [
{ key: 'ph', name: 'pH', unit: '', color: '#5470C6' },
{ key: 'dox', name: '溶解氧', unit: 'mg/L', color: '#91CC75' },
{ key: 'codmn', name: '高锰酸盐指数', unit: 'mg/L', color: '#FAC858' },
{ key: 'nh3n', name: '氨氮', unit: 'mg/L', color: '#EE6666' },
{ key: 'tp', name: '总磷', unit: 'mg/L', color: '#73C0DE' },
{ key: 'tn', name: '总氮', unit: 'mg/L', color: '#3BA272' }
];
// ==================== ====================
const getChartOption = (): EChartsOption => {
const data = mockData.value;
if (!data || data.length === 0) {
return {};
}
// X
const xData = data.map((item, index) => ({
value: item.stnm,
textStyle: {
padding: index % 2 !== 0 ? [16, 0, 0, 0] : 0
}
}));
// 线
const markLineData: any[] = [];
data.forEach((item, index) => {
if (item.type === '1') {
markLineData.push({ xAxis: index });
}
});
//
const legendData = indicatorConfig.map(item => item.name);
//
const selectedState: Record<string, boolean> = {};
indicatorConfig.forEach(config => {
selectedState[config.name] = visibleSeriesQueue.value.includes(config.name);
});
// Series
const seriesData = indicatorConfig.map((config, index) => {
const _key = config.key === 'dox' ? 'do' : config.key;
return {
name: config.name,
type: 'line' as const,
yAxisIndex: index,
smooth: true,
connectNulls: true,
symbol: 'circle' as const,
symbolSize: 6,
itemStyle: {
color: config.color
},
data: data.map(item => {
const value = item[config.key as keyof typeof item];
return typeof value === 'number' && !isNaN(value) ? value : null;
}),
markLine: index === 0 ? {
symbol: ['none', 'none'],
label: { show: false },
lineStyle: {
color: '#ccc',
type: 'dashed' as const
},
data: markLineData
} : undefined
};
});
// Y1N
const yAxisData = indicatorConfig.map((config, index) => {
const isLeft = index === 0;
const offset = index < 2 ? 0 : (index - 1) * 60;
return {
type: 'value' as const,
name: config.name,
position: isLeft ? ('left' as const) : ('right' as const),
offset,
axisLine: {
show: true,
lineStyle: {
color: config.color
}
},
axisLabel: {
color: config.color,
formatter: (value: number) => {
const decimalCount = (value.toString().split('.')[1] || '').length;
return decimalCount >= 2 ? value.toFixed(1) : value;
}
},
splitLine: {
show: true,
lineStyle: {
color: '#e0e0e0',
type: 'solid' as const
}
},
show: selectedState[config.name]
};
});
const option: EChartsOption = {
tooltip: {
trigger: 'axis',
confine: true,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
borderColor: 'transparent',
textStyle: {
color: '#ffffff'
},
formatter: (params: any) => {
if (!params || params.length === 0) return '';
const tm = data.find(item => item.stnm === params[0].name)?.tm;
let result = tm ? `${new Date(tm).toLocaleString('zh-CN')}<br/>` : '';
result += `${params[0].name}<br/>`;
params.forEach((param: any) => {
const config = indicatorConfig.find(c => c.name === param.seriesName);
const unit = config?.unit || '';
if (param.value !== null && param.value !== undefined) {
//
const numValue = Number(param.value);
let displayValue = param.value;
// 2
if (!isNaN(numValue)) {
const decimalPart = param.value.toString().split('.')[1];
if (decimalPart && decimalPart.length > 2) {
displayValue = numValue.toFixed(2);
}
}
result += `${param.marker}${param.seriesName}${displayValue}${unit}<br/>`;
}
});
return result;
}
},
legend: {
type: 'scroll',
top: 0,
data: legendData,
selected: selectedState,
inactiveColor: '#ccc',
itemWidth: 16,
itemHeight: 12,
itemGap: 8,
textStyle: {
fontSize: 14
}
},
grid: {
top: 60,
bottom: 50,
left: '20px',
right: '20px',
containLabel: true
},
xAxis: {
type: 'category',
data: xData,
axisLabel: {
interval: 0,
color: '#333',
fontSize: 12
},
axisLine: {
lineStyle: {
color: '#8f8f8f'
}
},
splitLine: {
show: true,
lineStyle: {
color: '#e0e0e0',
type: 'solid' as const
}
}
},
yAxis: yAxisData,
series: seriesData
};
return option;
};
// ==================== 2====================
const handleLegendSelectChanged = (params: any) => {
if (!chartInstance) return;
const { selected, name } = params;
const clickedName = name;
const isNowSelected = selected[clickedName];
console.log(`图例点击: ${clickedName}, 当前状态: ${isNowSelected ? '显示' : '隐藏'}`);
console.log('当前可见队列:', visibleSeriesQueue.value);
if (isNowSelected) {
//
if (visibleSeriesQueue.value.length >= 2) {
// 2
const removed = visibleSeriesQueue.value.shift();
console.log(`已达上限,移除最早系列: ${removed}`);
}
//
if (!visibleSeriesQueue.value.includes(clickedName)) {
visibleSeriesQueue.value.push(clickedName);
}
} else {
//
const index = visibleSeriesQueue.value.indexOf(clickedName);
if (index > -1) {
visibleSeriesQueue.value.splice(index, 1);
console.log(`从队列中移除: ${clickedName}`);
}
}
console.log('更新后可见队列:', visibleSeriesQueue.value);
// selected
const finalSelected: Record<string, boolean> = {};
indicatorConfig.forEach(config => {
finalSelected[config.name] = visibleSeriesQueue.value.includes(config.name);
});
//
const currentOption = JSON.parse(JSON.stringify(chartInstance.getOption()));
//
currentOption.legend[0].selected = finalSelected;
// Y
const newYAxis = currentOption.yAxis.map((item: any) => {
let isShow = false;
for (const key in finalSelected) {
if (key === item.name) {
isShow = finalSelected[key];
break;
}
}
return { ...item, show: isShow };
});
currentOption.yAxis = newYAxis;
// Y
yAxisShowDynamic(finalSelected, currentOption);
//
try {
chartInstance.setOption(currentOption, true);
console.log('图表配置已更新');
} catch (error) {
console.error('图表更新失败:', error);
}
};
// ==================== Y ====================
const yAxisShowDynamic = (selected: Record<string, boolean>, options: any) => {
const allShow = options.yAxis?.filter((item: any) => item.show);
const showCount = allShow?.length || 0;
// Y
if (showCount === 0) {
return;
}
// Y
if (showCount === 1) {
delete options.grid.right;
options.grid.left = '80px';
options.yAxis = options.yAxis.map((item: any) => {
if (item.show) {
return {
...item,
position: 'left',
offset: 0
};
}
return item;
});
return;
}
// Y1
if (showCount >= 2) {
let leftIndex = 0;
let rightIndex = 0;
options.yAxis = options.yAxis.map((item: any) => {
if (!item.show) {
return item;
}
// Y
if (leftIndex === 0) {
leftIndex++;
delete options.grid.right;
options.grid.left = '80px';
return {
...item,
position: 'left',
offset: 0
};
} else {
// Y
rightIndex++;
if (rightIndex > 1) {
options.grid.right = '100px';
return {
...item,
position: 'right',
offset: 60
};
} else {
options.grid.right = '60px';
return {
...item,
position: 'right',
offset: 0
};
}
}
});
}
};
// ==================== ====================
const initChart = async () => {
if (!chartRef.value) {
console.warn('图表容器未就绪');
return;
}
//
const rect = chartRef.value.getBoundingClientRect();
if (rect.width === 0 || rect.height === 0) {
console.warn('图表容器尺寸为0等待渲染...');
await new Promise(resolve => setTimeout(resolve, 50));
return initChart();
}
//
visibleSeriesQueue.value = [indicatorConfig[0].name];
console.log('初始化可见队列:', visibleSeriesQueue.value);
// ECharts
chartInstance = echarts.init(chartRef.value);
//
const option = getChartOption();
chartInstance.setOption(option);
//
chartInstance.on('legendselectchanged', handleLegendSelectChanged);
// resize
setTimeout(() => {
chartInstance?.resize();
}, 50);
console.log('图表初始化成功');
};
// ==================== ====================
const handleResize = () => {
chartInstance?.resize();
};
// ==================== ====================
onMounted(async () => {
await nextTick();
//
setTimeout(() => {
initChart();
}, 50);
window.addEventListener('resize', handleResize);
});
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize);
if (chartInstance) {
chartInstance.off('legendselectchanged', handleLegendSelectChanged);
chartInstance.dispose();
chartInstance = null;
}
});
</script>
<style lang="scss" scoped>
.chart-container {
width: 100%;
height: 280px;
min-height: 231px;
}
</style>

View File

@ -16,17 +16,17 @@ function normalizeRoutes(routes: any[]): any[] {
return routes.map(route => { return routes.map(route => {
// 创建副本以避免直接修改原始数据(可选,视具体需求而定) // 创建副本以避免直接修改原始数据(可选,视具体需求而定)
const normalizedRoute = { ...route }; const normalizedRoute = { ...route };
// 修正当前路由的 path // 修正当前路由的 path
if (normalizedRoute.path && !normalizedRoute.path.startsWith('/')) { if (normalizedRoute.path && !normalizedRoute.path.startsWith('/')) {
normalizedRoute.path = `/${normalizedRoute.path}`; normalizedRoute.path = `/${normalizedRoute.path}`;
} }
// 递归修正子路由 // 递归修正子路由
if (normalizedRoute.children && normalizedRoute.children.length > 0) { if (normalizedRoute.children && normalizedRoute.children.length > 0) {
normalizedRoute.children = normalizeRoutes(normalizedRoute.children); normalizedRoute.children = normalizeRoutes(normalizedRoute.children);
} }
return normalizedRoute; return normalizedRoute;
}); });
} }
@ -55,8 +55,6 @@ router.beforeEach(async (to, from, next) => {
if (userStore.Token) { if (userStore.Token) {
// 登录成功,跳转到首页 // 登录成功,跳转到首页
if (to.path === '/login') {
//login
if (to.path === '/login') { if (to.path === '/login') {
//login //login
next({ path: '/' }); next({ path: '/' });
@ -84,10 +82,12 @@ router.beforeEach(async (to, from, next) => {
const { roles } = await userStore.getInfo(); const { roles } = await userStore.getInfo();
let accessRoutes: RouteRecordRaw[] = let accessRoutes: RouteRecordRaw[] =
await permissionStore.generateRoutes(roles); await permissionStore.generateRoutes(roles);
// ✅ 关键修复:在添加路由前,标准化所有路径 // ✅ 关键修复:在添加路由前,标准化所有路径
accessRoutes = normalizeRoutes(accessRoutes); accessRoutes = normalizeRoutes(accessRoutes);
console.log('Normalized Access Routes:', accessRoutes);
accessRoutes.forEach((route: any) => { accessRoutes.forEach((route: any) => {
console.log('Adding Route:', route.path); console.log('Adding Route:', route.path);
router.addRoute(route); router.addRoute(route);
@ -125,4 +125,4 @@ router.beforeEach(async (to, from, next) => {
router.afterEach(() => { router.afterEach(() => {
NProgress.done(); NProgress.done();
}); });

View File

@ -29,14 +29,12 @@ const showMapModal = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "ENG"; modelStore.params.sttp = "ENG";
modelStore.title = "三峡 详情信息"; modelStore.title = "三峡 详情信息";
modelStore.currentTabKey = "basicInfo";
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
const showMapModal1 = () => { const showMapModal1 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "zh"; modelStore.params.sttp = "zh";
modelStore.title = "三峡222 详情信息"; modelStore.title = "水质 详情信息";
modelStore.currentTabKey = "basicInfo";
modelStore.isBasicEdit = false; modelStore.isBasicEdit = false;
// modelStore.modalVisible = true; // modelStore.modalVisible = true;
// modelStore.params.sttp = "zh"; // modelStore.params.sttp = "zh";