230 lines
7.1 KiB
Dart
230 lines
7.1 KiB
Dart
import 'package:autosos_flutter/model/base_response.dart';
|
||
import 'package:autosos_flutter/model/order.dart';
|
||
import 'package:autosos_flutter/provider/providers.dart';
|
||
import 'package:autosos_flutter/util/toast.dart';
|
||
import 'package:autosos_flutter/widget/multi_state_view.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
import 'package:go_router/go_router.dart';
|
||
import 'package:intl/intl.dart';
|
||
|
||
import '../../router/app_router.dart';
|
||
|
||
/// 核单页(对应 Android CheckOrderActivity / CheckFragment)
|
||
/// 展示待核单订单,技师确认后调 /v2/order/check 进入待接单
|
||
class CheckPage extends ConsumerStatefulWidget {
|
||
const CheckPage({super.key});
|
||
|
||
@override
|
||
ConsumerState<CheckPage> createState() => _CheckPageState();
|
||
}
|
||
|
||
class _CheckPageState extends ConsumerState<CheckPage> {
|
||
MultiState _state = MultiState.loading;
|
||
List<CheckItem> _items = [];
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_load();
|
||
}
|
||
|
||
Future<void> _load() async {
|
||
setState(() => _state = MultiState.loading);
|
||
try {
|
||
final api = ref.read(orderApiProvider);
|
||
final BaseResponse<List<CheckItem>> resp = await api.checkList();
|
||
if (!mounted) return;
|
||
if (!resp.isSuccess) {
|
||
setState(() => _state = MultiState.error);
|
||
Toast.error(resp.message ?? '加载失败');
|
||
return;
|
||
}
|
||
setState(() {
|
||
_items = resp.data ?? [];
|
||
_state = _items.isEmpty ? MultiState.empty : MultiState.success;
|
||
});
|
||
} catch (e) {
|
||
if (mounted) setState(() => _state = MultiState.error);
|
||
}
|
||
}
|
||
|
||
Future<void> _submit(CheckItem item) async {
|
||
final remark = await _showRemarkDialog();
|
||
if (remark == null) return;
|
||
EasyLoading.show(status: '提交中…');
|
||
try {
|
||
final resp = await ref.read(orderApiProvider).submitCheck(
|
||
orderId: item.orderId,
|
||
remark: remark,
|
||
);
|
||
EasyLoading.dismiss();
|
||
if (!resp.isSuccess) {
|
||
Toast.error(resp.message ?? '核单失败');
|
||
return;
|
||
}
|
||
Toast.success('核单成功');
|
||
setState(() => _items.removeWhere((e) => e.orderId == item.orderId));
|
||
if (_items.isEmpty) setState(() => _state = MultiState.empty);
|
||
} catch (e) {
|
||
EasyLoading.dismiss();
|
||
Toast.error('核单异常:$e');
|
||
}
|
||
}
|
||
|
||
Future<String?> _showRemarkDialog() async {
|
||
final ctrl = TextEditingController();
|
||
return showDialog<String>(
|
||
context: context,
|
||
builder: (ctx) => AlertDialog(
|
||
title: const Text('核单备注'),
|
||
content: TextField(
|
||
controller: ctrl,
|
||
maxLines: 3,
|
||
decoration: const InputDecoration(
|
||
hintText: '请输入核单说明(可选)',
|
||
border: OutlineInputBorder(),
|
||
),
|
||
),
|
||
actions: [
|
||
TextButton(
|
||
onPressed: () => Navigator.pop(ctx),
|
||
child: const Text('取消'),
|
||
),
|
||
ElevatedButton(
|
||
onPressed: () => Navigator.pop(ctx, ctrl.text.trim()),
|
||
child: const Text('确认'),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: AppBar(
|
||
title: const Text('待核单'),
|
||
actions: [
|
||
IconButton(icon: const Icon(Icons.refresh), onPressed: _load),
|
||
],
|
||
),
|
||
body: RefreshIndicator(
|
||
onRefresh: _load,
|
||
child: MultiStateView(
|
||
state: _state,
|
||
onRetry: _load,
|
||
child: ListView.separated(
|
||
padding: const EdgeInsets.all(12),
|
||
itemCount: _items.length,
|
||
separatorBuilder: (_, __) => const SizedBox(height: 8),
|
||
itemBuilder: (ctx, i) => _CheckCard(
|
||
item: _items[i],
|
||
onSubmit: () => _submit(_items[i]),
|
||
onDetail: () => context.push(
|
||
'${Routes.orderComplete}/${_items[i].orderId}',
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
class _CheckCard extends StatelessWidget {
|
||
final CheckItem item;
|
||
final VoidCallback onSubmit;
|
||
final VoidCallback onDetail;
|
||
const _CheckCard({
|
||
required this.item,
|
||
required this.onSubmit,
|
||
required this.onDetail,
|
||
});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final fmt = DateFormat('MM-dd HH:mm');
|
||
return Material(
|
||
color: Colors.white,
|
||
borderRadius: BorderRadius.circular(8),
|
||
child: InkWell(
|
||
borderRadius: BorderRadius.circular(8),
|
||
onTap: onDetail,
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(12),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Row(
|
||
children: [
|
||
Container(
|
||
padding: const EdgeInsets.symmetric(
|
||
horizontal: 8,
|
||
vertical: 2,
|
||
),
|
||
decoration: BoxDecoration(
|
||
color: Colors.orange.shade50,
|
||
borderRadius: BorderRadius.circular(4),
|
||
),
|
||
child: Text(
|
||
item.serviceType,
|
||
style: TextStyle(
|
||
color: Colors.orange.shade700,
|
||
fontSize: 12,
|
||
),
|
||
),
|
||
),
|
||
const Spacer(),
|
||
Text(
|
||
'¥${item.amount.toStringAsFixed(2)}',
|
||
style: const TextStyle(
|
||
color: Colors.red,
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
const SizedBox(height: 8),
|
||
Text('订单号:${item.orderNo}',
|
||
style: const TextStyle(fontSize: 13)),
|
||
if (item.address != null && item.address!.isNotEmpty) ...[
|
||
const SizedBox(height: 4),
|
||
Text('地点:${item.address}',
|
||
style: TextStyle(
|
||
fontSize: 13, color: Colors.grey.shade700)),
|
||
],
|
||
const SizedBox(height: 4),
|
||
Text('时间:${fmt.format(item.createdAt)}',
|
||
style: TextStyle(fontSize: 12, color: Colors.grey.shade500)),
|
||
const SizedBox(height: 8),
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: OutlinedButton(
|
||
onPressed: onDetail,
|
||
child: const Text('查看详情'),
|
||
),
|
||
),
|
||
const SizedBox(width: 8),
|
||
Expanded(
|
||
child: ElevatedButton(
|
||
onPressed: onSubmit,
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: Theme.of(context).primaryColor,
|
||
),
|
||
child: const Text('确认核单'),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|