overtime_detail_page.dart 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_riverpod/flutter_riverpod.dart';
  3. import '../../core/theme/app_colors.dart';
  4. import '../../core/utils/date_utils.dart' as du;
  5. import '../../core/utils/responsive.dart';
  6. import '../../shared/models/approval_status.dart';
  7. import '../../shared/widgets/form_section.dart';
  8. import '../../shared/widgets/form_field_row.dart';
  9. import '../../shared/widgets/status_tag.dart';
  10. import 'overtime_model.dart';
  11. final overtimeDetailProvider = FutureProvider.autoDispose.family<OvertimeModel, String>((ref, id) async {
  12. await Future.delayed(const Duration(milliseconds: 300));
  13. return OvertimeModel(
  14. id: id,
  15. applicationNo: 'OT202605001',
  16. applicantId: 'u-001',
  17. applicantName: '张三',
  18. deptId: 'dept-001',
  19. deptName: '市场部',
  20. otDate: DateTime(2026, 5, 20),
  21. startTime: DateTime(2026, 5, 20, 18, 0),
  22. endTime: DateTime(2026, 5, 20, 21, 0),
  23. otHours: 3.0,
  24. otType: '工作日加班',
  25. compensationType: '加班费',
  26. reason: '项目上线前紧急测试',
  27. status: 'pending',
  28. createTime: DateTime(2026, 5, 20),
  29. updateTime: DateTime(2026, 5, 20),
  30. approvalRecords: [
  31. ApprovalRecord(
  32. id: 'ar-ot-001',
  33. bizId: id,
  34. bizType: 'overtime',
  35. approverId: 'u-mgr',
  36. approverName: '李四',
  37. approvalLevel: 1,
  38. action: 'pending',
  39. opinion: '',
  40. approvalTime: DateTime(2026, 5, 20),
  41. ),
  42. ],
  43. );
  44. });
  45. class OvertimeDetailPage extends ConsumerWidget {
  46. final String id;
  47. const OvertimeDetailPage({super.key, required this.id});
  48. @override
  49. Widget build(BuildContext context, WidgetRef ref) {
  50. final detailAsync = ref.watch(overtimeDetailProvider(id));
  51. final r = ResponsiveHelper.of(context);
  52. return Scaffold(
  53. appBar: AppBar(title: const Text('加班详情')),
  54. body: detailAsync.when(
  55. loading: () => const Center(child: CircularProgressIndicator()),
  56. error: (_, __) => const Center(child: Text('加载失败')),
  57. data: (o) => Center(
  58. child: ConstrainedBox(
  59. constraints: BoxConstraints(maxWidth: r.detailTwoColumns ? 700 : double.infinity),
  60. child: SingleChildScrollView(
  61. padding: const EdgeInsets.symmetric(vertical: 8),
  62. child: FormSection(
  63. title: '加班信息',
  64. children: [
  65. FormFieldRow(label: '申请单号', value: o.applicationNo, showArrow: false),
  66. FormFieldRow(label: '加班类型', value: o.otType, showArrow: false),
  67. FormFieldRow(label: '补偿方式', value: o.compensationType, showArrow: false),
  68. FormFieldRow(label: '开始时间', value: du.DateUtils.formatDateTime(o.startTime), showArrow: false),
  69. FormFieldRow(label: '结束时间', value: du.DateUtils.formatDateTime(o.endTime), showArrow: false),
  70. FormFieldRow(label: '预估工时', value: '${o.otHours.toStringAsFixed(1)}h', showArrow: false),
  71. FormFieldRow(label: '部门', value: o.deptName, showArrow: false),
  72. FormFieldRow(label: '申请人', value: o.applicantName, showArrow: false),
  73. FormFieldRow(label: '创建时间', value: du.DateUtils.formatDateTime(o.createTime), showArrow: false),
  74. Padding(
  75. padding: const EdgeInsets.fromLTRB(14, 0, 14, 12),
  76. child: Row(
  77. children: [
  78. const SizedBox(width: 72, child: Text('状态', style: TextStyle(color: AppColors.textSecondary, fontSize: 13))),
  79. StatusTag(status: o.status),
  80. ],
  81. ),
  82. ),
  83. FormFieldRow(label: '加班事由', value: o.reason.isEmpty ? '-' : o.reason, showArrow: false),
  84. ],
  85. ),
  86. ),
  87. ),
  88. ),
  89. ),
  90. );
  91. }
  92. }