outing_log_detail_page.dart 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_riverpod/flutter_riverpod.dart';
  3. import 'package:tdesign_flutter/tdesign_flutter.dart';
  4. import '../../core/theme/app_colors.dart';
  5. import '../../core/utils/date_utils.dart' as du;
  6. import '../../shared/widgets/app_card.dart';
  7. import 'outing_log_model.dart';
  8. import 'outing_log_list_controller.dart';
  9. class OutingLogDetailPage extends ConsumerWidget {
  10. final String id;
  11. const OutingLogDetailPage({super.key, required this.id});
  12. @override
  13. Widget build(BuildContext context, WidgetRef ref) {
  14. final log = mockOutingLogs.firstWhere((e) => e.id == id,
  15. orElse: () => mockOutingLogs.first);
  16. return Scaffold(
  17. appBar: TDNavBar(
  18. title: '外出日志详情',
  19. titleColor: Colors.white,
  20. backgroundColor: const Color(0xFF00ABF3),
  21. centerTitle: false,
  22. ),
  23. body: SingleChildScrollView(
  24. padding: const EdgeInsets.all(12),
  25. child: Column(
  26. children: [
  27. _buildStatusHeader(log),
  28. const SizedBox(height: 12),
  29. _buildInfoSection(log),
  30. const SizedBox(height: 12),
  31. _buildContentSection(log),
  32. ],
  33. ),
  34. ),
  35. );
  36. }
  37. Widget _buildStatusHeader(OutingLogModel log) {
  38. final (icon, color, text) = switch (log.status) {
  39. '已完成' => (Icons.check_circle, AppColors.success, '已完成'),
  40. '待审核' => (Icons.schedule, AppColors.warning, '待审核'),
  41. _ => (Icons.info_outline, AppColors.textHint, log.status),
  42. };
  43. return Container(
  44. padding: const EdgeInsets.all(20),
  45. decoration: BoxDecoration(
  46. color: color.withValues(alpha: 0.08),
  47. borderRadius: BorderRadius.circular(12),
  48. ),
  49. child: Row(
  50. mainAxisAlignment: MainAxisAlignment.center,
  51. children: [
  52. Icon(icon, color: color, size: 36),
  53. const SizedBox(width: 10),
  54. Text(text,
  55. style: TextStyle(
  56. fontSize: 18,
  57. fontWeight: FontWeight.w600,
  58. color: color)),
  59. ],
  60. ),
  61. );
  62. }
  63. Widget _buildInfoSection(OutingLogModel log) {
  64. return _buildDetailCard('基本信息', [
  65. TDCell(title: '拜访编号', note: log.visitNo, showBottomBorder: true),
  66. TDCell(title: '业务员', note: '${log.salespersonName} · ${log.deptName}', showBottomBorder: true),
  67. TDCell(title: '客户名称', note: log.customerName, showBottomBorder: true),
  68. TDCell(title: '联系人', note: '${log.contactName.isNotEmpty ? log.contactName : '-'}${log.contactPhone.isNotEmpty ? ' · ${log.contactPhone}' : ''}', showBottomBorder: true),
  69. TDCell(title: '拜访类型', note: log.visitType, showBottomBorder: true),
  70. TDCell(title: '拜访目的', note: log.visitPurpose.isNotEmpty ? log.visitPurpose : '-', showBottomBorder: true),
  71. TDCell(title: '拜访时间', note: '${du.DateUtils.formatDate(log.visitDate)} ${du.DateUtils.formatTime(log.visitStartTime)} - ${du.DateUtils.formatTime(log.visitEndTime)}', showBottomBorder: true),
  72. TDCell(title: '拜访地点', note: log.visitLocation.isNotEmpty ? log.visitLocation : '-', showBottomBorder: false),
  73. ]);
  74. }
  75. Widget _buildDetailCard(String title, List<Widget> cells) {
  76. return Container(
  77. margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
  78. decoration: BoxDecoration(
  79. color: AppColors.cardWhite,
  80. borderRadius: BorderRadius.circular(10),
  81. boxShadow: [BoxShadow(color: Colors.black.withValues(alpha: 0.04), blurRadius: 4, offset: const Offset(0, 1))],
  82. ),
  83. child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
  84. Padding(
  85. padding: const EdgeInsets.fromLTRB(14, 12, 14, 8),
  86. child: Text(title, style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: AppColors.textPrimary)),
  87. ),
  88. ...cells,
  89. ]),
  90. );
  91. }
  92. Widget _buildContentSection(OutingLogModel log) {
  93. return AppCard(
  94. child: Column(
  95. crossAxisAlignment: CrossAxisAlignment.start,
  96. children: [
  97. const Text('拜访详情',
  98. style: TextStyle(
  99. fontSize: 13,
  100. fontWeight: FontWeight.w600,
  101. color: AppColors.textPrimary)),
  102. const SizedBox(height: 10),
  103. _contentBlock('拜访总结', log.visitSummary),
  104. if (log.customerFeedback.isNotEmpty)
  105. _contentBlock('客户反馈', log.customerFeedback),
  106. if (log.competitorInfo.isNotEmpty)
  107. _contentBlock('竞品信息', log.competitorInfo),
  108. _contentBlock('下次拜访',
  109. '${du.DateUtils.formatDate(log.nextVisitTime)}${log.nextVisitContent.isNotEmpty ? ' · ${log.nextVisitContent}' : ''}'),
  110. ],
  111. ),
  112. );
  113. }
  114. Widget _contentBlock(String label, String value) {
  115. return Padding(
  116. padding: const EdgeInsets.only(bottom: 12),
  117. child: Column(
  118. crossAxisAlignment: CrossAxisAlignment.start,
  119. children: [
  120. Text(label,
  121. style: const TextStyle(
  122. fontSize: 12, color: AppColors.textSecondary)),
  123. const SizedBox(height: 4),
  124. Text(value.isNotEmpty ? value : '-',
  125. style: const TextStyle(
  126. fontSize: 13,
  127. color: AppColors.textPrimary,
  128. height: 1.5)),
  129. ],
  130. ),
  131. );
  132. }
  133. }