fix: 后台接口对接,问题修复及线上提交测试。
This commit is contained in:
388
src/components/other/chartFullscreen.vue
Normal file
388
src/components/other/chartFullscreen.vue
Normal file
@@ -0,0 +1,388 @@
|
||||
<template>
|
||||
<view class="chart-fullscreen-page">
|
||||
<!-- 顶部标题栏 -->
|
||||
<view class="header">
|
||||
<view class="back-btn" @click="goBack">
|
||||
<text class="icon">←</text>
|
||||
</view>
|
||||
<view class="title">{{ chartTitle }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 时间选择 -->
|
||||
<view class="time-selector">
|
||||
<view
|
||||
class="time-item"
|
||||
:class="{ active: dayType === 1 }"
|
||||
@click="changeDay(1)"
|
||||
>
|
||||
1天
|
||||
</view>
|
||||
<view
|
||||
class="time-item"
|
||||
:class="{ active: dayType === 3 }"
|
||||
@click="changeDay(3)"
|
||||
>
|
||||
3天
|
||||
</view>
|
||||
<view
|
||||
class="time-item"
|
||||
:class="{ active: dayType === 7 }"
|
||||
@click="changeDay(7)"
|
||||
>
|
||||
7天
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 图表容器 -->
|
||||
<view class="chart-container">
|
||||
<canvas
|
||||
class="chart-canvas"
|
||||
canvas-id="fullscreen-chart"
|
||||
id="fullscreen-chart"
|
||||
></canvas>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { deviceHistory } from '@/api/device';
|
||||
import { formatDateMin } from '@/utils/tools';
|
||||
import uCharts from '@/utils/js-sdk/u-charts/u-charts.js';
|
||||
|
||||
const dayType = ref(1);
|
||||
const chartTitle = ref('溶解氧曲线图');
|
||||
const chartData = ref<any[]>([]);
|
||||
let chartInstance: any = null;
|
||||
|
||||
// 接收的参数
|
||||
const serialNum = ref('');
|
||||
const dataType = ref(1); // 1-溶解氧, 2-水温, 3-饱和度, 4-PH, 5-盐度
|
||||
|
||||
onMounted(() => {
|
||||
// 获取页面参数
|
||||
const instance = Taro.getCurrentInstance();
|
||||
const params = instance.router?.params || {};
|
||||
|
||||
serialNum.value = params.serialNum || '';
|
||||
dataType.value = Number(params.dataType) || 1;
|
||||
dayType.value = Number(params.dayType) || 1;
|
||||
|
||||
// 设置标题
|
||||
const titles = ['', '溶解氧曲线图', '水温曲线图', '饱和度曲线图', 'PH曲线图', '盐度曲线图'];
|
||||
chartTitle.value = titles[dataType.value] || '曲线图';
|
||||
|
||||
// 初始化图表
|
||||
setTimeout(() => {
|
||||
initChart();
|
||||
}, 500);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (chartInstance) {
|
||||
chartInstance = null;
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化图表
|
||||
function initChart() {
|
||||
// 横屏后的尺寸计算:
|
||||
// 页面宽度 = 屏幕高度(100vh)
|
||||
// 页面高度 = 屏幕宽度(100vw)
|
||||
// header(50px) + time-selector(50px) = 100px
|
||||
|
||||
const screenWidth = window.innerWidth; // 屏幕宽度
|
||||
const screenHeight = window.innerHeight; // 屏幕高度
|
||||
|
||||
// 横屏后:
|
||||
const cWidth = screenHeight - 40; // 页面宽度(100vh) - padding
|
||||
const cHeight = screenWidth - 120; // 页面高度(100vw) - header - time-selector - padding
|
||||
|
||||
console.log('📊 横屏图表尺寸计算:', {
|
||||
屏幕宽: screenWidth,
|
||||
屏幕高: screenHeight,
|
||||
图表宽: cWidth,
|
||||
图表高: cHeight
|
||||
});
|
||||
|
||||
// 加载数据
|
||||
loadChartData(cWidth, cHeight, 1);
|
||||
}
|
||||
|
||||
// 返回上一页
|
||||
function goBack() {
|
||||
Taro.navigateBack();
|
||||
}
|
||||
|
||||
// 返回首页
|
||||
function goHome() {
|
||||
Taro.switchTab({
|
||||
url: '/pages/main/home'
|
||||
});
|
||||
}
|
||||
|
||||
// 切换天数
|
||||
function changeDay(day: number) {
|
||||
dayType.value = day;
|
||||
|
||||
// 重新计算尺寸
|
||||
const screenWidth = window.innerWidth;
|
||||
const screenHeight = window.innerHeight;
|
||||
const cWidth = screenHeight - 40;
|
||||
const cHeight = screenWidth - 120;
|
||||
|
||||
loadChartData(cWidth, cHeight, 1);
|
||||
}
|
||||
|
||||
// 加载图表数据
|
||||
function loadChartData(cWidth: number, cHeight: number, pixelRatio: number) {
|
||||
if (!serialNum.value) return;
|
||||
|
||||
const now = new Date();
|
||||
const start = new Date(now.getTime() - dayType.value * 24 * 60 * 60 * 1000);
|
||||
|
||||
const params = {
|
||||
serialNum: serialNum.value,
|
||||
startTime: formatDateMin(start),
|
||||
endTime: formatDateMin(now),
|
||||
intervalType: dayType.value === 1 ? 1 : dayType.value === 3 ? 2 : 3,
|
||||
};
|
||||
|
||||
Taro.showLoading({ title: '加载中...' });
|
||||
|
||||
deviceHistory(params).then((res: any) => {
|
||||
Taro.hideLoading();
|
||||
|
||||
if (Array.isArray(res)) {
|
||||
chartData.value = res;
|
||||
} else if (res.code == 200) {
|
||||
chartData.value = res.data || [];
|
||||
}
|
||||
|
||||
// 绘制图表
|
||||
drawChart(cWidth, cHeight, pixelRatio);
|
||||
}).catch(() => {
|
||||
Taro.hideLoading();
|
||||
});
|
||||
}
|
||||
|
||||
// 绘制图表
|
||||
function drawChart(cWidth: number, cHeight: number, pixelRatio: number) {
|
||||
if (!chartData.value || chartData.value.length === 0) {
|
||||
console.log('❌ 数据为空');
|
||||
return;
|
||||
}
|
||||
|
||||
const fieldMap: any = {
|
||||
1: 'dissolvedOxygen',
|
||||
2: 'temperature',
|
||||
3: 'saturability',
|
||||
4: 'ph',
|
||||
5: 'salinity',
|
||||
};
|
||||
|
||||
const nameMap: any = {
|
||||
1: '溶解氧',
|
||||
2: '水温',
|
||||
3: '饱和度',
|
||||
4: 'PH',
|
||||
5: '盐度',
|
||||
};
|
||||
|
||||
const fieldName = fieldMap[dataType.value] || 'dissolvedOxygen';
|
||||
const seriesName = nameMap[dataType.value] || '溶解氧';
|
||||
|
||||
const xAxisData: string[] = [];
|
||||
const seriesData: number[] = [];
|
||||
|
||||
chartData.value.forEach((item: any) => {
|
||||
const timeStr = item.time || item.createTime || '';
|
||||
const timeParts = timeStr.split(' ');
|
||||
if (timeParts.length > 1) {
|
||||
const datePart = timeParts[0]; // YYYY-MM-DD
|
||||
const timePart = timeParts[1]; // HH:mm:ss.0
|
||||
|
||||
// 提取 MM-DD HH:mm
|
||||
const dateMatch = datePart.match(/\d{4}-(\d{2})-(\d{2})/);
|
||||
const monthDay = dateMatch ? `${dateMatch[1]}-${dateMatch[2]}` : '';
|
||||
const hourMin = timePart.substring(0, 5); // HH:mm
|
||||
|
||||
const formattedTime = `${monthDay} ${hourMin}`;
|
||||
xAxisData.push(formattedTime);
|
||||
}
|
||||
const value = item[fieldName];
|
||||
seriesData.push(value !== null && value !== undefined ? Number(value) : 0);
|
||||
});
|
||||
|
||||
// H5 环境,延迟获取 Canvas 确保 DOM 渲染完成
|
||||
setTimeout(() => {
|
||||
// Taro 在 H5 下会在容器内部生成 <canvas> 标签
|
||||
const canvasElement = document.querySelector('#fullscreen-chart canvas') as HTMLCanvasElement;
|
||||
|
||||
if (!canvasElement) {
|
||||
console.error('❌ Canvas 元素未找到');
|
||||
console.log('尝试查找所有 canvas...');
|
||||
const allCanvas = document.querySelectorAll('canvas');
|
||||
console.log('页面中所有 canvas:', allCanvas);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('✅ 找到 Canvas 元素:', canvasElement);
|
||||
|
||||
const ctx = canvasElement.getContext('2d');
|
||||
if (!ctx) {
|
||||
console.error('❌ 无法获取 Canvas Context');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('✅ 获取 Context 成功');
|
||||
|
||||
chartInstance = new uCharts({
|
||||
type: 'line',
|
||||
context: ctx,
|
||||
width: cWidth,
|
||||
height: cHeight,
|
||||
categories: xAxisData,
|
||||
series: [
|
||||
{
|
||||
name: seriesName,
|
||||
data: seriesData,
|
||||
}
|
||||
],
|
||||
pixelRatio: 1,
|
||||
dataPointShape: false,
|
||||
animation: true,
|
||||
background: '#FFFFFF',
|
||||
color: ['#1890FF'],
|
||||
padding: [15, 30, 35, 45],
|
||||
enableScroll: false,
|
||||
boundaryGap: 'justify',
|
||||
legend: {
|
||||
show: false
|
||||
},
|
||||
dataLabel: false,
|
||||
xAxis: {
|
||||
disableGrid: true,
|
||||
axisLine: true,
|
||||
type: 'grid',
|
||||
gridType: 'dash',
|
||||
itemCount: 0,
|
||||
scrollShow: false,
|
||||
scrollAlign: 'left',
|
||||
labelCount: 10,
|
||||
rotateLabel: true,
|
||||
rotateAngle: 25,
|
||||
},
|
||||
yAxis: {
|
||||
disableGrid: false,
|
||||
gridType: 'dash',
|
||||
tofix: 2,
|
||||
},
|
||||
extra: {
|
||||
line: {
|
||||
type: 'curve',
|
||||
width: 2,
|
||||
activeType: 'hollow',
|
||||
linearType: 'custom',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
console.log('✅ 图表绘制完成');
|
||||
}, 300);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.chart-fullscreen-page {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 100vh; // 横屏后的宽度 = 屏幕高度
|
||||
height: 100vw; // 横屏后的高度 = 屏幕宽度
|
||||
transform: translate(-50%, -50%) rotate(90deg);
|
||||
background: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 50px;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
flex-shrink: 0;
|
||||
|
||||
.back-btn {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.icon {
|
||||
font-size: 28px;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.home-btn {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.home-icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.time-selector {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
gap: 12px;
|
||||
background: #fff;
|
||||
flex-shrink: 0;
|
||||
height: 50px;
|
||||
|
||||
.time-item {
|
||||
padding: 8px 24px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 6px;
|
||||
font-size: 24px;
|
||||
color: #666;
|
||||
|
||||
&.active {
|
||||
background: #1890FF;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
padding: 10px;
|
||||
|
||||
.chart-canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user