|
|
@@ -44,9 +44,11 @@ class _ExpenseDetailReportPageState
|
|
|
super.initState();
|
|
|
final now = DateTime.now();
|
|
|
final elevenMonthsAgo = DateTime(now.year, now.month - 11, 1);
|
|
|
- _startCtrl.text = '${elevenMonthsAgo.year}-${elevenMonthsAgo.month.toString().padLeft(2, '0')}-01';
|
|
|
+ _startCtrl.text =
|
|
|
+ '${elevenMonthsAgo.year}-${elevenMonthsAgo.month.toString().padLeft(2, '0')}-01';
|
|
|
final lastDay = DateTime(now.year, now.month + 1, 0).day;
|
|
|
- _endCtrl.text = '${now.year}-${now.month.toString().padLeft(2, '0')}-${lastDay.toString().padLeft(2, '0')}';
|
|
|
+ _endCtrl.text =
|
|
|
+ '${now.year}-${now.month.toString().padLeft(2, '0')}-${lastDay.toString().padLeft(2, '0')}';
|
|
|
_scrollCtrl.addListener(_onScroll);
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) => _loadData());
|
|
|
}
|
|
|
@@ -145,8 +147,12 @@ class _ExpenseDetailReportPageState
|
|
|
}
|
|
|
|
|
|
void _onScroll() {
|
|
|
- if (_scrollCtrl.position.pixels < _scrollCtrl.position.maxScrollExtent - 200) return;
|
|
|
- if (_detailTotal > 0 && _details.length < _detailTotal && !_detailLoadingMore) {
|
|
|
+ if (_scrollCtrl.position.pixels <
|
|
|
+ _scrollCtrl.position.maxScrollExtent - 200)
|
|
|
+ return;
|
|
|
+ if (_detailTotal > 0 &&
|
|
|
+ _details.length < _detailTotal &&
|
|
|
+ !_detailLoadingMore) {
|
|
|
_loadMoreDetails();
|
|
|
}
|
|
|
}
|
|
|
@@ -160,7 +166,11 @@ class _ExpenseDetailReportPageState
|
|
|
startDate: _startCtrl.text.isNotEmpty ? _startCtrl.text : null,
|
|
|
endDate: _endCtrl.text.isNotEmpty ? _endCtrl.text : null,
|
|
|
);
|
|
|
- if (mounted) setState(() { _subordinateData = data; _subordinateLoading = false; });
|
|
|
+ if (mounted)
|
|
|
+ setState(() {
|
|
|
+ _subordinateData = data;
|
|
|
+ _subordinateLoading = false;
|
|
|
+ });
|
|
|
} catch (_) {
|
|
|
if (mounted) setState(() => _subordinateLoading = false);
|
|
|
}
|
|
|
@@ -500,13 +510,22 @@ class _ExpenseDetailReportPageState
|
|
|
monthlyMap[item.month] = item;
|
|
|
}
|
|
|
|
|
|
- final amountData = monthKeys.map((m) => monthlyMap[m]?.amount ?? 0.0).toList();
|
|
|
- final approvedData = monthKeys.map((m) => monthlyMap[m]?.approvedAmount ?? 0.0).toList();
|
|
|
+ final amountData = monthKeys
|
|
|
+ .map((m) => monthlyMap[m]?.amount ?? 0.0)
|
|
|
+ .toList();
|
|
|
+ final approvedData = monthKeys
|
|
|
+ .map((m) => monthlyMap[m]?.approvedAmount ?? 0.0)
|
|
|
+ .toList();
|
|
|
|
|
|
if (amountData.isEmpty) {
|
|
|
return SizedBox(
|
|
|
height: 200,
|
|
|
- child: Center(child: Text(AppLocalizations.of(context).get('noData'), style: TextStyle(fontSize: 14, color: colors.textPlaceholder))),
|
|
|
+ child: Center(
|
|
|
+ child: Text(
|
|
|
+ AppLocalizations.of(context).get('noData'),
|
|
|
+ style: TextStyle(fontSize: 14, color: colors.textPlaceholder),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@@ -514,118 +533,128 @@ class _ExpenseDetailReportPageState
|
|
|
final maxVal = allValues.reduce((a, b) => a > b ? a : b);
|
|
|
final maxY = (maxVal > 0 ? maxVal * 1.2 : 100).toDouble();
|
|
|
|
|
|
- return LineChart(
|
|
|
- LineChartData(
|
|
|
- gridData: FlGridData(
|
|
|
- show: true,
|
|
|
- drawVerticalLine: false,
|
|
|
- horizontalInterval: maxY / 4,
|
|
|
- getDrawingHorizontalLine: (v) =>
|
|
|
- FlLine(color: colors.border, strokeWidth: 0.5),
|
|
|
- ),
|
|
|
- titlesData: FlTitlesData(
|
|
|
- leftTitles: AxisTitles(
|
|
|
- sideTitles: SideTitles(
|
|
|
- showTitles: true,
|
|
|
- reservedSize: 80,
|
|
|
- interval: maxY / 4,
|
|
|
- getTitlesWidget: (v, meta) => Text(
|
|
|
- formatAmount(v.toDouble()),
|
|
|
- style: TextStyle(fontSize: 10, color: colors.textPlaceholder),
|
|
|
- ),
|
|
|
- ),
|
|
|
- ),
|
|
|
- bottomTitles: AxisTitles(
|
|
|
- sideTitles: SideTitles(
|
|
|
- showTitles: true,
|
|
|
- interval: 1,
|
|
|
- reservedSize: 26,
|
|
|
- getTitlesWidget: (v, meta) {
|
|
|
- final i = v.toInt();
|
|
|
- if (i < 0 || i >= monthLabels.length) return const SizedBox();
|
|
|
- return Padding(
|
|
|
- padding: const EdgeInsets.only(top: 4),
|
|
|
- child: Text(
|
|
|
- monthLabels[i],
|
|
|
- style: TextStyle(fontSize: 9, color: colors.textPlaceholder),
|
|
|
- ),
|
|
|
- );
|
|
|
- },
|
|
|
- ),
|
|
|
- ),
|
|
|
- topTitles: const AxisTitles(
|
|
|
- sideTitles: SideTitles(showTitles: false),
|
|
|
- ),
|
|
|
- rightTitles: const AxisTitles(
|
|
|
- sideTitles: SideTitles(showTitles: false),
|
|
|
+ return Padding(
|
|
|
+ padding: const EdgeInsets.only(top: 8),
|
|
|
+ child: LineChart(
|
|
|
+ LineChartData(
|
|
|
+ gridData: FlGridData(
|
|
|
+ show: true,
|
|
|
+ drawVerticalLine: false,
|
|
|
+ horizontalInterval: maxY / 4,
|
|
|
+ getDrawingHorizontalLine: (v) =>
|
|
|
+ FlLine(color: colors.border, strokeWidth: 0.5),
|
|
|
),
|
|
|
- ),
|
|
|
- borderData: FlBorderData(show: false),
|
|
|
- minY: 0,
|
|
|
- maxY: maxY,
|
|
|
- lineTouchData: LineTouchData(
|
|
|
- enabled: true,
|
|
|
- touchTooltipData: LineTouchTooltipData(
|
|
|
- getTooltipItems: (spots) => spots.map((s) {
|
|
|
- return LineTooltipItem(
|
|
|
- '${monthLabels[s.spotIndex]}\n${formatAmount(s.y)}',
|
|
|
- const TextStyle(
|
|
|
- color: Colors.white,
|
|
|
- fontSize: 12,
|
|
|
- fontWeight: FontWeight.w500,
|
|
|
+ titlesData: FlTitlesData(
|
|
|
+ leftTitles: AxisTitles(
|
|
|
+ sideTitles: SideTitles(
|
|
|
+ showTitles: true,
|
|
|
+ reservedSize: 80,
|
|
|
+ interval: maxY / 4,
|
|
|
+ getTitlesWidget: (v, meta) => Text(
|
|
|
+ formatAmount(v.toDouble()),
|
|
|
+ style: TextStyle(fontSize: 10, color: colors.textPlaceholder),
|
|
|
),
|
|
|
- );
|
|
|
- }).toList(),
|
|
|
- ),
|
|
|
- ),
|
|
|
- lineBarsData: [
|
|
|
- LineChartBarData(
|
|
|
- spots: List.generate(
|
|
|
- amountData.length,
|
|
|
- (i) => FlSpot(i.toDouble(), amountData[i]),
|
|
|
+ ),
|
|
|
),
|
|
|
- isCurved: true,
|
|
|
- preventCurveOverShooting: true,
|
|
|
- color: colors.amountPrimary,
|
|
|
- barWidth: 2.5,
|
|
|
- dotData: FlDotData(
|
|
|
- show: true,
|
|
|
- getDotPainter: (spot, percent, barData, index) =>
|
|
|
- FlDotCirclePainter(
|
|
|
- radius: 3,
|
|
|
- color: colors.amountPrimary,
|
|
|
- strokeWidth: 0,
|
|
|
- ),
|
|
|
+ bottomTitles: AxisTitles(
|
|
|
+ sideTitles: SideTitles(
|
|
|
+ showTitles: true,
|
|
|
+ interval: 1,
|
|
|
+ reservedSize: 26,
|
|
|
+ getTitlesWidget: (v, meta) {
|
|
|
+ final i = v.toInt();
|
|
|
+ if (i < 0 || i >= monthLabels.length) return const SizedBox();
|
|
|
+ return Padding(
|
|
|
+ padding: const EdgeInsets.only(top: 4),
|
|
|
+ child: Text(
|
|
|
+ monthLabels[i],
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 9,
|
|
|
+ color: colors.textPlaceholder,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ },
|
|
|
+ ),
|
|
|
),
|
|
|
- belowBarData: BarAreaData(
|
|
|
- show: true,
|
|
|
- color: colors.amountPrimary.withValues(alpha: 0.08),
|
|
|
+ topTitles: const AxisTitles(
|
|
|
+ sideTitles: SideTitles(showTitles: false),
|
|
|
),
|
|
|
- ),
|
|
|
- LineChartBarData(
|
|
|
- spots: List.generate(
|
|
|
- approvedData.length,
|
|
|
- (i) => FlSpot(i.toDouble(), approvedData[i]),
|
|
|
+ rightTitles: const AxisTitles(
|
|
|
+ sideTitles: SideTitles(showTitles: false),
|
|
|
),
|
|
|
- isCurved: true,
|
|
|
- preventCurveOverShooting: true,
|
|
|
- color: colors.success,
|
|
|
- barWidth: 2.5,
|
|
|
- dotData: FlDotData(
|
|
|
- show: true,
|
|
|
- getDotPainter: (spot, percent, barData, index) =>
|
|
|
- FlDotCirclePainter(
|
|
|
- radius: 3,
|
|
|
- color: colors.success,
|
|
|
- strokeWidth: 0,
|
|
|
+ ),
|
|
|
+ borderData: FlBorderData(show: false),
|
|
|
+ minY: 0,
|
|
|
+ maxY: maxY,
|
|
|
+ lineTouchData: LineTouchData(
|
|
|
+ enabled: true,
|
|
|
+ touchTooltipData: LineTouchTooltipData(
|
|
|
+ fitInsideHorizontally: true,
|
|
|
+ fitInsideVertically: true,
|
|
|
+ getTooltipColor: (_) =>
|
|
|
+ colors.textPrimary.withValues(alpha: 0.85),
|
|
|
+ getTooltipItems: (spots) => spots.map((s) {
|
|
|
+ return LineTooltipItem(
|
|
|
+ '${monthLabels[s.spotIndex]}\n${formatAmount(s.y)}',
|
|
|
+ const TextStyle(
|
|
|
+ color: Colors.white,
|
|
|
+ fontSize: 12,
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
),
|
|
|
- ),
|
|
|
- belowBarData: BarAreaData(
|
|
|
- show: true,
|
|
|
- color: colors.success.withValues(alpha: 0.08),
|
|
|
+ );
|
|
|
+ }).toList(),
|
|
|
),
|
|
|
),
|
|
|
- ],
|
|
|
+ lineBarsData: [
|
|
|
+ LineChartBarData(
|
|
|
+ spots: List.generate(
|
|
|
+ amountData.length,
|
|
|
+ (i) => FlSpot(i.toDouble(), amountData[i]),
|
|
|
+ ),
|
|
|
+ isCurved: true,
|
|
|
+ preventCurveOverShooting: true,
|
|
|
+ color: colors.amountPrimary,
|
|
|
+ barWidth: 2.5,
|
|
|
+ dotData: FlDotData(
|
|
|
+ show: true,
|
|
|
+ getDotPainter: (spot, percent, barData, index) =>
|
|
|
+ FlDotCirclePainter(
|
|
|
+ radius: 3,
|
|
|
+ color: colors.amountPrimary,
|
|
|
+ strokeWidth: 0,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ belowBarData: BarAreaData(
|
|
|
+ show: true,
|
|
|
+ color: colors.amountPrimary.withValues(alpha: 0.08),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ LineChartBarData(
|
|
|
+ spots: List.generate(
|
|
|
+ approvedData.length,
|
|
|
+ (i) => FlSpot(i.toDouble(), approvedData[i]),
|
|
|
+ ),
|
|
|
+ isCurved: true,
|
|
|
+ preventCurveOverShooting: true,
|
|
|
+ color: colors.success,
|
|
|
+ barWidth: 2.5,
|
|
|
+ dotData: FlDotData(
|
|
|
+ show: true,
|
|
|
+ getDotPainter: (spot, percent, barData, index) =>
|
|
|
+ FlDotCirclePainter(
|
|
|
+ radius: 3,
|
|
|
+ color: colors.success,
|
|
|
+ strokeWidth: 0,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ belowBarData: BarAreaData(
|
|
|
+ show: true,
|
|
|
+ color: colors.success.withValues(alpha: 0.08),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
),
|
|
|
);
|
|
|
}
|
|
|
@@ -637,7 +666,12 @@ class _ExpenseDetailReportPageState
|
|
|
if (_subordinateLoading && _subordinateData.isEmpty) {
|
|
|
return const Padding(
|
|
|
padding: EdgeInsets.only(top: 16),
|
|
|
- child: Center(child: TDLoading(size: TDLoadingSize.small, icon: TDLoadingIcon.activity)),
|
|
|
+ child: Center(
|
|
|
+ child: TDLoading(
|
|
|
+ size: TDLoadingSize.small,
|
|
|
+ icon: TDLoadingIcon.activity,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
);
|
|
|
}
|
|
|
if (_subordinateData.isEmpty) return const SizedBox.shrink();
|
|
|
@@ -650,14 +684,24 @@ class _ExpenseDetailReportPageState
|
|
|
decoration: BoxDecoration(
|
|
|
color: colors.bgCard,
|
|
|
borderRadius: BorderRadius.circular(8),
|
|
|
- boxShadow: const [BoxShadow(color: Color(0x08000000), blurRadius: 4, offset: Offset(0, 1))],
|
|
|
+ boxShadow: const [
|
|
|
+ BoxShadow(
|
|
|
+ color: Color(0x08000000),
|
|
|
+ blurRadius: 4,
|
|
|
+ offset: Offset(0, 1),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
),
|
|
|
child: Column(
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
children: [
|
|
|
Text(
|
|
|
l10n.get('chartTitle8'),
|
|
|
- style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: colors.textPrimary),
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 14,
|
|
|
+ fontWeight: FontWeight.w600,
|
|
|
+ color: colors.textPrimary,
|
|
|
+ ),
|
|
|
),
|
|
|
const SizedBox(height: 16),
|
|
|
SizedBox(
|
|
|
@@ -665,51 +709,143 @@ class _ExpenseDetailReportPageState
|
|
|
child: SingleChildScrollView(
|
|
|
scrollDirection: Axis.horizontal,
|
|
|
child: SizedBox(
|
|
|
- width: (_subordinateData.length * 60.0).clamp(MediaQuery.of(context).size.width - 56, double.infinity),
|
|
|
- child: BarChart(
|
|
|
- BarChartData(
|
|
|
- alignment: _subordinateData.length == 1 ? BarChartAlignment.center : BarChartAlignment.spaceAround,
|
|
|
- maxY: (_subordinateData.map((e) => e.amount).reduce((a, b) => a > b ? a : b) * 1.2).clamp(1, double.infinity),
|
|
|
- barGroups: _subordinateData.asMap().entries.map((e) {
|
|
|
- final barColors = [colors.chart1, colors.chart2, colors.chart3, colors.chart4, colors.chart5, colors.primary, colors.success, colors.warning, colors.infoText, colors.danger];
|
|
|
- return BarChartGroupData(
|
|
|
- x: e.key,
|
|
|
- barRods: [BarChartRodData(toY: e.value.amount, color: barColors[e.key % barColors.length], width: _subordinateData.length == 1 ? 40 : 20, borderRadius: const BorderRadius.vertical(top: Radius.circular(4)))],
|
|
|
- );
|
|
|
- }).toList(),
|
|
|
- titlesData: FlTitlesData(
|
|
|
- leftTitles: AxisTitles(
|
|
|
- sideTitles: SideTitles(showTitles: true, reservedSize: 80, interval: (_subordinateData.map((e) => e.amount).reduce((a, b) => a > b ? a : b) * 1.2).clamp(1, double.infinity) / 4, getTitlesWidget: (v, _) => Text(formatAmount(v), style: TextStyle(fontSize: 10, color: colors.textPlaceholder))),
|
|
|
- ),
|
|
|
- bottomTitles: AxisTitles(
|
|
|
- sideTitles: SideTitles(
|
|
|
- showTitles: true,
|
|
|
- reservedSize: 40,
|
|
|
- getTitlesWidget: (v, _) {
|
|
|
- final i = v.toInt();
|
|
|
- if (i < 0 || i >= _subordinateData.length) return const SizedBox();
|
|
|
- return Padding(
|
|
|
- padding: const EdgeInsets.only(top: 4),
|
|
|
- child: Text(
|
|
|
- _subordinateData[i].usrName.length > 4 ? '${_subordinateData[i].usrName.substring(0, 4)}…' : _subordinateData[i].usrName,
|
|
|
- style: TextStyle(fontSize: 9, color: colors.textPlaceholder),
|
|
|
- maxLines: 2,
|
|
|
- overflow: TextOverflow.ellipsis,
|
|
|
- ),
|
|
|
+ width: (_subordinateData.length * 60.0).clamp(
|
|
|
+ MediaQuery.of(context).size.width - 56,
|
|
|
+ double.infinity,
|
|
|
+ ),
|
|
|
+ child: Padding(
|
|
|
+ padding: const EdgeInsets.only(top: 8),
|
|
|
+ child: BarChart(
|
|
|
+ BarChartData(
|
|
|
+ alignment: _subordinateData.length == 1
|
|
|
+ ? BarChartAlignment.center
|
|
|
+ : BarChartAlignment.spaceAround,
|
|
|
+ maxY:
|
|
|
+ (_subordinateData
|
|
|
+ .map((e) => e.amount)
|
|
|
+ .reduce((a, b) => a > b ? a : b) *
|
|
|
+ 1.2)
|
|
|
+ .clamp(1, double.infinity),
|
|
|
+ barTouchData: BarTouchData(
|
|
|
+ enabled: true,
|
|
|
+ touchTooltipData: BarTouchTooltipData(
|
|
|
+ fitInsideHorizontally: true,
|
|
|
+ fitInsideVertically: true,
|
|
|
+ getTooltipColor: (_) =>
|
|
|
+ colors.textPrimary.withValues(alpha: 0.85),
|
|
|
+ getTooltipItem: (group, groupIndex, rod, rodIndex) {
|
|
|
+ final item = _subordinateData[group.x];
|
|
|
+ return BarTooltipItem(
|
|
|
+ '${item.usrName}\n${formatAmount(rod.toY)}',
|
|
|
+ const TextStyle(
|
|
|
+ color: Colors.white,
|
|
|
+ fontSize: 12,
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ barGroups: _subordinateData.asMap().entries.map((e) {
|
|
|
+ final barColors = [
|
|
|
+ colors.chart1,
|
|
|
+ colors.chart2,
|
|
|
+ colors.chart3,
|
|
|
+ colors.chart4,
|
|
|
+ colors.chart5,
|
|
|
+ colors.primary,
|
|
|
+ colors.success,
|
|
|
+ colors.warning,
|
|
|
+ colors.infoText,
|
|
|
+ colors.danger,
|
|
|
+ ];
|
|
|
+ return BarChartGroupData(
|
|
|
+ x: e.key,
|
|
|
+ barRods: [
|
|
|
+ BarChartRodData(
|
|
|
+ toY: e.value.amount,
|
|
|
+ color: barColors[e.key % barColors.length],
|
|
|
+ width: _subordinateData.length == 1 ? 40 : 20,
|
|
|
+ borderRadius: const BorderRadius.vertical(
|
|
|
+ top: Radius.circular(4),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
);
|
|
|
- },
|
|
|
+ }).toList(),
|
|
|
+ titlesData: FlTitlesData(
|
|
|
+ leftTitles: AxisTitles(
|
|
|
+ sideTitles: SideTitles(
|
|
|
+ showTitles: true,
|
|
|
+ reservedSize: 80,
|
|
|
+ interval:
|
|
|
+ (_subordinateData
|
|
|
+ .map((e) => e.amount)
|
|
|
+ .reduce((a, b) => a > b ? a : b) *
|
|
|
+ 1.2)
|
|
|
+ .clamp(1, double.infinity) /
|
|
|
+ 4,
|
|
|
+ getTitlesWidget: (v, _) => Text(
|
|
|
+ formatAmount(v),
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 10,
|
|
|
+ color: colors.textPlaceholder,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ bottomTitles: AxisTitles(
|
|
|
+ sideTitles: SideTitles(
|
|
|
+ showTitles: true,
|
|
|
+ reservedSize: 40,
|
|
|
+ getTitlesWidget: (v, _) {
|
|
|
+ final i = v.toInt();
|
|
|
+ if (i < 0 || i >= _subordinateData.length)
|
|
|
+ return const SizedBox();
|
|
|
+ return Padding(
|
|
|
+ padding: const EdgeInsets.only(top: 4),
|
|
|
+ child: Text(
|
|
|
+ _subordinateData[i].usrName.length > 4
|
|
|
+ ? '${_subordinateData[i].usrName.substring(0, 4)}…'
|
|
|
+ : _subordinateData[i].usrName,
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 9,
|
|
|
+ color: colors.textPlaceholder,
|
|
|
+ ),
|
|
|
+ maxLines: 2,
|
|
|
+ overflow: TextOverflow.ellipsis,
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ topTitles: const AxisTitles(
|
|
|
+ sideTitles: SideTitles(showTitles: false),
|
|
|
+ ),
|
|
|
+ rightTitles: const AxisTitles(
|
|
|
+ sideTitles: SideTitles(showTitles: false),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ borderData: FlBorderData(show: false),
|
|
|
+ gridData: FlGridData(
|
|
|
+ show: true,
|
|
|
+ drawVerticalLine: false,
|
|
|
+ horizontalInterval:
|
|
|
+ (_subordinateData
|
|
|
+ .map((e) => e.amount)
|
|
|
+ .reduce((a, b) => a > b ? a : b) *
|
|
|
+ 1.2)
|
|
|
+ .clamp(1, double.infinity) /
|
|
|
+ 5,
|
|
|
+ getDrawingHorizontalLine: (v) =>
|
|
|
+ FlLine(color: colors.border, strokeWidth: 0.5),
|
|
|
+ ),
|
|
|
),
|
|
|
),
|
|
|
- topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
|
|
- rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
|
|
),
|
|
|
- borderData: FlBorderData(show: false),
|
|
|
- gridData: FlGridData(show: true, drawVerticalLine: false, horizontalInterval: (_subordinateData.map((e) => e.amount).reduce((a, b) => a > b ? a : b) * 1.2).clamp(1, double.infinity) / 5, getDrawingHorizontalLine: (v) => FlLine(color: colors.border, strokeWidth: 0.5)),
|
|
|
),
|
|
|
),
|
|
|
),
|
|
|
- ),
|
|
|
- ),
|
|
|
],
|
|
|
),
|
|
|
),
|
|
|
@@ -828,7 +964,11 @@ class _ExpenseDetailReportPageState
|
|
|
child: Column(
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
children: [
|
|
|
- Icon(Icons.inbox_outlined, size: 48, color: colors.textPlaceholder),
|
|
|
+ Icon(
|
|
|
+ Icons.inbox_outlined,
|
|
|
+ size: 48,
|
|
|
+ color: colors.textPlaceholder,
|
|
|
+ ),
|
|
|
const SizedBox(height: 12),
|
|
|
Text(
|
|
|
l10n.get('noDetailData'),
|
|
|
@@ -981,7 +1121,10 @@ class _ExpenseDetailReportPageState
|
|
|
Align(
|
|
|
alignment: Alignment.centerRight,
|
|
|
child: Container(
|
|
|
- padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 1),
|
|
|
+ padding: const EdgeInsets.symmetric(
|
|
|
+ horizontal: 6,
|
|
|
+ vertical: 1,
|
|
|
+ ),
|
|
|
decoration: BoxDecoration(
|
|
|
color: colors.primary.withValues(alpha: 0.1),
|
|
|
borderRadius: BorderRadius.circular(4),
|
|
|
@@ -989,7 +1132,11 @@ class _ExpenseDetailReportPageState
|
|
|
),
|
|
|
child: Text(
|
|
|
l10n.get('statusTransferred'),
|
|
|
- style: TextStyle(fontSize: 11, fontWeight: FontWeight.w500, color: colors.primary),
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 11,
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
+ color: colors.primary,
|
|
|
+ ),
|
|
|
),
|
|
|
),
|
|
|
),
|
|
|
@@ -1001,5 +1148,4 @@ class _ExpenseDetailReportPageState
|
|
|
],
|
|
|
);
|
|
|
}
|
|
|
-
|
|
|
}
|