Files
platforms/apps/user_app/test/support/a1_fixture.dart
czl231 3ef33b531d 已完成用户APP首期功能开发
交付用户端首期页面、配套接口、后台资源及测试文档。用户APP构建、静态分析和三个管理后台构建通过;完整测试仍有2项失败,后端模型注释检查未通过,详见交付记录。
2026-09-13 00:57:32 +08:00

852 lines
27 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 功能描述A1 自动测试与截图共用的明确 Fixture禁止作为运行入口使用。
// 版本1.0.0
import 'package:user_app/data/repositories/client_repository.dart';
import 'package:user_app/data/services/api_client.dart';
import 'package:user_app/domain/models/client_models.dart';
import 'package:user_app/domain/models/shipping_address.dart';
import 'package:user_app/domain/models/product_detail.dart';
import 'package:user_app/domain/models/cart_item.dart';
import 'package:user_app/domain/models/product_favorite.dart';
import 'package:user_app/domain/models/primary_models.dart';
import 'package:user_app/domain/models/product_recommendations.dart';
import 'package:user_app/domain/models/shop_order_detail.dart';
import 'package:user_app/domain/models/gas_order_detail.dart';
import 'package:user_app/domain/models/gas_order_checkout.dart';
import 'package:user_app/domain/models/wallet_bill.dart';
import 'package:user_app/domain/models/wallet_account.dart';
import 'package:user_app/domain/models/deposit.dart';
import 'package:user_app/domain/models/recharge.dart';
import 'package:user_app/domain/models/delivery_detail.dart';
import 'package:user_app/domain/models/delivery_track.dart';
import 'package:user_app/domain/models/usage_statistics.dart';
import 'package:user_app/domain/models/message_center.dart';
import 'package:user_app/domain/models/family_sharing.dart';
/// 提供可控数据及失败状态,测试不依赖本地数据库。
class A1FixtureRepository extends ClientRepository {
A1FixtureRepository() : super(ApiClient(() => ''));
bool fail = false;
int withdrawalCalls = 0;
int depositReturnCalls = 0;
int gasOrderCreateCalls = 0;
final markedMessageKeys = <String>[];
@override
Future<FamilyDashboardData> familyDashboard() async => FamilyDashboardData(
householdName: '薛海路之家',
ownerName: '张先生',
memberCount: 3,
deviceCount: 3,
members: [
const FamilyMember(
identity: 'owner',
name: '张先生',
phoneMasked: '138****5678',
relationship: '房主',
inviteStatus: 20,
isOwner: true,
permissions: [],
),
const FamilyMember(
identity: 'member-1',
name: '张女士',
phoneMasked: '139****6078',
relationship: '家人',
inviteStatus: 20,
isOwner: false,
permissions: [
FamilyDevicePermission(
deviceIdentity: 'device-1',
deviceName: '厨房角阀',
deviceKind: 'valve',
canView: true,
canAlert: true,
canControl: true,
),
],
),
const FamilyMember(
identity: 'member-2',
name: '李先生',
phoneMasked: '138****0028',
relationship: '房东',
inviteStatus: 20,
isOwner: false,
permissions: [
FamilyDevicePermission(
deviceIdentity: 'device-2',
deviceName: '厨房报警器',
deviceKind: 'alarm',
canView: true,
canAlert: true,
canControl: false,
),
],
),
FamilyMember(
identity: 'member-3',
name: '王女士',
phoneMasked: '137****9056',
relationship: '家人',
inviteStatus: 10,
isOwner: false,
permissions: const [],
expiresAt: DateTime(2026, 9, 20),
),
],
devices: const [
FamilyDevice(
identity: 'device-1',
name: '厨房角阀',
kind: 'valve',
shareCount: 3,
mappingConfigured: true,
),
FamilyDevice(
identity: 'device-2',
name: '厨房报警器',
kind: 'alarm',
shareCount: 3,
mappingConfigured: true,
),
FamilyDevice(
identity: 'device-3',
name: '客厅报警器',
kind: 'alarm',
shareCount: 2,
mappingConfigured: true,
),
],
);
@override
Future<MessageCenterData> messages() async => MessageCenterData(
counts: const {'all': 5, 'unread': 2, 'safety': 1, 'order': 2, 'service': 1, 'notice': 1},
items: [
UserMessage(
key: 'safety-1',
category: 'safety',
title: '厨房燃气浓度异常',
summary: '厨房报警器1检测到燃气浓度异常',
statusText: '已解除',
target: '',
targetIdentity: '',
occurredAt: DateTime(2026, 9, 12, 9, 18),
read: false,
),
UserMessage(
key: 'order-2',
category: 'order',
title: '厨房角阀已远程关闭',
summary: '厨房角阀已为您远程关闭,保障用气安全',
statusText: '已完成',
target: '',
targetIdentity: '',
occurredAt: DateTime(2026, 9, 12, 8, 52),
read: true,
),
UserMessage(
key: 'service-1',
category: 'service',
title: '报修工单已受理',
summary: '您的报修工单已受理,工程师将尽快与您联系',
statusText: '进行中',
target: 'ticket',
targetIdentity: 'ticket-1',
occurredAt: DateTime(2026, 9, 11, 16, 30),
read: true,
),
UserMessage(
key: 'order-1',
category: 'order',
title: '配送员已出发',
summary: '您的燃气商品订单配送状态已更新',
statusText: '配送中',
target: 'gas_order',
targetIdentity: 'gas-1',
occurredAt: DateTime(2026, 9, 3, 9, 42),
read: false,
),
UserMessage(
key: 'notice-1',
category: 'notice',
title: '秋季安全用气提醒',
summary: '天气转凉,请注意用气通风,定期检查燃气设备。',
statusText: '平台公告',
target: 'content',
targetIdentity: 'notice-1',
occurredAt: DateTime(2026, 9, 1, 10),
read: true,
),
],
);
@override
Future<void> markMessagesRead(List<String> keys) async => markedMessageKeys.addAll(keys);
@override
Future<List<ClientRecord>> devices() async => const [
ClientRecord(
identity: 'device-1',
title: '厨房15kg气瓶',
subtitle: 'GZ-15-0286',
raw: {'kind': 'valve'},
),
];
@override
Future<UsageStatistics> usageStatistics({
required String deviceIdentity,
required String period,
DateTime? anchor,
}) async {
final start = DateTime(2026, 9, 1);
final values = [
0.12,
0.20,
0.13,
0.15,
0.08,
0.16,
0.30,
0.40,
0.28,
0.31,
0.42,
0.30,
0.29,
0.20,
0.28,
0.35,
0.20,
0.27,
0.39,
0.33,
0.19,
0.32,
0.49,
0.62,
0.35,
0.29,
0.37,
0.31,
0.17,
0.23,
];
return UsageStatistics(
available: true,
deviceIdentity: deviceIdentity,
deviceName: '厨房15kg气瓶',
deviceCode: 'GZ-15-0286',
period: period,
periodStart: start,
periodEnd: DateTime(2026, 9, 30),
unit: 'kg',
points: [
for (var index = 0; index < values.length; index++)
UsagePoint(
date: start.add(Duration(days: index)),
usage: values[index],
),
],
totalUsage: values.fold(0.0, (sum, value) => sum + value),
averageUsage: values.fold(0.0, (sum, value) => sum + value) / values.length,
composition: const UsageComposition(breakfast: 2.2, lunch: 2.5, dinner: 3.9),
source: 'device',
calcVersion: 'v1',
updatedAt: DateTime(2026, 9, 30, 23, 50),
unavailableReason: '',
);
}
@override
Future<DeliveryDetail> gasOrderDelivery(String identity) async => DeliveryDetail.fromJson({
'identity': identity,
'order_no': '178509050920001',
'status_code': 33,
'status_name': '配送中',
'status_message': '配送员正在前往您指定地点,请留意电话或消息通知',
'appointment_at': '2026-09-05T10:30:00+08:00',
'track_updated_at': '2026-09-05T09:56:00+08:00',
'address': '北京市朝阳区望京中环南路2号星源国际B座1201室',
'contact_name': '张女士',
'contact_phone_masked': '138****5678',
'station_name': '薛海气站',
'delivery_name': '薛海气站配送点',
'delivery_address': '北京市朝阳区薛海路8号',
'staff_name': '张师傅',
'staff_avatar': 'asset:assets/staff/delivery-worker.png',
'staff_assigned': true,
'credential_verified': true,
'credential_type': 'hazmat',
'track_available': true,
'controlled_call_available': false,
'message_available': false,
'vehicle_configured': false,
'products': [
{'name': '15kg液化气', 'quantity': 1},
],
});
@override
Future<DeliveryTrack> gasOrderDeliveryTrack(String identity) async => DeliveryTrack.fromJson({
'identity': identity,
'status_code': 33,
'status_name': '配送中',
'status_message': '配送员正在为您配送,请耐心等待',
'appointment_at': '2026-09-05T10:30:00+08:00',
'updated_at': '2026-09-05T09:56:00+08:00',
'station_name': '薛海气站',
'staff_name': '张师傅',
'staff_avatar': 'asset:assets/staff/delivery-worker.png',
'staff_phone_masked': '138****5678',
'controlled_call_available': false,
'route_available': true,
'destination_available': true,
'destination_longitude': 116.472,
'destination_latitude': 39.997,
'points': [
{'longitude': 116.451, 'latitude': 40.002, 'occurred_at': '2026-09-05T09:42:00+08:00'},
{'longitude': 116.456, 'latitude': 40.001, 'occurred_at': '2026-09-05T09:47:00+08:00'},
{'longitude': 116.461, 'latitude': 39.999, 'occurred_at': '2026-09-05T09:51:00+08:00'},
{'longitude': 116.466, 'latitude': 39.998, 'occurred_at': '2026-09-05T09:56:00+08:00'},
],
'timeline': [
{
'status_code': 18,
'title': '气站已接单',
'detail': '薛海气站已接收您的订单',
'occurred_at': '2026-09-05T09:21:00+08:00',
},
{
'status_code': 20,
'title': '商品装车完成',
'detail': '商品已装车,准备出发',
'occurred_at': '2026-09-05T09:35:00+08:00',
},
{
'status_code': 33,
'title': '配送员已出发',
'detail': '配送员已从薛海气站出发',
'occurred_at': '2026-09-05T09:42:00+08:00',
},
],
});
@override
Future<RechargeOptions> rechargeOptions() async => const RechargeOptions(
min: 1,
max: 500000,
channels: [
RechargeChannel('wechat', app: true, wap: true),
RechargeChannel('alipay', app: true, wap: true),
],
);
@override
Future<GasOrderCheckoutData> gasOrderOptions() async => GasOrderCheckoutData(
stationName: '薛海气站',
stationStatus: '营业中',
deliveryScope: '薛海镇及周边区域',
deliveryFee: 0,
products: const [
GasOrderProductOption(
name: '5kg 便携瓶',
description: '小巧轻便,适合单人或短期使用',
unitPrice: 5800,
depositAmount: 10000,
itemIdentities: ['g5'],
),
GasOrderProductOption(
name: '10kg 家用瓶',
description: '家庭日常使用,经济实惠',
unitPrice: 9600,
depositAmount: 10000,
itemIdentities: ['g10'],
),
GasOrderProductOption(
name: '15kg 家用瓶',
description: '大容量更耐用,适合多人家庭',
unitPrice: 12800,
depositAmount: 10000,
itemIdentities: ['g15'],
),
],
addresses: const [
ShippingAddress(
identity: 'a1',
address: '薛海镇泰山路188号 薛海花园3栋602室',
contactName: '张先生',
contactPhone: '13812345678',
isDefault: true,
),
],
slots: [
GasOrderAppointmentSlot(startAt: DateTime(2026, 9, 12, 9), label: '明日 09:00-11:00'),
],
);
@override
Future<GasOrderCreateResult> createGasOrder({
required String requestNo,
required String addressIdentity,
required List<String> itemIdentities,
required DateTime appointmentAt,
required int expectedAmount,
}) async {
gasOrderCreateCalls++;
return GasOrderCreateResult(identity: 'gas-created', payableAmount: expectedAmount);
}
@override
Future<DepositSummary> deposits() async => DepositSummary(
refundableAmount: 20000,
usingCount: 2,
ruleText: '气瓶完好、回收检测合格后,押金原路退回至余额账户。',
items: [
DepositRecord(
identity: 'd1',
depositNo: 'YJ20260905001',
status: 10,
statusName: '使用中',
amount: 10000,
productName: '15kg 液化气钢瓶',
productCode: 'GZ-15-0286',
paidAt: DateTime(2026, 8, 18),
refundedAt: null,
allowedActions: const ['return_bottle'],
),
DepositRecord(
identity: 'd2',
depositNo: 'YJ20260904002',
status: 20,
statusName: '退款中',
amount: 10000,
productName: '15kg 液化气钢瓶',
productCode: 'GZ-15-0193',
paidAt: DateTime(2026, 8, 12),
refundedAt: null,
allowedActions: const [],
),
DepositRecord(
identity: 'd3',
depositNo: 'YJ20260828003',
status: 23,
statusName: '已退回',
amount: 10000,
productName: '15kg 液化气钢瓶',
productCode: 'GZ-15-0127',
paidAt: DateTime(2026, 7, 28),
refundedAt: DateTime(2026, 7, 30),
allowedActions: const [],
),
],
);
@override
Future<DepositReturnRequest> createDepositReturn({
required String depositIdentity,
required ShippingAddress address,
required DateTime appointmentStart,
required DateTime appointmentEnd,
required String requestNo,
}) async {
depositReturnCalls++;
return const DepositReturnRequest(
identity: 'return-1',
status: 10,
statusName: '待上门',
estimatedAmount: 10000,
refundAmount: 0,
);
}
@override
Future<WalletBillPage> walletBills({String direction = '', String cursor = ''}) async {
if (fail) throw const ApiException(500, '测试账单错误');
final items = [
for (final (id, type, amount, flow) in [
('1', 'gas_order', 22800, 'expense'),
('2', 'refund', 5900, 'income'),
('3', 'recharge', 30000, 'income'),
])
WalletBill(
identity: id,
number: 'TEST-$id',
direction: flow,
tradeType: type,
amount: amount,
fee: 0,
balanceAfter: 56800,
createdAt: DateTime(2026, 9, 6 - int.parse(id)),
channel: 'wallet',
),
];
return WalletBillPage(
items.where((i) => direction.isEmpty || i.direction == direction).toList(),
'',
);
}
@override
Future<GasOrderDetail> gasOrderDetail(String identity) async {
final payment = identity == 'payment-1';
return GasOrderDetail.fromJson({
'identity': identity,
'order_no': payment ? '202609051628001' : 'G202609050920001',
'status_name': payment ? '待付款' : '待签收',
'allowed_actions': payment ? ['pay', 'cancel'] : ['confirm_receipt'],
'station_name': '薛海气站',
'delivery_staff_name': '李师傅',
'contract_identity': 'contract-1',
'contract_no': 'HT20260905001',
'product_amount': 12800,
'deposit_amount': payment ? 10000 : 0,
'delivery_fee': 0,
'discount_amount': 0,
'payable_amount': payment ? 22800 : 12800,
'contact_name': '张女士',
'contact_phone': '13800005678',
'address': '北京市朝阳区望京街道望京中环南路2号星源国际B座1201室',
'created_at': '2026-09-05T09:20:00+08:00',
'items': [
{'identity': 'gas-item', 'name': '15kg家用液化气', 'quantity': 1, 'sale_amount': 12800},
],
'timeline': payment
? []
: [
{'status_name': '已分配', 'occurred_at': '2026-09-05T09:21:00+08:00'},
{'status_name': '配送中', 'occurred_at': '2026-09-05T09:30:00+08:00'},
{'status_name': '待签收', 'occurred_at': '2026-09-05T10:30:00+08:00'},
],
'payments': payment
? []
: [
{'amount': 12800, 'channel': 'wechat', 'paid_at': '2026-09-05T09:22:00+08:00'},
],
}, (s) => s);
}
@override
Future<List<GasContractSummary>> gasContracts() async => [
GasContractSummary.fromJson({
'identity': 'contract-1',
'contract_no': 'HT20260905001',
'title': '居民瓶装燃气供用气合同',
'terms': '测试合同正文',
'contract_status': 11,
'station_name': '薛海气站',
'signed_at': '2026-08-18T00:00:00+08:00',
'effective_at': '2026-08-18T00:00:00+08:00',
'expired_at': '2027-08-17T00:00:00+08:00',
'has_attachment': false,
}),
];
@override
Future<GasContractDetail> gasContractDetail(String identity) async => GasContractDetail.fromJson({
'identity': identity,
'contract_no': 'HT20260905001',
'title': '居民瓶装燃气供用气合同',
'terms': '测试合同正文,仅用于自动验证,不作为真实合同。',
'contract_status': 11,
'signed_at': '2026-08-18T00:00:00+08:00',
'effective_at': '2026-08-18T00:00:00+08:00',
'expired_at': '2027-08-17T00:00:00+08:00',
'has_attachment': false,
});
@override
Future<ShopOrderDetail> shopOrderDetail(String identity) async {
final payment = identity == 'payment-1';
return ShopOrderDetail.fromJson({
'identity': identity,
'order_no': payment ? 'EC202609051628001' : 'EC202609050920001',
'status_name': payment ? '待付款' : '待收货',
'allowed_actions': payment ? ['pay', 'cancel'] : ['refund', 'confirm_receipt'],
'contact_name': '张女士',
'contact_phone': '13800005678',
'address': '北京市朝阳区望京街道望京中环南路2号星源国际B座1201室',
'product_amount': payment ? 23800 : 12800,
'discount_amount': payment ? 1000 : 0,
'payable_amount': payment ? 22800 : 12800,
'created_at': '2026-09-05T09:20:00+08:00',
'paid_at': payment ? null : '2026-09-05T09:21:00+08:00',
'shipped_at': payment ? null : '2026-09-05T09:30:00+08:00',
'received_at': null,
'remark': '送达前电话联系',
'items': [
{
'identity': 'item-1',
'product_identity': 'p1',
'name': '15kg家用液化气',
'quantity': 1,
'sale_amount': payment ? 23800 : 12800,
'image_url': '',
},
],
}, (s) => s);
}
@override
Future<ProductRecommendations> recommendations({required String source, int page = 1}) async =>
ProductRecommendations(
items: const [
ProductSummary(identity: 'r1', name: '家用燃气减压阀', price: 3900, stock: 10, category: '燃气配件'),
ProductSummary(identity: 'r2', name: '不锈钢燃气管', price: 5900, stock: 10, category: '燃气配件'),
],
page: page,
hasMore: false,
);
@override
Future<ProductFavoriteState> favoriteState(String identity) async =>
ProductFavoriteState(productIdentity: identity, active: false, revision: '');
@override
Future<List<ProductFavorite>> favorites() async => [
for (final p in await products())
ProductFavorite(
state: ProductFavoriteState(productIdentity: p.identity, active: true, revision: 'r1'),
product: ProductSummary(
identity: p.identity,
name: p.title,
price: p.raw['price_amount'] as int,
stock: 20,
category: p.raw['category_name'] as String,
),
available: true,
),
const ProductFavorite(
state: ProductFavoriteState(productIdentity: 'p5', active: true, revision: 'r1'),
product: ProductSummary(
identity: 'p5',
name: '家用燃气灶 双灶',
price: 69900,
stock: 0,
category: '灶具',
),
available: false,
specifications: ['天然气'],
),
];
@override
Future<List<CartItem>> cart() async => const [
CartItem(
product: ProductSummary(identity: 'p1', name: '15kg家用液化气', price: 12800, stock: 30),
quantity: 1,
selected: true,
available: true,
revision: 'r1',
),
CartItem(
product: ProductSummary(identity: 'p2', name: '燃气报警器', price: 16900, stock: 20),
quantity: 1,
selected: true,
available: true,
revision: 'r2',
),
];
@override
Future<ProductDetail> productDetail(String identity) async => ProductDetail(
identity: identity,
name: '15kg家用液化气',
price: 12800,
stock: 30,
category: '家用液化气',
attributes: const [(name: '净重', value: '15kg'), (name: '适用家庭', value: '3—5人家庭日常烹饪使用')],
);
int relationCalls = 0;
@override
Future<List<ShippingAddress>> shippingAddresses() async => const [
ShippingAddress(
identity: 'a1',
address: '广东省广州市白云区薛海路88号\n6栋502',
contactName: '张先生',
contactPhone: '13800005678',
isDefault: true,
),
ShippingAddress(
identity: 'a2',
address: '广东省广州市白云区泰山路188号\n薛海花园3栋602',
contactName: '李女士',
contactPhone: '13900006078',
),
ShippingAddress(
identity: 'a3',
address: '广东省广州市白云区同和街道同泰路28号\n同泰大厦1栋901',
contactName: '王先生',
contactPhone: '13700008910',
),
];
@override
Future<List<ClientRecord>> contents() async {
if (fail) throw const ApiException(500, '测试网络失败');
return const [
ClientRecord(
identity: 'notice-1',
title: '夏季用气安全提醒',
subtitle: '',
raw: {
'body': '高温天气注意通风,定期检查燃气设备',
'content_type': 'notice',
'version_no': 1,
'created_at': '2026-07-26T10:00:00+08:00',
},
),
ClientRecord(
identity: 'notice-2',
title: '燃气设施维护通知',
subtitle: '',
raw: {
'body': '本周将对部分区域进行例行维护',
'content_type': 'notice',
'version_no': 1,
'created_at': '2026-07-24T10:00:00+08:00',
},
),
];
}
@override
Future<Map<String, Object?>?> serviceRelation() async {
relationCalls++;
return {'gas_name': '薛海气站', 'delivery_name': '城南配送点'};
}
@override
Future<List<ClientRecord>> products() async => [
for (final (identity, name, price, category) in [
('p1', '15kg家用液化气', 12800, '液化气'),
('p2', '燃气报警器', 16900, '安全设备'),
('p3', '不锈钢减压阀', 5900, '燃气配件'),
('p4', '燃气软管2米', 2990, '燃气配件'),
])
ClientRecord(
identity: identity,
title: name,
subtitle: '',
raw: {'price_amount': price, 'stock_quantity': 20, 'category_name': category},
),
];
@override
Future<UserProfile> profile() async => const UserProfile(
identity: 'user-fixture',
name: '张先生',
phone: '13800005678',
avatar: '',
realName: '张先生',
);
@override
Future<WalletSummary> wallet() async =>
const WalletSummary(balance: 56800, withdrawalBalance: 56800, paymentPasswordSet: true);
@override
Future<List<WalletBank>> walletBanks() async => const [
WalletBank(
identity: 'bank-1',
maskedNumber: '**** **** **** 2868',
bankName: '中国建设银行',
owner: '张先生',
type: 'debit',
isDefault: true,
),
WalletBank(
identity: 'bank-2',
maskedNumber: '**** **** **** 6078',
bankName: '中国工商银行',
owner: '张先生',
type: 'debit',
isDefault: false,
),
];
@override
Future<List<WalletWithdrawal>> walletWithdrawals() async => const [];
@override
Future<WalletWithdrawal> createWalletWithdrawal({
required String bankIdentity,
required int amount,
required String requestNo,
required String paymentPassword,
}) async {
withdrawalCalls++;
return WalletWithdrawal(
identity: 'withdraw-1',
number: 'WD20260911001',
amount: amount,
fee: 0,
status: 10,
createdAt: DateTime(2026, 9, 11, 12),
);
}
@override
Future<List<ClientRecord>> addresses() async => [];
@override
Future<List<ClientRecord>> emergencyContacts() async => const [
ClientRecord(identity: 'contact-1', title: '家人一', subtitle: '', raw: {}),
ClientRecord(identity: 'contact-2', title: '家人二', subtitle: '', raw: {}),
];
@override
Future<List<ClientRecord>> shopOrders() async => const [
ClientRecord(
identity: 'order-1',
title: '订单号1785051399865',
subtitle: '',
status: 16,
raw: {
'payable_amount': 22800,
'status_name': '待付款',
'allowed_actions': ['pay', 'cancel'],
'created_at': '2026-07-26T15:36:00+08:00',
'items': [
{'identity': 'item-1', 'quantity': 1, 'product_snapshot': '{"name":"15kg家用液化气"}'},
],
},
),
];
@override
Future<List<ClientRecord>> gasOrders() async => (await shopOrders())
.map(
(r) => ClientRecord(
identity: r.identity,
title: r.title,
subtitle: r.subtitle,
status: r.status,
raw: {
...r.raw,
'station_name': '薛海气站',
'items': [
{
'identity': 'item-1',
'quantity': 1,
'product_type_name': '15kg家用液化气',
'product_params': '{"weight":"15kg"}',
},
],
'allowed_actions': ['pay', 'cancel'],
},
),
)
.toList();
@override
Future<List<ClientRecord>> refunds() async => [];
@override
Future<List<ClientRecord>> tickets() async => [
const ClientRecord(
identity: 't1',
title: 'BX202609040123',
subtitle: '厨房角阀关闭后仍有轻微异响',
status: 34,
raw: {
'ticket_no': 'BX202609040123',
'ticket_status': 34,
'status_name': '待确认',
'allowed_actions': ['cancel', 'confirm'],
'category': 'repair',
'description': '厨房角阀关闭后仍有轻微异响',
'address': '四川省成都市武侯区万科·公园传奇南区3栋2单元1804',
'created_at': '2026-09-04T01:15:00Z',
'started_at': '2026-09-04T08:00:00Z',
'appointment_at': '2026-09-04T08:00:00Z',
'result': '已检查阀门并更换密封件,请确认处理结果。',
},
),
];
}