|
|
import 'package:flutter/cupertino.dart';
|
|
|
import 'package:flutter/material.dart';
|
|
|
import 'package:bookatanker/supplier/todaysprice/custom_calendar.dart';
|
|
|
|
|
|
import '../../common/settings.dart';
|
|
|
|
|
|
// Contains date picker + filtered graph
|
|
|
class GraphScreen extends StatefulWidget {
|
|
|
final int selectedType;
|
|
|
|
|
|
const GraphScreen({super.key, required this.selectedType});
|
|
|
|
|
|
@override
|
|
|
State<GraphScreen> createState() => _GraphScreenState();
|
|
|
}
|
|
|
|
|
|
class _GraphScreenState extends State<GraphScreen> {
|
|
|
List<Map<String, dynamic>> filteredDrinking = [];
|
|
|
List<Map<String, dynamic>> filteredBore = [];
|
|
|
|
|
|
DateTimeRange? selectedRange;
|
|
|
|
|
|
@override
|
|
|
void initState() {
|
|
|
super.initState();
|
|
|
_loadLastWeek(); // Load last week by default
|
|
|
}
|
|
|
|
|
|
void _loadLastWeek() {
|
|
|
DateTime today = DateTime.now();
|
|
|
DateTime lastWeek = today.subtract(const Duration(days: 7));
|
|
|
debugPrint('$lastWeek');
|
|
|
|
|
|
// Update selectedRange so the card shows last week
|
|
|
selectedRange = DateTimeRange(start: lastWeek, end: today);
|
|
|
|
|
|
_filterData(lastWeek, today);
|
|
|
|
|
|
setState(() {}); // trigger rebuild
|
|
|
}
|
|
|
|
|
|
void _pickDateRange() async {
|
|
|
final result = await showDialog<DateTimeRange>(
|
|
|
context: context,
|
|
|
builder: (context) => AdvancedDateRangePicker(
|
|
|
initialRange: selectedRange,
|
|
|
),
|
|
|
);
|
|
|
|
|
|
if (result != null) {
|
|
|
selectedRange = result;
|
|
|
_filterData(result.start, result.end);
|
|
|
setState(() {
|
|
|
selectedRange = result; // store this for showing in card above graph
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void _filterData(DateTime start, DateTime end) {
|
|
|
setState(() {
|
|
|
filteredDrinking = weeklyPriceData["Drinking Water"]!
|
|
|
.where((d) {
|
|
|
DateTime date = DateTime.parse(d["date"]);
|
|
|
return !date.isBefore(start) && !date.isAfter(end);
|
|
|
}).toList();
|
|
|
|
|
|
filteredBore = weeklyPriceData["bore Water"]!
|
|
|
.where((d) {
|
|
|
DateTime date = DateTime.parse(d["date"]);
|
|
|
return !date.isBefore(start) && !date.isAfter(end);
|
|
|
}).toList();
|
|
|
});
|
|
|
}
|
|
|
|
|
|
void _openDateMenu() {
|
|
|
showMenu(
|
|
|
context: context,
|
|
|
color: Colors.white,
|
|
|
elevation: 6, // smooth shadow
|
|
|
position: const RelativeRect.fromLTRB(1000, 100, 10, 0), // position near icon
|
|
|
items: [
|
|
|
PopupMenuItem(
|
|
|
value: "week",
|
|
|
child: Text("Last Week",
|
|
|
style: fontTextStyle(14, Colors.black, FontWeight.w500),
|
|
|
),
|
|
|
),
|
|
|
PopupMenuItem(
|
|
|
value: "month",
|
|
|
child: Text("Last Month",
|
|
|
style: fontTextStyle(14, Colors.black, FontWeight.w500),
|
|
|
),
|
|
|
),
|
|
|
PopupMenuItem(
|
|
|
value: "custom",
|
|
|
child: Text("Custom Dates",
|
|
|
style: fontTextStyle(14, Colors.black, FontWeight.w500),
|
|
|
),
|
|
|
),
|
|
|
],
|
|
|
).then((value) {
|
|
|
if (value == null) return;
|
|
|
if (value == "week") {
|
|
|
DateTime today = DateTime.now();
|
|
|
DateTime lastWeek = today.subtract(const Duration(days: 7));
|
|
|
setState(() {
|
|
|
selectedRange = DateTimeRange(start: lastWeek, end: today);
|
|
|
_filterData(lastWeek, today);
|
|
|
});
|
|
|
}
|
|
|
else if (value == "month") {
|
|
|
DateTime today = DateTime.now();
|
|
|
DateTime lastMonth = DateTime(today.year, today.month - 1, today.day);
|
|
|
setState(() {
|
|
|
selectedRange = DateTimeRange(start: lastMonth, end: today);
|
|
|
_filterData(lastMonth, today);
|
|
|
});
|
|
|
}
|
|
|
else if (value == "custom") {
|
|
|
_pickDateRange();
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
// For showing date in card above graph
|
|
|
String _formattedDateRange() {
|
|
|
if (selectedRange == null) return "Select Date";
|
|
|
|
|
|
final start = selectedRange!.start;
|
|
|
final end = selectedRange!.end;
|
|
|
|
|
|
const months = [
|
|
|
"", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
|
|
];
|
|
|
|
|
|
if (start.month == end.month) {
|
|
|
return "${start.day} – ${end.day} ${months[start.month]}";
|
|
|
} else {
|
|
|
return "${start.day} ${months[start.month]} – ${end.day} ${months[end.month]}";
|
|
|
}
|
|
|
}
|
|
|
|
|
|
String _formattedAvgPrice() {
|
|
|
List<Map<String, dynamic>> activeList =
|
|
|
widget.selectedType == 0 ? filteredDrinking : filteredBore;
|
|
|
|
|
|
debugPrint('$activeList');
|
|
|
|
|
|
if (activeList.isEmpty) return "-";
|
|
|
|
|
|
double total = 0;
|
|
|
for (var item in activeList) {
|
|
|
total += (item["price"] as num).toDouble();
|
|
|
}
|
|
|
|
|
|
double avg = total / activeList.length;
|
|
|
return "${avg.toStringAsFixed(2)}";
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
Widget build(BuildContext context) {
|
|
|
return Column(
|
|
|
children: [
|
|
|
|
|
|
// 🔥 TOP ROW (LEFT: BOX, RIGHT: CALENDAR)
|
|
|
Row(
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
children: [
|
|
|
|
|
|
// LEFT BOX
|
|
|
Padding(
|
|
|
padding: const EdgeInsets.only(top: 14, left: 10),
|
|
|
child: Container(
|
|
|
height: 100,
|
|
|
width: 180,
|
|
|
padding: const EdgeInsets.all(12),
|
|
|
decoration: BoxDecoration(
|
|
|
color: Colors.white,
|
|
|
borderRadius: BorderRadius.circular(12),
|
|
|
boxShadow: [
|
|
|
BoxShadow(
|
|
|
color: Colors.black.withOpacity(0.15),
|
|
|
blurRadius: 8,
|
|
|
spreadRadius: 2,
|
|
|
offset: const Offset(2, 4),
|
|
|
),
|
|
|
],
|
|
|
),
|
|
|
child: AnimatedSwitcher(
|
|
|
duration: const Duration(milliseconds: 350),
|
|
|
transitionBuilder: (child, animation) {
|
|
|
return FadeTransition(
|
|
|
opacity: animation,
|
|
|
child: SlideTransition(
|
|
|
position: Tween<Offset>(
|
|
|
begin: const Offset(0.2, 0), // Soft slide from right
|
|
|
end: Offset.zero,
|
|
|
).animate(animation),
|
|
|
child: child,
|
|
|
),
|
|
|
);
|
|
|
},
|
|
|
child: Column(
|
|
|
key: ValueKey(widget.selectedType), // IMPORTANT 🔑
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
children: [
|
|
|
Text(
|
|
|
widget.selectedType == 0 ? "Drinking Water" : "Bore Water",
|
|
|
style: fontTextStyle(14, Colors.black, FontWeight.w600),
|
|
|
),
|
|
|
|
|
|
const SizedBox(height: 4),
|
|
|
|
|
|
Text(
|
|
|
_formattedDateRange(),
|
|
|
style: fontTextStyle(14, Colors.grey.shade700, FontWeight.w500),
|
|
|
),
|
|
|
|
|
|
const SizedBox(height: 4),
|
|
|
|
|
|
RichText(
|
|
|
text: TextSpan(
|
|
|
children: [
|
|
|
TextSpan(
|
|
|
text: "${_formattedAvgPrice()} ",
|
|
|
style: fontTextStyle(20, Colors.black, FontWeight.bold),
|
|
|
),
|
|
|
TextSpan(
|
|
|
text: "/5000 L",
|
|
|
style: fontTextStyle(14, Colors.grey.shade600, FontWeight.w400),
|
|
|
),
|
|
|
],
|
|
|
),
|
|
|
),
|
|
|
],
|
|
|
),
|
|
|
),
|
|
|
),
|
|
|
),
|
|
|
|
|
|
// RIGHT CALENDAR BUTTON
|
|
|
Padding(
|
|
|
padding: const EdgeInsets.only(top: 4, right: 8),
|
|
|
child: InkWell(
|
|
|
onTap: () => _openDateMenu(),
|
|
|
borderRadius: BorderRadius.circular(10),
|
|
|
child: Container(
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 8),
|
|
|
decoration: BoxDecoration(
|
|
|
color: Colors.white,
|
|
|
borderRadius: BorderRadius.circular(10),
|
|
|
border: Border.all(color: Colors.grey.shade300),
|
|
|
boxShadow: const [
|
|
|
BoxShadow(
|
|
|
color: Colors.black12,
|
|
|
blurRadius: 4,
|
|
|
offset: Offset(0, 2),
|
|
|
),
|
|
|
],
|
|
|
),
|
|
|
child: Row(
|
|
|
children: const [
|
|
|
Icon(Icons.calendar_month, size: 28, color: Colors.blueAccent),
|
|
|
Icon(Icons.arrow_drop_down, size: 28, color: Colors.blueAccent),
|
|
|
],
|
|
|
),
|
|
|
),
|
|
|
),
|
|
|
),
|
|
|
],
|
|
|
),
|
|
|
|
|
|
const SizedBox(height: 5),
|
|
|
|
|
|
// Show graph only if data is available
|
|
|
if (filteredDrinking.isNotEmpty || filteredBore.isNotEmpty)
|
|
|
Expanded(
|
|
|
child: SingleChildScrollView(
|
|
|
scrollDirection: Axis.horizontal,
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 10),
|
|
|
child: DoublePriceBarGraph(
|
|
|
drinkingData: filteredDrinking,
|
|
|
boreData: filteredBore,
|
|
|
),
|
|
|
),
|
|
|
)
|
|
|
else
|
|
|
Padding(
|
|
|
padding: EdgeInsets.all(30),
|
|
|
child: Text("No data available for the selected dates",
|
|
|
style: fontTextStyle(13, Colors.black87, FontWeight.w600),
|
|
|
),
|
|
|
),
|
|
|
],
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
Widget buildLegend() {
|
|
|
return Row(
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
children: [
|
|
|
// Drinking Water Legend
|
|
|
Row(
|
|
|
children: [
|
|
|
Container(
|
|
|
width: 14,
|
|
|
height: 14,
|
|
|
decoration: BoxDecoration(
|
|
|
color: Colors.blueAccent,
|
|
|
borderRadius: BorderRadius.circular(4),
|
|
|
),
|
|
|
),
|
|
|
const SizedBox(width: 6),
|
|
|
|
|
|
Text(
|
|
|
"Drinking Water",
|
|
|
style: fontTextStyle(12, Colors.black87, FontWeight.w600),
|
|
|
),
|
|
|
],
|
|
|
),
|
|
|
|
|
|
const SizedBox(width: 20),
|
|
|
|
|
|
// Bore Water Legend
|
|
|
Row(
|
|
|
children: [
|
|
|
Container(
|
|
|
width: 14,
|
|
|
height: 14,
|
|
|
decoration: BoxDecoration(
|
|
|
color: Colors.orangeAccent,
|
|
|
borderRadius: BorderRadius.circular(4),
|
|
|
),
|
|
|
),
|
|
|
const SizedBox(width: 6),
|
|
|
|
|
|
Text(
|
|
|
"Bore Water",
|
|
|
style: fontTextStyle(12, Colors.black87, FontWeight.w600),
|
|
|
),
|
|
|
],
|
|
|
),
|
|
|
],
|
|
|
);
|
|
|
}
|
|
|
|
|
|
|
|
|
class DoublePriceBarGraph extends StatelessWidget {
|
|
|
final List<Map<String, dynamic>> drinkingData;
|
|
|
final List<Map<String, dynamic>> boreData;
|
|
|
|
|
|
const DoublePriceBarGraph({
|
|
|
super.key,
|
|
|
required this.drinkingData,
|
|
|
required this.boreData,
|
|
|
});
|
|
|
|
|
|
@override
|
|
|
Widget build(BuildContext context) {
|
|
|
final drinkMap = {for (var d in drinkingData) d["date"]: d};
|
|
|
final boreMap = {for (var b in boreData) b["date"]: b};
|
|
|
|
|
|
final allDates = [...drinkMap.keys, ...boreMap.keys].toSet().toList()
|
|
|
..sort((a, b) =>
|
|
|
DateTime.parse(a).compareTo(DateTime.parse(b))); // FIXED
|
|
|
|
|
|
return Row(
|
|
|
crossAxisAlignment: CrossAxisAlignment.end,
|
|
|
children: allDates.map((date) {
|
|
|
final d = drinkMap[date];
|
|
|
final b = boreMap[date];
|
|
|
|
|
|
double drinkPrice = d?["price"]?.toDouble() ?? 0.0;
|
|
|
double borePrice = b?["price"]?.toDouble() ?? 0.0;
|
|
|
|
|
|
String day = DateTime.parse(date).day.toString();
|
|
|
|
|
|
return Padding(
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
|
|
child: Column(
|
|
|
mainAxisAlignment: MainAxisAlignment.end,
|
|
|
children: [
|
|
|
Row(
|
|
|
crossAxisAlignment: CrossAxisAlignment.end,
|
|
|
children: [
|
|
|
// Drinking
|
|
|
_buildBar(drinkPrice, Colors.blueAccent),
|
|
|
|
|
|
const SizedBox(width: 0),
|
|
|
|
|
|
// Bore
|
|
|
_buildBar(borePrice, Colors.orangeAccent)
|
|
|
],
|
|
|
),
|
|
|
const SizedBox(height: 6),
|
|
|
Text(day, style: fontTextStyle(12, Colors.black87, FontWeight.w600)),
|
|
|
],
|
|
|
),
|
|
|
);
|
|
|
}).toList(),
|
|
|
);
|
|
|
}
|
|
|
|
|
|
Widget _buildBar(double price, Color color) {
|
|
|
return Column(
|
|
|
children: [
|
|
|
Text(
|
|
|
"₹${price.toInt()}",
|
|
|
style: fontTextStyle(9, color, FontWeight.bold),
|
|
|
),
|
|
|
Container(
|
|
|
width: 20,
|
|
|
height: price / 15, // Adjust scaling if bars too short
|
|
|
decoration: BoxDecoration(
|
|
|
color: color,
|
|
|
borderRadius: BorderRadius.circular(5),
|
|
|
),
|
|
|
),
|
|
|
],
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final Map<String, List<Map<String, dynamic>>> weeklyPriceData = {
|
|
|
|
|
|
"Drinking Water": [
|
|
|
{
|
|
|
"date": "2025-11-01",
|
|
|
"price": 1570,
|
|
|
"minPrice": 1550,
|
|
|
"maxPrice": 1650,
|
|
|
"avgPrice": 1600
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-02",
|
|
|
"price": 1590,
|
|
|
"minPrice": 1560,
|
|
|
"maxPrice": 1660,
|
|
|
"avgPrice": 1610
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-03",
|
|
|
"price": 1550,
|
|
|
"minPrice": 1520,
|
|
|
"maxPrice": 1600,
|
|
|
"avgPrice": 1560
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-04",
|
|
|
"price": 1610,
|
|
|
"minPrice": 1580,
|
|
|
"maxPrice": 1670,
|
|
|
"avgPrice": 1620
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-05",
|
|
|
"price": 1630,
|
|
|
"minPrice": 1600,
|
|
|
"maxPrice": 1700,
|
|
|
"avgPrice": 1650
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-06",
|
|
|
"price": 1580,
|
|
|
"minPrice": 1550,
|
|
|
"maxPrice": 1650,
|
|
|
"avgPrice": 1600
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-07",
|
|
|
"price": 1600,
|
|
|
"minPrice": 1580,
|
|
|
"maxPrice": 1670,
|
|
|
"avgPrice": 1620
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-08",
|
|
|
"price": 1640,
|
|
|
"minPrice": 1600,
|
|
|
"maxPrice": 1700,
|
|
|
"avgPrice": 1650
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-09",
|
|
|
"price": 1620,
|
|
|
"minPrice": 1590,
|
|
|
"maxPrice": 1680,
|
|
|
"avgPrice": 1630
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-10",
|
|
|
"price": 1575,
|
|
|
"minPrice": 1550,
|
|
|
"maxPrice": 1640,
|
|
|
"avgPrice": 1600
|
|
|
},
|
|
|
|
|
|
{
|
|
|
"date": "2025-11-11",
|
|
|
"price": 1585,
|
|
|
"minPrice": 1550,
|
|
|
"maxPrice": 1650,
|
|
|
"avgPrice": 1605
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-12",
|
|
|
"price": 1615,
|
|
|
"minPrice": 1580,
|
|
|
"maxPrice": 1670,
|
|
|
"avgPrice": 1625
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-13",
|
|
|
"price": 1590,
|
|
|
"minPrice": 1560,
|
|
|
"maxPrice": 1650,
|
|
|
"avgPrice": 1610
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-14",
|
|
|
"price": 1645,
|
|
|
"minPrice": 1610,
|
|
|
"maxPrice": 1710,
|
|
|
"avgPrice": 1660
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-15",
|
|
|
"price": 1625,
|
|
|
"minPrice": 1590,
|
|
|
"maxPrice": 1680,
|
|
|
"avgPrice": 1635
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-16",
|
|
|
"price": 1580,
|
|
|
"minPrice": 1550,
|
|
|
"maxPrice": 1640,
|
|
|
"avgPrice": 1595
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-17",
|
|
|
"price": 1570,
|
|
|
"minPrice": 1540,
|
|
|
"maxPrice": 1630,
|
|
|
"avgPrice": 1580
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-18",
|
|
|
"price": 1600,
|
|
|
"minPrice": 1580,
|
|
|
"maxPrice": 1660,
|
|
|
"avgPrice": 1620
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-19",
|
|
|
"price": 1630,
|
|
|
"minPrice": 1600,
|
|
|
"maxPrice": 1690,
|
|
|
"avgPrice": 1650
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-20",
|
|
|
"price": 1650,
|
|
|
"minPrice": 1610,
|
|
|
"maxPrice": 1720,
|
|
|
"avgPrice": 1670
|
|
|
},
|
|
|
|
|
|
{
|
|
|
"date": "2025-11-21",
|
|
|
"price": 1610,
|
|
|
"minPrice": 1580,
|
|
|
"maxPrice": 1670,
|
|
|
"avgPrice": 1630
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-22",
|
|
|
"price": 1590,
|
|
|
"minPrice": 1560,
|
|
|
"maxPrice": 1650,
|
|
|
"avgPrice": 1605
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-23",
|
|
|
"price": 1620,
|
|
|
"minPrice": 1590,
|
|
|
"maxPrice": 1680,
|
|
|
"avgPrice": 1630
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-24",
|
|
|
"price": 1670,
|
|
|
"minPrice": 1630,
|
|
|
"maxPrice": 1730,
|
|
|
"avgPrice": 1680
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-25",
|
|
|
"price": 1690,
|
|
|
"minPrice": 1650,
|
|
|
"maxPrice": 1750,
|
|
|
"avgPrice": 1700
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-26",
|
|
|
"price": 1580,
|
|
|
"minPrice": 1550,
|
|
|
"maxPrice": 1640,
|
|
|
"avgPrice": 1600
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-27",
|
|
|
"price": 1600,
|
|
|
"minPrice": 1570,
|
|
|
"maxPrice": 1670,
|
|
|
"avgPrice": 1620
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-28",
|
|
|
"price": 1615,
|
|
|
"minPrice": 1580,
|
|
|
"maxPrice": 1680,
|
|
|
"avgPrice": 1630
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-29",
|
|
|
"price": 1635,
|
|
|
"minPrice": 1600,
|
|
|
"maxPrice": 1700,
|
|
|
"avgPrice": 1650
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-30",
|
|
|
"price": 1605,
|
|
|
"minPrice": 1580,
|
|
|
"maxPrice": 1670,
|
|
|
"avgPrice": 1620
|
|
|
},
|
|
|
],
|
|
|
|
|
|
"bore Water": [
|
|
|
{
|
|
|
"date": "2025-11-01",
|
|
|
"price": 780,
|
|
|
"minPrice": 760,
|
|
|
"maxPrice": 810,
|
|
|
"avgPrice": 790
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-02",
|
|
|
"price": 800,
|
|
|
"minPrice": 780,
|
|
|
"maxPrice": 840,
|
|
|
"avgPrice": 810
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-03",
|
|
|
"price": 770,
|
|
|
"minPrice": 750,
|
|
|
"maxPrice": 800,
|
|
|
"avgPrice": 780
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-04",
|
|
|
"price": 820,
|
|
|
"minPrice": 800,
|
|
|
"maxPrice": 850,
|
|
|
"avgPrice": 830
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-05",
|
|
|
"price": 830,
|
|
|
"minPrice": 810,
|
|
|
"maxPrice": 860,
|
|
|
"avgPrice": 840
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-06",
|
|
|
"price": 785,
|
|
|
"minPrice": 760,
|
|
|
"maxPrice": 820,
|
|
|
"avgPrice": 795
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-07",
|
|
|
"price": 810,
|
|
|
"minPrice": 790,
|
|
|
"maxPrice": 840,
|
|
|
"avgPrice": 820
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-08",
|
|
|
"price": 825,
|
|
|
"minPrice": 800,
|
|
|
"maxPrice": 860,
|
|
|
"avgPrice": 835
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-09",
|
|
|
"price": 795,
|
|
|
"minPrice": 770,
|
|
|
"maxPrice": 830,
|
|
|
"avgPrice": 810
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-10",
|
|
|
"price": 820,
|
|
|
"minPrice": 790,
|
|
|
"maxPrice": 860,
|
|
|
"avgPrice": 830
|
|
|
},
|
|
|
|
|
|
{
|
|
|
"date": "2025-11-11",
|
|
|
"price": 810,
|
|
|
"minPrice": 780,
|
|
|
"maxPrice": 850,
|
|
|
"avgPrice": 820
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-12",
|
|
|
"price": 830,
|
|
|
"minPrice": 800,
|
|
|
"maxPrice": 870,
|
|
|
"avgPrice": 840
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-13",
|
|
|
"price": 785,
|
|
|
"minPrice": 770,
|
|
|
"maxPrice": 820,
|
|
|
"avgPrice": 795
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-14",
|
|
|
"price": 750,
|
|
|
"minPrice": 730,
|
|
|
"maxPrice": 790,
|
|
|
"avgPrice": 760
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-15",
|
|
|
"price": 770,
|
|
|
"minPrice": 750,
|
|
|
"maxPrice": 810,
|
|
|
"avgPrice": 780
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-16",
|
|
|
"price": 825,
|
|
|
"minPrice": 800,
|
|
|
"maxPrice": 870,
|
|
|
"avgPrice": 840
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-17",
|
|
|
"price": 840,
|
|
|
"minPrice": 820,
|
|
|
"maxPrice": 880,
|
|
|
"avgPrice": 850
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-18",
|
|
|
"price": 810,
|
|
|
"minPrice": 790,
|
|
|
"maxPrice": 840,
|
|
|
"avgPrice": 820
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-19",
|
|
|
"price": 790,
|
|
|
"minPrice": 770,
|
|
|
"maxPrice": 830,
|
|
|
"avgPrice": 800
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-20",
|
|
|
"price": 830,
|
|
|
"minPrice": 800,
|
|
|
"maxPrice": 870,
|
|
|
"avgPrice": 840
|
|
|
},
|
|
|
|
|
|
{
|
|
|
"date": "2025-11-21",
|
|
|
"price": 850,
|
|
|
"minPrice": 820,
|
|
|
"maxPrice": 890,
|
|
|
"avgPrice": 860
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-22",
|
|
|
"price": 780,
|
|
|
"minPrice": 760,
|
|
|
"maxPrice": 810,
|
|
|
"avgPrice": 790
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-23",
|
|
|
"price": 790,
|
|
|
"minPrice": 770,
|
|
|
"maxPrice": 820,
|
|
|
"avgPrice": 800
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-24",
|
|
|
"price": 835,
|
|
|
"minPrice": 810,
|
|
|
"maxPrice": 870,
|
|
|
"avgPrice": 845
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-25",
|
|
|
"price": 820,
|
|
|
"minPrice": 800,
|
|
|
"maxPrice": 860,
|
|
|
"avgPrice": 830
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-26",
|
|
|
"price": 760,
|
|
|
"minPrice": 740,
|
|
|
"maxPrice": 800,
|
|
|
"avgPrice": 780
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-27",
|
|
|
"price": 810,
|
|
|
"minPrice": 780,
|
|
|
"maxPrice": 850,
|
|
|
"avgPrice": 820
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-28",
|
|
|
"price": 795,
|
|
|
"minPrice": 770,
|
|
|
"maxPrice": 830,
|
|
|
"avgPrice": 805
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-29",
|
|
|
"price": 835,
|
|
|
"minPrice": 810,
|
|
|
"maxPrice": 870,
|
|
|
"avgPrice": 845
|
|
|
},
|
|
|
{
|
|
|
"date": "2025-11-30",
|
|
|
"price": 820,
|
|
|
"minPrice": 790,
|
|
|
"maxPrice": 860,
|
|
|
"avgPrice": 830
|
|
|
},
|
|
|
]
|
|
|
};
|