jjsos_autosos_flutter/lib/pages/order/check_page.dart

230 lines
7.1 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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('确认核单'),
),
),
],
),
],
),
),
),
);
}
}