flutter_for_openharmonyflutter小区门禁管理app实战+报修详情实现
报修详情页面实现摘要(148字): 该Flutter实现的报修详情页面采用StatefulWidget构建,包含六大核心模块:报修信息展示区、处理进度跟踪区、图片附件预览区、互动回复记录区、服务评价区及新增回复区。页面通过动态状态管理实现数据交互,支持图片上传预览功能,并采用分类标签和状态颜色标识提升信息可读性。关键特性包括:1) 完整展示报修内容与处理状态;2) 可视化进度时间线;3) 多媒体附
·
报修详情是小区管理系统中的重要功能,它为住户提供了查看报修进度、回复内容、评价服务的重要界面,同时也为物业人员提供了处理报修的便捷渠道。
在实际项目中,报修详情页面需要解决几个关键问题:
- 如何清晰展示报修的完整信息和进度状态
- 如何支持图片预览和多媒体内容
- 如何显示处理时间线和回复记录
- 如何支持用户评价和满意度反馈
这篇讲报修详情页面的实现,重点是如何让报修详情展示既完整又易于跟踪。
对应源码
lib/pages/home/repair_detail_page.dart
报修详情页面的设计思路是:信息完整 + 进度清晰 + 互动便捷。
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:image_picker/image_picker.dart';
class RepairDetailPage extends StatefulWidget {
final Map<String, dynamic> repair;
const RepairDetailPage({
Key? key,
required this.repair,
}) : super(key: key);
State<RepairDetailPage> createState() => _RepairDetailPageState();
}
class _RepairDetailPageState extends State<RepairDetailPage> {
final _commentController = TextEditingController();
final ImagePicker _imagePicker = ImagePicker();
List<Map<String, dynamic>> _comments = [];
List<String> _images = [];
bool _isSubmitting = false;
bool _isLoading = false;
String _selectedRating = '0';
基础结构说明:
- 报修详情页面需要维护评论和状态,所以用
StatefulWidget。 - 接收
repair参数,显示指定报修的详情。 - 使用
ImagePicker支持图片上传功能。 _comments存储回复记录,_images存储图片附件。
void initState() {
super.initState();
_initializeState();
}
void _initializeState() {
setState(() {
_comments = List<Map<String, dynamic>>.from(repair['comments'] ?? []);
_images = List<String>.from(repair['images'] ?? []);
_selectedRating = repair['rating'] ?? '0';
});
}
void dispose() {
_commentController.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('报修详情'),
centerTitle: true,
actions: [
IconButton(
icon: const Icon(Icons.edit),
onPressed: _editRepair,
),
],
),
body: _isLoading
? const Center(child: CircularProgressIndicator())
: SingleChildScrollView(
padding: EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 报修信息
_buildRepairInfo(),
SizedBox(height: 24.h),
// 处理进度
_buildProgressSection(),
SizedBox(height: 24.h),
// 图片附件
if (_images.isNotEmpty)
_buildImagesSection(),
SizedBox(height: 24.h),
// 回复记录
_buildCommentsSection(),
SizedBox(height: 24.h),
// 评价区域
_buildRatingSection(),
SizedBox(height: 24.h),
// 添加回复
_buildReplySection(),
],
),
),
);
}
页面布局设计:
- AppBar 右侧提供编辑功能。
- 使用
SingleChildScrollView确保内容可滚动。 - 页面分为六个主要部分:报修信息、处理进度、图片附件、回复记录、评价区域、添加回复。
- 加载状态显示进度器,提升用户体验。
Widget _buildRepairInfo() {
return Container(
width: double.infinity,
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 8.r,
offset: Offset(0, 2.h),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 标题和状态
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
repair['title'],
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
Container(
padding: EdgeInsets.symmetric(
horizontal: 8.w,
vertical: 4.h,
),
decoration: BoxDecoration(
color: _getStatusColor(repair['status']),
borderRadius: BorderRadius.circular(12.r),
),
child: Text(
_getStatusText(repair['status']),
style: TextStyle(
fontSize: 10.sp,
color: Colors.white,
),
),
),
],
),
SizedBox(height: 12.h),
// 分类标签
Row(
children: [
Container(
padding: EdgeInsets.symmetric(
horizontal: 6.w,
vertical: 2.h,
),
decoration: BoxDecoration(
color: _getCategoryColor(repair['category']),
borderRadius: BorderRadius.circular(8.r),
),
child: Text(
_getCategoryText(repair['category']),
style: TextStyle(
fontSize: 10.sp,
color: Colors.white,
),
),
),
SizedBox(width: 8.w),
Text(
repair['location'],
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey[600],
),
),
SizedBox(width: 8.w),
Text(
repair['reportTime'],
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey[500],
),
),
],
),
SizedBox(height: 16.h),
// 描述
Text(
repair['description'],
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey[700],
height: 1.5,
),
),
],
),
);
}
报修信息区域:
- 显示报修标题、状态、分类、位置、时间等信息。
- 状态标签使用不同颜色区分处理状态。
- 分类标签使用不同颜色区分报修类型。
- 描述文字使用合适的行高,提升可读性。
Color _getStatusColor(String status) {
switch (status) {
case 'pending':
return Colors.orange;
case 'processing':
return Colors.blue;
case 'completed':
return Colors.green;
case 'rejected':
return Colors.red;
default:
return Colors.grey;
}
}
String _getStatusText(String status) {
switch (status) {
case 'pending':
return '待处理';
case 'processing':
return '处理中';
case 'completed':
return '已完成';
case 'rejected':
return '已拒绝';
default:
return '未知';
}
}
状态处理方法:
_getStatusColor获取状态对应的颜色。_getStatusText获取状态的中文文本。- 待处理(橙色)、处理中(蓝色)、已完成(绿色)、已拒绝(红色)。
Color _getCategoryColor(String category) {
switch (category) {
case 'plumbing':
return Colors.blue;
case 'electrical':
return Colors.yellow;
case 'structure':
return Colors.purple;
case 'cleaning':
return Colors.green;
case 'security':
return Colors.red;
default:
return Colors.grey;
}
}
String _getCategoryText(String category) {
switch (category) {
case 'plumbing':
return '水电';
case 'electrical':
return '电气';
case 'structure':
return '结构';
case 'cleaning':
return '清洁';
case 'security':
return '安保';
default:
return '其他';
}
}
分类处理方法:
_getCategoryColor获取分类对应的颜色。_getCategoryText获取分类的中文文本。- 水电(蓝色)、电气(黄色)、结构(紫色)、清洁(绿色)、安保(红色)。
Widget _buildProgressSection() {
return Container(
width: double.infinity,
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 8.r,
offset: Offset(0, 2.h),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'处理进度',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 16.h),
// 时间线
_buildTimelineItem(
icon: Icons.receipt,
title: '提交报修',
time: repair['reportTime'],
isCompleted: true,
isFirst: true,
),
_buildTimelineItem(
icon: Icons.assignment,
title: '受理中',
time: repair['acceptTime'] ?? '待受理',
isCompleted: repair['status'] != 'pending',
),
_buildTimelineItem(
icon: Icons.build,
title: '处理中',
time: repair['processTime'] ?? '待处理',
isCompleted: repair['status'] == 'completed' ||
repair['status'] == 'rejected',
),
_buildTimelineItem(
icon: _getStatusIcon(repair['status']),
title: _getStatusProgressText(repair['status']),
time: repair['completeTime'] ?? '进行中',
isCompleted: repair['status'] == 'completed' ||
repair['status'] == 'rejected',
isLast: true,
),
],
),
);
}
处理进度区域:
- 使用时间线展示报修处理进度。
- 四个阶段:提交→受理→处理→完成。
- 每个阶段显示图标、标题、时间和完成状态。
- 当前阶段高亮显示,已完成阶段显示完成状态。
Widget _buildTimelineItem({
required IconData icon,
required String title,
required String time,
required bool isCompleted,
bool isFirst = false,
bool isLast = false,
}) {
return Column(
children: [
Row(
children: [
Container(
width: 32.w,
height: 32.w,
decoration: BoxDecoration(
color: isCompleted ? Colors.green : Colors.grey[300],
shape: BoxShape.circle,
),
child: Icon(
icon,
color: Colors.white,
size: 16.sp,
),
),
SizedBox(width: 12.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w500,
color: isCompleted ? Colors.black : Colors.grey[600],
),
),
Text(
time,
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey[500],
),
),
],
),
),
],
),
if (!isLast) ...[
SizedBox(height: 8.h),
Container(
margin: EdgeInsets.only(left: 16.w),
height: 20.h,
width: 2.w,
color: isCompleted ? Colors.green : Colors.grey[300],
),
SizedBox(height: 8.h),
],
],
);
}
时间线项组件:
- 圆形图标显示阶段状态,完成状态用绿色。
- 标题和时间垂直排列,信息层次清晰。
- 连接线显示阶段之间的进度关系。
- 最后一个阶段不显示连接线。
Widget _buildImagesSection() {
return Container(
width: double.infinity,
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 8.r,
offset: Offset(0, 2.h),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'图片附件',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 12.h),
GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 8.w,
mainAxisSpacing: 8.h,
childAspectRatio: 1,
),
itemCount: _images.length,
itemBuilder: (context, index) {
return _buildImageItem(_images[index], index);
},
),
],
),
);
}
图片附件区域:
- 网格布局展示图片附件,3列排列。
- 使用
_buildImageItem构建图片项。 - 支持图片预览和删除操作。
- 使用
shrinkWrap和NeverScrollableScrollPhysics确保正确显示。
Widget _buildImageItem(String imagePath, int index) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.r),
border: Border.all(color: Colors.grey[300]!),
),
child: Stack(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(7.r),
child: Image.file(
File(imagePath),
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Container(
color: Colors.grey[200],
child: Icon(
Icons.broken_image,
color: Colors.grey[400],
),
);
},
),
),
Positioned(
top: 4.h,
right: 4.w,
child: GestureDetector(
onTap: () => _removeImage(index),
child: Container(
width: 20.w,
height: 20.w,
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
child: Icon(
Icons.close,
color: Colors.white,
size: 12.sp,
),
),
),
),
],
),
);
}
图片项组件:
- 使用
Stack布局实现图片和删除按钮的叠加。 - 图片使用
ClipRRect圆角裁剪。 - 错误处理显示占位图标。
- 删除按钮使用红色圆形背景,位于右上角。
Widget _buildCommentsSection() {
return Container(
width: double.infinity,
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 8.r,
offset: Offset(0, 2.h),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'回复记录',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 12.h),
if (_comments.isEmpty)
Container(
width: double.infinity,
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Colors.grey[50],
borderRadius: BorderRadius.circular(8.r),
),
child: Text(
'暂无回复记录',
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey[600],
),
textAlign: TextAlign.center,
),
)
else
..._comments.map((comment) => _buildCommentItem(comment)).toList(),
],
),
);
}
回复记录区域:
- 显示物业对报修的回复记录。
- 空状态显示暂无回复的提示。
- 有回复时使用
_buildCommentItem构建回复项。 - 回复记录按时间顺序排列。
Widget _buildCommentItem(Map<String, dynamic> comment) {
return Container(
margin: EdgeInsets.only(bottom: 16.h),
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Colors.blue[50],
borderRadius: BorderRadius.circular(8.r),
border: Border.all(color: Colors.blue[200]!),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
comment['author'],
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.bold,
color: Colors.blue[700],
),
),
Text(
comment['time'],
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey[600],
),
),
],
),
SizedBox(height: 8.h),
Text(
comment['content'],
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey[700],
),
),
],
),
);
}
回复项组件:
- 蓝色背景的回复卡片,与报修信息区分。
- 显示回复者、时间和内容。
- 回复者使用蓝色突出显示。
- 内容使用灰色文字,层次分明。
Widget _buildRatingSection() {
return Container(
width: double.infinity,
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius(12.r),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 8.r,
offset: Offset(0, 2.h),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'服务评价',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 16.h),
Text(
'请对本次服务进行评价,您的反馈对我们很重要',
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey[600],
),
),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildRatingStar(1),
_buildRatingStar(2),
_buildRatingStar(3),
_buildRatingStar(4),
_buildRatingStar(5),
],
),
SizedBox(height: 16.h),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _submitRating,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange,
foregroundColor: Colors.white,
padding: EdgeInsets.symmetric(vertical: 12.h),
),
child: Text(
'提交评价',
style: TextStyle(fontSize: 14.sp),
),
),
),
],
),
);
}
评价区域:
- 显示服务评价的说明文字。
- 使用5星评分系统,直观易用。
- 提交按钮使用橙色主题色,视觉突出。
- 评价功能帮助物业改进服务质量。
Widget _buildRatingStar(int rating) {
return GestureDetector(
onTap: () => _selectRating(rating),
child: Icon(
rating <= _selectedRating ? Icons.star : Icons.star_border,
color: rating <= _selectedRating ? Colors.amber : Colors.grey[400],
size: 32.sp,
),
);
}
void _selectRating(int rating) {
setState(() {
_selectedRating = rating.toString();
});
}
评分组件:
- 使用
GestureDetector支持点击选择评分。 - 当前评分用实心星,未评分用空心星。
- 评分使用琥珀色,视觉上更吸引人。
- 评分范围从1到5星。
Widget _buildReplySection() {
return Container(
width: double.infinity,
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
blurRadius: 8.r,
offset: Offset(0, 2.h),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'添加回复',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 12.h),
TextFormField(
controller: _commentController,
maxLines: 3,
decoration: InputDecoration(
hintText: '请输入回复内容',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.r),
),
),
),
SizedBox(height: 12.h),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _isSubmitting ? null : _submitReply,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
padding: EdgeInsets.symmetric(vertical: 12.h),
),
child: _isSubmitting
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 16.w,
height: 16.w,
child: CircularProgressIndicator(
strokeWidth: 2.w,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
),
SizedBox(width: 8.w),
const Text('提交中...'),
],
)
: const Text(
'提交回复',
style: TextStyle(fontSize: 14.sp),
),
),
),
],
),
);
}
添加回复区域:
- 多行文本输入框用于输入回复内容。
- 提交按钮使用蓝色主题色,视觉突出。
- 提交过程中显示进度器和状态文字。
- 为物业人员提供便捷的回复渠道。
Future<void> _submitRating() async {
if (_selectedRating == '0') {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('请选择评分')),
);
return;
}
setState(() {
_isSubmitting = true;
});
try {
// 模拟提交评价
await Future.delayed(const Duration(seconds: 2));
final ratingData = {
'repairId': repair['id'],
'rating': int.parse(_selectedRating),
'comment': _commentController.text,
'ratingTime': DateTime.now().toIso8601String(),
};
// 实际项目中这里会调用API保存评价
print('提交评价:$ratingData');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('评价提交成功,感谢您的反馈'),
backgroundColor: Colors.green,
),
);
Navigator.pop(context);
} catch (e) {
setState(() {
_isSubmitting = false;
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('提交失败,请重试'),
backgroundColor: Colors.red,
),
);
}
}
Future<void> _submitReply() async {
if (_commentController.text.trim().isEmpty) {
return;
}
setState(() {
_isSubmitting = true;
});
try {
// 模拟提交回复
await Future.delayed(const Duration(seconds: 2));
final commentData = {
'repairId': repair['id'],
'author': '物业客服',
'content': _commentController.text,
'time': DateTime.now().toIso8601String(),
};
// 实际项目中这里会调用API保存回复
print('提交回复:$commentData');
setState(() {
_comments.insert(0, commentData);
_isSubmitting = false;
_commentController.clear();
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('回复成功'),
backgroundColor: Colors.green,
),
);
} catch (e) {
setState(() {
_isSubmitting = false;
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('回复失败,请重试'),
backgroundColor: Colors.red,
),
);
}
}
void _editRepair() {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('编辑报修功能开发中...')),
);
}
void _removeImage(int index) {
setState(() {
_images.removeAt(index);
});
}
}
其他功能实现:
_submitRating提交评价,需要选择评分。_submitReply提交回复,验证内容非空。_editRepair编辑报修信息(预留接口)。_removeImage删除指定索引的图片。
用户体验设计
报修详情页面的用户体验重点:
- 进度可视化:时间线清晰显示处理进度
- 信息完整:展示报修的所有相关信息
- 互动便捷:支持回复、评价、图片预览
- 状态明确:不同状态用颜色区分
这些设计让报修详情查看和处理变得简单高效。
数据管理策略
报修详情的数据管理考虑:
- 状态流转:提交→受理→处理→完成/拒绝
- 时间线展示:按时间顺序显示处理进度
- 评论管理:按时间顺序存储回复记录
- 评价系统:5星评分系统收集用户反馈
这些策略确保报修数据的有序管理和用户反馈收集。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycendplatform.csdn.net
更多推荐


所有评论(0)