251 lines
8.7 KiB
Dart
251 lines
8.7 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:image_picker/image_picker.dart';
|
||
|
||
class RepairPage extends StatefulWidget {
|
||
const RepairPage({super.key, required this.scrollController});
|
||
|
||
final ScrollController scrollController;
|
||
|
||
@override
|
||
State<RepairPage> createState() => _RepairPageState();
|
||
}
|
||
|
||
class _RepairPageState extends State<RepairPage> {
|
||
final _formKey = GlobalKey<FormState>();
|
||
String? _repairType;
|
||
final _locationController = TextEditingController();
|
||
final _descriptionController = TextEditingController();
|
||
XFile? _photo;
|
||
|
||
final List<Map<String, String>> _repairRecords = [
|
||
{
|
||
"date": "2025/04/20",
|
||
"type": "水管漏水",
|
||
"location": "A棟 2F",
|
||
"status": "處理中",
|
||
},
|
||
{
|
||
"date": "2025/04/18",
|
||
"type": "網路異常",
|
||
"location": "C棟 5F",
|
||
"status": "已完成",
|
||
},
|
||
{
|
||
"date": "2025/04/15",
|
||
"type": "電力問題",
|
||
"location": "B棟 6F",
|
||
"status": "待處理",
|
||
},
|
||
];
|
||
|
||
Future<void> _pickImage() async {
|
||
final picker = ImagePicker();
|
||
final picked = await picker.pickImage(source: ImageSource.gallery);
|
||
if (picked != null) {
|
||
setState(() {
|
||
_photo = picked;
|
||
});
|
||
}
|
||
}
|
||
|
||
void _submitForm() {
|
||
if (_formKey.currentState!.validate() && _repairType != null) {
|
||
ScaffoldMessenger.of(
|
||
context,
|
||
).showSnackBar(const SnackBar(content: Text('報修已提交!')));
|
||
// 這裡可以擴充送出資料到伺服器的邏輯
|
||
}
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
_locationController.dispose();
|
||
_descriptionController.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Container(
|
||
decoration: const BoxDecoration(
|
||
color: Color(0xFFF7F8FA),
|
||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||
),
|
||
child: Column(
|
||
children: [
|
||
// 標題列
|
||
Container(
|
||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||
decoration: const BoxDecoration(
|
||
color: Color(0xFF9EAF9F),
|
||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||
),
|
||
child: Row(
|
||
children: [
|
||
IconButton(
|
||
icon: const Icon(Icons.close, color: Colors.white),
|
||
onPressed: () => Navigator.pop(context),
|
||
),
|
||
const SizedBox(width: 8),
|
||
const Text(
|
||
'水電網路報修',
|
||
style: TextStyle(
|
||
fontWeight: FontWeight.bold,
|
||
fontSize: 20,
|
||
color: Colors.white,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
|
||
Expanded(
|
||
child: ListView(
|
||
controller: widget.scrollController,
|
||
padding: const EdgeInsets.all(16),
|
||
children: [
|
||
const Text('🛠️ 填寫報修單', style: TextStyle(fontSize: 16)),
|
||
const SizedBox(height: 12),
|
||
Form(
|
||
key: _formKey,
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
const Text(
|
||
'報修類別',
|
||
style: TextStyle(fontWeight: FontWeight.bold),
|
||
),
|
||
DropdownButtonFormField<String>(
|
||
value: _repairType,
|
||
items: const [
|
||
DropdownMenuItem(value: '電力問題', child: Text('電力問題')),
|
||
DropdownMenuItem(value: '水管漏水', child: Text('水管漏水')),
|
||
DropdownMenuItem(value: '網路異常', child: Text('網路異常')),
|
||
DropdownMenuItem(value: '其他', child: Text('其他')),
|
||
],
|
||
hint: const Text('請選擇'),
|
||
onChanged: (value) {
|
||
setState(() {
|
||
_repairType = value;
|
||
});
|
||
},
|
||
validator: (value) => value == null ? '請選擇報修類別' : null,
|
||
),
|
||
const SizedBox(height: 12),
|
||
const Text(
|
||
'地點/房號',
|
||
style: TextStyle(fontWeight: FontWeight.bold),
|
||
),
|
||
TextFormField(
|
||
controller: _locationController,
|
||
decoration: const InputDecoration(hintText: '如:B棟 3F'),
|
||
validator:
|
||
(value) =>
|
||
value == null || value.isEmpty ? '請輸入地點' : null,
|
||
),
|
||
const SizedBox(height: 12),
|
||
const Text(
|
||
'問題描述',
|
||
style: TextStyle(fontWeight: FontWeight.bold),
|
||
),
|
||
TextFormField(
|
||
controller: _descriptionController,
|
||
maxLines: 3,
|
||
decoration: const InputDecoration(
|
||
hintText: '請簡要描述問題...',
|
||
border: OutlineInputBorder(),
|
||
),
|
||
validator:
|
||
(value) =>
|
||
value == null || value.isEmpty
|
||
? '請輸入問題描述'
|
||
: null,
|
||
),
|
||
const SizedBox(height: 12),
|
||
const Text(
|
||
'照片上傳(選填)',
|
||
style: TextStyle(fontWeight: FontWeight.bold),
|
||
),
|
||
Row(
|
||
children: [
|
||
ElevatedButton(
|
||
onPressed: _pickImage,
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: Colors.white,
|
||
),
|
||
child: const Text(
|
||
'選擇照片',
|
||
style: TextStyle(color: Colors.purple),
|
||
),
|
||
),
|
||
const SizedBox(width: 8),
|
||
if (_photo != null)
|
||
const Text(
|
||
'已選擇圖片',
|
||
style: TextStyle(color: Colors.green),
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 16),
|
||
ElevatedButton(
|
||
onPressed: _submitForm,
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: Colors.green,
|
||
minimumSize: const Size.fromHeight(48),
|
||
),
|
||
child: const Text(
|
||
'送出報修',
|
||
style: TextStyle(color: Colors.white),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
const SizedBox(height: 24),
|
||
const Text('📋 已申報紀錄', style: TextStyle(fontSize: 16)),
|
||
const SizedBox(height: 12),
|
||
..._repairRecords.map(
|
||
(record) => Padding(
|
||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(
|
||
'${record["date"]} - ${record["type"]}',
|
||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||
),
|
||
Text('地點:${record["location"]}|狀態:${record["status"]}'),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
// 浮層包裝元件,給 showModalBottomSheet 使用
|
||
class RepairPageWrapper extends StatelessWidget {
|
||
const RepairPageWrapper({super.key});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return DraggableScrollableSheet(
|
||
initialChildSize: 0.95,
|
||
minChildSize: 0.5,
|
||
maxChildSize: 1.0,
|
||
expand: false,
|
||
builder: (_, scrollController) {
|
||
return Container(
|
||
color: Colors.transparent,
|
||
child: RepairPage(scrollController: scrollController),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
}
|