Просмотр исходного кода

fix #19900 #19888 加班申请单、用车申请单

chengc 2 недель назад
Родитель
Сommit
ad0ac30b37

+ 10 - 6
assets/i18n/en.json

@@ -252,10 +252,12 @@
     "tdEmptyData": "No Data",
     "tdEmptyData": "No Data",
     "basicInfo": "Basic Info",
     "basicInfo": "Basic Info",
     "noDetailData": "No detail data",
     "noDetailData": "No detail data",
+    "noChartData": "No comparison data",
     "unitItem": "items",
     "unitItem": "items",
     "unitCount": "times",
     "unitCount": "times",
     "unitYuan": "yuan",
     "unitYuan": "yuan",
     "unitKm": "km",
     "unitKm": "km",
+    "unitHours": "h",
     "personUnit": "persons"
     "personUnit": "persons"
   },
   },
   "home": {
   "home": {
@@ -671,8 +673,8 @@
     "selectVehicleType": "Select Vehicle Type",
     "selectVehicleType": "Select Vehicle Type",
     "brand": "Brand",
     "brand": "Brand",
     "seats": "Seats",
     "seats": "Seats",
-    "odometerBegin": "Odometer",
-    "odometerEnd": "Return Odometer",
+    "odometerBegin": "Odometer(km)",
+    "odometerEnd": "Return Odometer(km)",
     "driverName": "Driver Name",
     "driverName": "Driver Name",
     "returnCarInfo": "Return Info",
     "returnCarInfo": "Return Info",
     "costRemark": "Cost Remark",
     "costRemark": "Cost Remark",
@@ -822,8 +824,8 @@
   "report": {
   "report": {
     "reports": "Reports",
     "reports": "Reports",
     "chartTitle1": "Expense & Approved Amount Trend",
     "chartTitle1": "Expense & Approved Amount Trend",
-    "chartTitle2": "Overtime Hours Trend (Last 12 Months)",
-    "chartTitle3": "Vehicle Trips vs Total Cost (Last 12 Months)",
+    "chartTitle2": "Overtime Hours Trend",
+    "chartTitle3": "Vehicle Trips Trend",
     "chartTitle4": "Monthly Trend",
     "chartTitle4": "Monthly Trend",
     "chartTitle5": "Visits vs Avg Rating (Last 12 Months)",
     "chartTitle5": "Visits vs Avg Rating (Last 12 Months)",
     "chartTitle6": "Apply Amount Trend",
     "chartTitle6": "Apply Amount Trend",
@@ -851,8 +853,8 @@
     "statTransferredAmount": "Transferred Amount",
     "statTransferredAmount": "Transferred Amount",
     "statMonthHours": "This Month Net Hours",
     "statMonthHours": "This Month Net Hours",
     "statMonthTrips": "This Month Trips",
     "statMonthTrips": "This Month Trips",
-    "statTotalMileage": "Total Mileage",
-    "statTotalCost": "Tolls & Parking",
+    "statTotalMileage": "Total Mileage(km)",
+    "statTotalCost": "Actual Cost",
     "statNotReturned": "Not Returned",
     "statNotReturned": "Not Returned",
     "statMonthVisits": "This Month Visits",
     "statMonthVisits": "This Month Visits",
     "statVisitedCustomers": "Customers Visited",
     "statVisitedCustomers": "Customers Visited",
@@ -868,6 +870,8 @@
     "settleCount": "Settlement Count",
     "settleCount": "Settlement Count",
     "monthVehicle": "This Month Vehicle",
     "monthVehicle": "This Month Vehicle",
     "totalMileage": "Total Mileage",
     "totalMileage": "Total Mileage",
+    "statTotalTrips": "Total Trips",
+    "chartTitle7": "Person Vehicle Trips Comparison",
     "totalCost": "Total Cost",
     "totalCost": "Total Cost",
     "notReturned": "Not Returned",
     "notReturned": "Not Returned",
     "yearTotalApp": "Total Amount",
     "yearTotalApp": "Total Amount",

+ 10 - 6
assets/i18n/zh_CN.json

@@ -252,10 +252,12 @@
     "tdEmptyData": "暂无数据",
     "tdEmptyData": "暂无数据",
     "basicInfo": "基本信息",
     "basicInfo": "基本信息",
     "noDetailData": "暂无明细数据",
     "noDetailData": "暂无明细数据",
+    "noChartData": "暂无对比数据",
     "unitItem": "笔",
     "unitItem": "笔",
     "unitCount": "次",
     "unitCount": "次",
     "unitYuan": "元",
     "unitYuan": "元",
     "unitKm": "公里",
     "unitKm": "公里",
+    "unitHours": "小时",
     "personUnit": "人"
     "personUnit": "人"
   },
   },
   "home": {
   "home": {
@@ -671,8 +673,8 @@
     "selectVehicleType": "选择车辆类型",
     "selectVehicleType": "选择车辆类型",
     "brand": "品牌型号",
     "brand": "品牌型号",
     "seats": "核定座位数",
     "seats": "核定座位数",
-    "odometerBegin": "出发前里程",
-    "odometerEnd": "还车里程",
+    "odometerBegin": "出发前里程(km)",
+    "odometerEnd": "还车里程(km)",
     "driverName": "默认驾驶员",
     "driverName": "默认驾驶员",
     "returnCarInfo": "还车信息",
     "returnCarInfo": "还车信息",
     "costRemark": "费用备注",
     "costRemark": "费用备注",
@@ -822,12 +824,13 @@
   "report": {
   "report": {
     "reports": "报表",
     "reports": "报表",
     "chartTitle1": "报销金额与核准金额趋势",
     "chartTitle1": "报销金额与核准金额趋势",
-    "chartTitle2": "近12个月加班工时趋势",
-    "chartTitle3": "近12个月用车次数 vs 累计费用",
+    "chartTitle2": "加班工时趋势",
+    "chartTitle3": "用车次数趋势",
     "chartTitle4": "近12个月申请金额 vs 已通过金额",
     "chartTitle4": "近12个月申请金额 vs 已通过金额",
     "chartTitle5": "近12个月拜访次数 vs 平均评分",
     "chartTitle5": "近12个月拜访次数 vs 平均评分",
     "chartTitle6": "申请金额趋势",
     "chartTitle6": "申请金额趋势",
     "chartTitle8": "人员报销金额对比",
     "chartTitle8": "人员报销金额对比",
+    "chartTitle7": "人员用车次数对比",
     "chartTitleOT": "人员加班时数对比",
     "chartTitleOT": "人员加班时数对比",
     "chartDesc1": "双折线对比图",
     "chartDesc1": "双折线对比图",
     "chartDesc2": "柱状趋势图",
     "chartDesc2": "柱状趋势图",
@@ -851,8 +854,9 @@
     "statTransferredAmount": "已转报销金额",
     "statTransferredAmount": "已转报销金额",
     "statMonthHours": "当月净工时",
     "statMonthHours": "当月净工时",
     "statMonthTrips": "当月次数",
     "statMonthTrips": "当月次数",
-    "statTotalMileage": "累计里程",
-    "statTotalCost": "路桥停车费",
+    "statTotalMileage": "累计里程(km)",
+    "statTotalCost": "实际费用",
+    "statTotalTrips": "总出车次数",
     "statNotReturned": "未还车数",
     "statNotReturned": "未还车数",
     "statMonthVisits": "当月拜访次数",
     "statMonthVisits": "当月拜访次数",
     "statVisitedCustomers": "拜访客户数",
     "statVisitedCustomers": "拜访客户数",

+ 10 - 6
assets/i18n/zh_TW.json

@@ -252,10 +252,12 @@
     "tdEmptyData": "暫無數據",
     "tdEmptyData": "暫無數據",
     "basicInfo": "基本信息",
     "basicInfo": "基本信息",
     "noDetailData": "暫無明細數據",
     "noDetailData": "暫無明細數據",
+    "noChartData": "暫無對比數據",
     "unitItem": "笔",
     "unitItem": "笔",
     "unitCount": "次",
     "unitCount": "次",
     "unitYuan": "元",
     "unitYuan": "元",
     "unitKm": "公里",
     "unitKm": "公里",
+    "unitHours": "小時",
     "personUnit": "人"
     "personUnit": "人"
   },
   },
   "home": {
   "home": {
@@ -671,8 +673,8 @@
     "selectVehicleType": "選擇車輛類型",
     "selectVehicleType": "選擇車輛類型",
     "brand": "品牌型號",
     "brand": "品牌型號",
     "seats": "核定座位數",
     "seats": "核定座位數",
-    "odometerBegin": "出發前里程",
-    "odometerEnd": "還車里程",
+    "odometerBegin": "出發前里程(km)",
+    "odometerEnd": "還車里程(km)",
     "driverName": "默認駕駛員",
     "driverName": "默認駕駛員",
     "returnCarInfo": "還車資訊",
     "returnCarInfo": "還車資訊",
     "costRemark": "費用備註",
     "costRemark": "費用備註",
@@ -822,8 +824,8 @@
   "report": {
   "report": {
     "reports": "報表",
     "reports": "報表",
     "chartTitle1": "報銷金額與核准金額趨勢",
     "chartTitle1": "報銷金額與核准金額趨勢",
-    "chartTitle2": "近12個月加班工時趋势",
-    "chartTitle3": "近12個月用車次數 vs 累計費用",
+    "chartTitle2": "加班工時趋势",
+    "chartTitle3": "用車次數趋势",
     "chartTitle4": "近12個月申請金額 vs 已通過金額",
     "chartTitle4": "近12個月申請金額 vs 已通過金額",
     "chartTitle5": "近12個月拜訪次數 vs 平均評分",
     "chartTitle5": "近12個月拜訪次數 vs 平均評分",
     "chartTitle6": "申請金額趨勢",
     "chartTitle6": "申請金額趨勢",
@@ -851,8 +853,10 @@
     "statTransferredAmount": "已轉報銷金額",
     "statTransferredAmount": "已轉報銷金額",
     "statMonthHours": "当月净工時",
     "statMonthHours": "当月净工時",
     "statMonthTrips": "当月次數",
     "statMonthTrips": "当月次數",
-    "statTotalMileage": "累計里程",
-    "statTotalCost": "路桥停車費",
+    "statTotalMileage": "累計里程(km)",
+    "statTotalCost": "实際費用",
+    "statTotalTrips": "總出車次數",
+    "chartTitle7": "人員用車次數對比",
     "statNotReturned": "未還車數",
     "statNotReturned": "未還車數",
     "statMonthVisits": "当月拜訪次數",
     "statMonthVisits": "当月拜訪次數",
     "statVisitedCustomers": "拜訪客戶數",
     "statVisitedCustomers": "拜訪客戶數",

+ 2 - 0
lib/core/router/app_router.dart

@@ -182,6 +182,7 @@ GoRouter createAppRouter() => GoRouter(
         child: AppScaffold(
         child: AppScaffold(
           navConfig: NavBarConfig(showBack: true),
           navConfig: NavBarConfig(showBack: true),
           body: const OvertimeApplyCreatePage(),
           body: const OvertimeApplyCreatePage(),
+          resizeToAvoidBottomInset: false,
         ),
         ),
       ),
       ),
     ),
     ),
@@ -241,6 +242,7 @@ GoRouter createAppRouter() => GoRouter(
         child: AppScaffold(
         child: AppScaffold(
           navConfig: NavBarConfig(showBack: true),
           navConfig: NavBarConfig(showBack: true),
           body: const VehicleApplyCreatePage(),
           body: const VehicleApplyCreatePage(),
+          resizeToAvoidBottomInset: false,
         ),
         ),
       ),
       ),
     ),
     ),

+ 3 - 0
lib/features/overtime/ot_report_model.dart

@@ -105,6 +105,7 @@ class OTReportDetailItem {
   final double hours;
   final double hours;
   final String jbType;
   final String jbType;
   final String compensationType;
   final String compensationType;
+  final String reason;
 
 
   const OTReportDetailItem({
   const OTReportDetailItem({
     this.billNo = '',
     this.billNo = '',
@@ -113,6 +114,7 @@ class OTReportDetailItem {
     this.hours = 0,
     this.hours = 0,
     this.jbType = '',
     this.jbType = '',
     this.compensationType = '',
     this.compensationType = '',
+    this.reason = '',
   });
   });
 
 
   factory OTReportDetailItem.fromJson(Map<String, dynamic> json) {
   factory OTReportDetailItem.fromJson(Map<String, dynamic> json) {
@@ -123,6 +125,7 @@ class OTReportDetailItem {
       hours: (json['hours'] as num?)?.toDouble() ?? 0,
       hours: (json['hours'] as num?)?.toDouble() ?? 0,
       jbType: json['jbType'] as String? ?? '',
       jbType: json['jbType'] as String? ?? '',
       compensationType: json['compensationType'] as String? ?? '',
       compensationType: json['compensationType'] as String? ?? '',
+      reason: json['reason'] as String? ?? '',
     );
     );
   }
   }
 }
 }

+ 36 - 7
lib/features/report/overtime_detail_report_page.dart

@@ -337,7 +337,7 @@ class _OvertimeDetailReportPageState
               Expanded(
               Expanded(
                 child: _statCard(
                 child: _statCard(
                   l10n.get('statTotalOvertimeCount'),
                   l10n.get('statTotalOvertimeCount'),
-                  '${summary.totalCount} ${l10n.get('unitItem')}',
+                  '${summary.totalCount}',
                   colors.textPrimary,
                   colors.textPrimary,
                 ),
                 ),
               ),
               ),
@@ -662,7 +662,7 @@ class _OvertimeDetailReportPageState
           children: [
           children: [
             Text(l10n.get('chartTitleOT'),
             Text(l10n.get('chartTitleOT'),
                 style: TextStyle(
                 style: TextStyle(
-                  fontSize: 16,
+                  fontSize: 14,
                   fontWeight: FontWeight.w600,
                   fontWeight: FontWeight.w600,
                   color: colors.textPrimary,
                   color: colors.textPrimary,
                 )),
                 )),
@@ -703,6 +703,21 @@ class _OvertimeDetailReportPageState
                             sideTitles: SideTitles(showTitles: false)),
                             sideTitles: SideTitles(showTitles: false)),
                         rightTitles: const AxisTitles(
                         rightTitles: const AxisTitles(
                             sideTitles: SideTitles(showTitles: false)),
                             sideTitles: SideTitles(showTitles: false)),
+                        leftTitles: AxisTitles(
+                          sideTitles: SideTitles(
+                            showTitles: true,
+                            reservedSize: 36,
+                            interval: (_subordinateData
+                                    .map((e) => e.hours)
+                                    .reduce((a, b) => a > b ? a : b) *
+                                1.3) / 4,
+                            getTitlesWidget: (v, _) => Text(
+                              v.toInt().toString(),
+                              style: TextStyle(
+                                  fontSize: 10, color: colors.textPlaceholder),
+                            ),
+                          ),
+                        ),
                         bottomTitles: AxisTitles(
                         bottomTitles: AxisTitles(
                           sideTitles: SideTitles(
                           sideTitles: SideTitles(
                             showTitles: true,
                             showTitles: true,
@@ -728,7 +743,12 @@ class _OvertimeDetailReportPageState
                         ),
                         ),
                       ),
                       ),
                       borderData: FlBorderData(show: false),
                       borderData: FlBorderData(show: false),
-                      gridData: const FlGridData(show: false),
+                      gridData: FlGridData(
+                        show: true,
+                        drawVerticalLine: false,
+                        getDrawingHorizontalLine: (v) =>
+                            FlLine(color: colors.border.withValues(alpha: 0.3), strokeWidth: 0.5),
+                      ),
                       barTouchData: BarTouchData(
                       barTouchData: BarTouchData(
                         touchTooltipData: BarTouchTooltipData(
                         touchTooltipData: BarTouchTooltipData(
                           getTooltipItem: (group, groupIndex, rod, rodIndex) {
                           getTooltipItem: (group, groupIndex, rod, rodIndex) {
@@ -736,8 +756,8 @@ class _OvertimeDetailReportPageState
                                 _subordinateData[group.x.toInt()];
                                 _subordinateData[group.x.toInt()];
                             return BarTooltipItem(
                             return BarTooltipItem(
                               '${item.usrName}\n${item.hours}',
                               '${item.usrName}\n${item.hours}',
-                              TextStyle(
-                                  color: colors.textPrimary,
+                              const TextStyle(
+                                  color: Colors.white,
                                   fontSize: 12),
                                   fontSize: 12),
                             );
                             );
                           },
                           },
@@ -897,13 +917,13 @@ class _OvertimeDetailReportPageState
                   ),
                   ),
                   const SizedBox(width: 12),
                   const SizedBox(width: 12),
                   Text(
                   Text(
-                    d.hours.toStringAsFixed(1),
+                    '${d.hours.toStringAsFixed(1)}${l10n.get('unitHours')}',
                     maxLines: 1,
                     maxLines: 1,
                     overflow: TextOverflow.ellipsis,
                     overflow: TextOverflow.ellipsis,
                     style: TextStyle(
                     style: TextStyle(
                       fontSize: 16,
                       fontSize: 16,
                       fontWeight: FontWeight.w700,
                       fontWeight: FontWeight.w700,
-                      color: colors.amountPrimary,
+                      color: colors.timePrimary,
                     ),
                     ),
                   ),
                   ),
                 ],
                 ],
@@ -969,6 +989,15 @@ class _OvertimeDetailReportPageState
                     ),
                     ),
                 ],
                 ],
               ),
               ),
+              if (d.reason.isNotEmpty) ...[
+                const SizedBox(height: 6),
+                Text(
+                  d.reason,
+                  maxLines: 2,
+                  overflow: TextOverflow.ellipsis,
+                  style: TextStyle(fontSize: 12, color: colors.textSecondary),
+                ),
+              ],
             ],
             ],
           ),
           ),
         ),
         ),

Разница между файлами не показана из-за своего большого размера
+ 464 - 330
lib/features/report/vehicle_detail_report_page.dart


+ 24 - 4
lib/features/vehicle/vehicle_apply_api.dart

@@ -178,8 +178,8 @@ class VehicleApplyApi {
     return response.data!;
     return response.data!;
   }
   }
 
 
-  /// 用车报表汇总+月度数据
-  Future<VehicleReportData> getVehicleReport({
+  /// 用车报表汇总
+  Future<VehicleReportSummary> getVehicleReportSummary({
     String startDate = '',
     String startDate = '',
     String endDate = '',
     String endDate = '',
   }) async {
   }) async {
@@ -187,10 +187,30 @@ class VehicleApplyApi {
     if (startDate.isNotEmpty) params['startDate'] = startDate;
     if (startDate.isNotEmpty) params['startDate'] = startDate;
     if (endDate.isNotEmpty) params['endDate'] = endDate;
     if (endDate.isNotEmpty) params['endDate'] = endDate;
     final response = await _client.get<Map<String, dynamic>>(
     final response = await _client.get<Map<String, dynamic>>(
-      '/OA/GetVehicleReport',
+      '/OA/GetVehicleReportSummary',
       queryParameters: params,
       queryParameters: params,
     );
     );
-    return VehicleReportData.fromJson(response.data!);
+    return VehicleReportSummary.fromJson(response.data!);
+  }
+
+  /// 用车报表月度数据
+  Future<List<VehicleMonthlyItem>> getVehicleReportMonthly({
+    String startDate = '',
+    String endDate = '',
+  }) async {
+    final params = <String, dynamic>{};
+    if (startDate.isNotEmpty) params['startDate'] = startDate;
+    if (endDate.isNotEmpty) params['endDate'] = endDate;
+    final response = await _client.get<dynamic>(
+      '/OA/GetVehicleReportMonthly',
+      queryParameters: params,
+    );
+    final list =
+        (response.data as List<dynamic>?)
+            ?.map((e) => VehicleMonthlyItem.fromJson(e as Map<String, dynamic>))
+            .toList() ??
+        [];
+    return list;
   }
   }
 
 
   /// 用车报表下属对比
   /// 用车报表下属对比

+ 2 - 2
lib/features/vehicle/vehicle_apply_list_page.dart

@@ -367,9 +367,9 @@ class _VehicleApplyListContent extends ConsumerWidget {
         : (m.applicantName.isNotEmpty ? m.applicantName : m.salNo);
         : (m.applicantName.isNotEmpty ? m.applicantName : m.salNo);
     final deptLabel = m.deptName.isNotEmpty ? m.deptName : m.dep;
     final deptLabel = m.deptName.isNotEmpty ? m.deptName : m.dep;
     final hasRoute =
     final hasRoute =
-        m.originAdr.isNotEmpty || m.destAdr.isNotEmpty;
+        m.originAdr.isNotEmpty && m.destAdr.isNotEmpty;
     final routeText = hasRoute
     final routeText = hasRoute
-        ? '${m.originAdr.isNotEmpty ? m.originAdr : '?'} → ${m.destAdr.isNotEmpty ? m.destAdr : '?'}'
+        ? '${m.originAdr} → ${m.destAdr}'
         : '';
         : '';
     final descParts = <String>[];
     final descParts = <String>[];
     if (m.reason.isNotEmpty) descParts.add(m.reason);
     if (m.reason.isNotEmpty) descParts.add(m.reason);

+ 3 - 0
lib/features/vehicle/vehicle_report_model.dart

@@ -110,6 +110,7 @@ class VehicleReportDetailItem {
   final String originAdr;
   final String originAdr;
   final String destAdr;
   final String destAdr;
   final double mileage;
   final double mileage;
+  final String reason;
 
 
   const VehicleReportDetailItem({
   const VehicleReportDetailItem({
     this.billNo = '',
     this.billNo = '',
@@ -119,6 +120,7 @@ class VehicleReportDetailItem {
     this.originAdr = '',
     this.originAdr = '',
     this.destAdr = '',
     this.destAdr = '',
     this.mileage = 0,
     this.mileage = 0,
+    this.reason = '',
   });
   });
 
 
   factory VehicleReportDetailItem.fromJson(Map<String, dynamic> json) {
   factory VehicleReportDetailItem.fromJson(Map<String, dynamic> json) {
@@ -130,6 +132,7 @@ class VehicleReportDetailItem {
       originAdr: json['originAdr'] as String? ?? '',
       originAdr: json['originAdr'] as String? ?? '',
       destAdr: json['destAdr'] as String? ?? '',
       destAdr: json['destAdr'] as String? ?? '',
       mileage: (json['mileage'] as num?)?.toDouble() ?? 0,
       mileage: (json['mileage'] as num?)?.toDouble() ?? 0,
+      reason: json['reason'] as String? ?? '',
     );
     );
   }
   }
 }
 }

+ 3 - 3
lib/shared/widgets/bill_status_bar.dart

@@ -174,7 +174,7 @@ class BillStatusBar {
               child: TDButton(
               child: TDButton(
                 icon: TDIcons.edit,
                 icon: TDIcons.edit,
                 text: _editLabel(),
                 text: _editLabel(),
-                size: TDButtonSize.large,
+                size: TDButtonSize.medium,
                 type: TDButtonType.outline,
                 type: TDButtonType.outline,
                 shape: TDButtonShape.rectangle,
                 shape: TDButtonShape.rectangle,
                 theme: TDButtonTheme.primary,
                 theme: TDButtonTheme.primary,
@@ -189,7 +189,7 @@ class BillStatusBar {
               child: TDButton(
               child: TDButton(
                 icon: TDIcons.send,
                 icon: TDIcons.send,
                 text: _submitLabel(),
                 text: _submitLabel(),
-                size: TDButtonSize.large,
+                size: TDButtonSize.medium,
                 type: TDButtonType.fill,
                 type: TDButtonType.fill,
                 shape: TDButtonShape.rectangle,
                 shape: TDButtonShape.rectangle,
                 theme: TDButtonTheme.primary,
                 theme: TDButtonTheme.primary,
@@ -201,7 +201,7 @@ class BillStatusBar {
               child: TDButton(
               child: TDButton(
                 icon: TDIcons.rollback,
                 icon: TDIcons.rollback,
                 text: _cancelSubmitLabel(),
                 text: _cancelSubmitLabel(),
-                size: TDButtonSize.large,
+                size: TDButtonSize.medium,
                 type: TDButtonType.fill,
                 type: TDButtonType.fill,
                 shape: TDButtonShape.rectangle,
                 shape: TDButtonShape.rectangle,
                 theme: TDButtonTheme.danger,
                 theme: TDButtonTheme.danger,

Некоторые файлы не были показаны из-за большого количества измененных файлов