import { Component, AfterViewInit, ViewChild, ElementRef, OnDestroy, ChangeDetectorRef } from '@angular/core'; import * as echarts from 'echarts'; import { CsvReaderService } from './csv-reader-service'; import { IonicModule,ModalController } from '@ionic/angular'; import { CommonModule } from '@angular/common'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; // 导入 FormsModule 和 ReactiveFormsModule @Component({ selector: 'app-market-forecast', templateUrl: './market-forecast.component.html', styleUrls: ['./market-forecast.component.scss'], standalone: true, imports: [IonicModule, CommonModule,FormsModule, ReactiveFormsModule] }) export class MarketForecastComponent implements AfterViewInit, OnDestroy { @ViewChild('chartContainer', { static: false }) priceChartContainer!: ElementRef; @ViewChild('indexChartContainer', { static: false }) indexChartContainer!: ElementRef; isModalOpen = false; userEntries: { price?: string; index?: string }[] = []; private currentChart?: echarts.ECharts; public currentChartType: 'price' | 'index' = 'price'; // 明确限定类型 constructor(private csvReaderService: CsvReaderService, private cdr: ChangeDetectorRef,private modalCtrl: ModalController) { } openDataEntryModal() { this.isModalOpen = true; this.userEntries.push({}); // 初始化至少一条记录 } closeModal() { this.isModalOpen = false; } addEntry() { this.userEntries.push({}); } onSubmit(form: any) { if (form.valid) { const jsonData = { "价格": this.userEntries.map(entry => entry.price).filter(Boolean), "指数": this.userEntries.map(entry => entry.index).filter(Boolean) }; console.log(JSON.stringify(jsonData, null, 2)); // 在这里你可以将 jsonData 发送到服务器或进行其他操作 this.closeModal(); } } ngAfterViewInit(): void { this.cdr.detectChanges(); // 确保变更检测运行以更新视图 requestAnimationFrame(() => { this.selectChart(this.currentChartType); }); } loadPredictChartData(): void { this.csvReaderService.getPredictData().subscribe(data => { this.updatePredictChart(data); }); } updatePredictChart(data: any[]): void { if (!this.currentChart || !data) return; const dates = data.map(d => d['日期'].getTime()); const prices = data.map(d => d['数值']); const indices = data.map(d => d['指数']); const xAxisConfig = { type: 'value', boundaryGap: false, name: '价格', min: Math.min(...prices), // 动态设置最小值 max: Math.max(...prices), // 动态设置最大值 axisLabel: { formatter: '{value}', rotate: -90 // 将 X 轴标签旋转 -90 度 }, axisLine: { show: true }, axisTick: { show: true }, axisPointer: { label: { formatter: function (params: any) { return params.value; } } } }; const option = { title: { text: '预测脐橙价格', left: 'center' }, tooltip: { trigger: 'axis' }, xAxis: xAxisConfig, yAxis: { type: 'time', boundaryGap: false, name: '', axisLabel: { formatter: function (value: any) { const date = new Date(value); return `${date.getMonth() + 1}-${date.getDate()}`; }, rotate: -90 // 将 Y 轴标签旋转 -90 度 }, axisLine: { show: true }, axisTick: { show: true }, axisPointer: { label: { formatter: function (params: any) { const date = new Date(params.value); return `${date.getMonth() + 1}-${date.getDate()}`; } } } }, series: [{ name: '预测价格', type: 'line', data: data.map((item, index) => [prices[index], dates[index]]), itemStyle: { color: 'red' } }], dataZoom: [ { type: 'slider', show: true, yAxisIndex: [0], start: 50, end: 100 }, { type: 'inside', yAxisIndex: [0], start: 50, end: 100 } ], graphic: [ { type: 'text', left: 'middle', top: 'bottom', style: { text: '预测价格', textAlign: 'center', fontSize: 14, rotation: -Math.PI / 2, // 旋转 -90 度 transformOrigin: 'center' } } ] }; this.currentChart.setOption(option); } predictChart(){ this.cdr.detectChanges(); // 触发变更检测以更新视图 this.csvReaderService.getPredictData().subscribe(data => { this.clearChart(); this.initChart(); this.updatePredictChart(data); // 更新预测图表 }); } selectChart(type: 'price' | 'index'): void { this.currentChartType = type; this.cdr.detectChanges(); // 触发变更检测以更新视图 // 延迟初始化以确保视图更新完毕 setTimeout(() => { requestAnimationFrame(() => { this.clearChart(); this.initChart(); this.loadChartData(); }); }, 0); } initChart() { let chartContainerEl: HTMLElement | null = null; if (this.currentChartType === 'price') { chartContainerEl = this.priceChartContainer?.nativeElement; } else if (this.currentChartType === 'index') { chartContainerEl = this.indexChartContainer?.nativeElement; } // 检查图表容器是否已准备好,并且有非零尺寸 if (chartContainerEl && chartContainerEl.offsetWidth > 0 && chartContainerEl.offsetHeight > 0) { this.currentChart = echarts.init(chartContainerEl); } else { console.warn('Chart container is not ready or has zero size.'); // 如果图表容器尚未准备好,设置一个短暂的延时并再次尝试 setTimeout(() => this.initChart(), 100); } } loadChartData(): void { this.csvReaderService.getOrangeData().subscribe(data => { this.updateChart(data); }); } updateChart(data: any[]): void { if (!this.currentChart) return; const dates = data.map(d => d['日期'].getTime()); const prices = data.map(d => d['数值']); const indices = data.map(d => d['指数']); const xAxisConfig = { type: 'value', boundaryGap: false, name: '', min: this.currentChartType === 'price' ? 6 : 90, max: this.currentChartType === 'price' ? 15 : 120, axisLabel: { formatter: function (value: any) { return value.toString(); }, rotate: -90 // 将 X 轴标签旋转 -90 度 }, axisLine: { show: true }, axisTick: { show: true }, axisPointer: { label: { formatter: function (params: any) { return params.value; } } } }; const yAxisConfig = { type: 'time', boundaryGap: false, name: '', axisLabel: { formatter: function (value: any) { const date = new Date(value); return `${date.getMonth() + 1}-${date.getDate()}`; }, rotate: -90 // 将 Y 轴标签旋转 -90 度 }, axisLine: { show: true }, axisTick: { show: true }, axisPointer: { label: { formatter: function (params: any) { const date = new Date(params.value); return `${date.getMonth() + 1}-${date.getDate()}`; } } } }; const dataZoomConfig = [ { type: 'slider', show: true, yAxisIndex: [0], start: 50, end: 100 }, { type: 'inside', yAxisIndex: [0], start: 50, end: 100 } ]; let option; if (this.currentChartType === 'price') { option = { title: { text: '每日脐橙价格', left: 'center' }, tooltip: { trigger: 'axis' }, xAxis: xAxisConfig, yAxis: yAxisConfig, series: [{ name: '价格', type: 'line', data: data.map((item, index) => [prices[index], dates[index]]), itemStyle: { color: 'orange' } }], dataZoom: dataZoomConfig, graphic: [ { type: 'text', left: 'middle', top: 'bottom', style: { text: '价格', textAlign: 'center', fontSize: 14, rotation: -Math.PI / 2, // 旋转 -90 度 transformOrigin: 'center' } } ] }; } else { option = { title: { text: '脐橙价格指数', left: 'center' }, tooltip: { trigger: 'axis' }, xAxis: xAxisConfig, yAxis: yAxisConfig, series: [{ name: '指数', type: 'line', data: data.map((item, index) => [indices[index], dates[index]]) }], dataZoom: dataZoomConfig, graphic: [ { type: 'text', left: 'middle', top: 'bottom', style: { text: '指数', textAlign: 'center', fontSize: 14, rotation: -Math.PI / 2, // 旋转 -90 度 transformOrigin: 'center' } } ] }; } this.currentChart.setOption(option); } clearChart(): void { if (this.currentChart) { this.currentChart.dispose(); this.currentChart = undefined; } } ngOnDestroy(): void { this.clearChart(); } }