import 'dart:math'; import '../models/user.dart'; import '../models/message.dart'; import '../models/event.dart'; import '../models/work_order.dart'; import '../models/order.dart'; class ApiService { static final ApiService _instance = ApiService._internal(); factory ApiService() => _instance; ApiService._internal(); final _random = Random(); Future> login(String phone, String password) async { await Future.delayed(const Duration(milliseconds: 800)); if (phone.length != 11) { throw Exception('手机号格式不正确'); } if (password.length < 6) { throw Exception('密码不能少于6位'); } final isBoss = phone.endsWith('88'); return { 'user': { 'id': 'user_${_random.nextInt(99999)}', 'phone': phone, 'name': isBoss ? '张老板' : '李员工', 'avatar': 'https://api.dicebear.com/7.x/avataaars/svg?seed=$phone', 'role': isBoss ? 'boss' : 'employee', 'token': 'token_${DateTime.now().millisecondsSinceEpoch}', 'hotelName': '智念度假酒店', 'scenicName': '智念风景区', }, 'token': 'mock_token_${DateTime.now().millisecondsSinceEpoch}', }; } Future> getChatHistory() async { await Future.delayed(const Duration(milliseconds: 500)); return [ ChatMessage( id: 'msg_1', content: '您好,我是智念AI助手,有什么可以帮您的吗?', type: MessageType.markdown, sender: MessageSender.ai, timestamp: DateTime.now().subtract(const Duration(minutes: 5)), ), ]; } Future sendMessage(String content) async { await Future.delayed(const Duration(milliseconds: 1200)); final tableTrigger = RegExp(r'表格|列表|清单|明细'); if (tableTrigger.hasMatch(content)) { return ChatMessage( id: 'msg_${DateTime.now().millisecondsSinceEpoch}', content: _tableReport(), type: MessageType.markdown, sender: MessageSender.ai, timestamp: DateTime.now(), ); } final imageTrigger = RegExp(r'图片|照片|图像|实景|环境照|相册'); if (imageTrigger.hasMatch(content)) { return ChatMessage( id: 'msg_${DateTime.now().millisecondsSinceEpoch}', content: _imageGallery(), type: MessageType.markdown, sender: MessageSender.ai, timestamp: DateTime.now(), ); } final chartTrigger = RegExp(r'报表|数据|营收|趋势|占比|图表|统计|分析'); if (chartTrigger.hasMatch(content)) { return ChatMessage( id: 'msg_${DateTime.now().millisecondsSinceEpoch}', content: _chartReport(), type: MessageType.markdown, sender: MessageSender.ai, timestamp: DateTime.now(), ); } final responses = [ '收到您的消息,我已记录并会尽快处理。\n\n**当前状态**:已受理\n**预计处理时间**:2小时内', '好的,我来帮您查询一下。\n\n| 项目 | 状态 | 时间 |\n|------|------|------|\n| 订单核销 | 已完成 | 10:30 |\n| 工单处理 | 进行中 | 11:00 |', '感谢您的反馈!根据系统记录,今日共有 **15笔订单** 待处理,**3个工单** 需要跟进。', '已为您生成今日数据报表:\n\n- 总订单数:128笔\n- 核销完成:96笔\n- 待处理:32笔\n- 退款申请:2笔', '事件已发布成功!\n\n> 事件将在设定的时间自动生效,系统会提前30分钟发送提醒。', ]; return ChatMessage( id: 'msg_${DateTime.now().millisecondsSinceEpoch}', content: responses[_random.nextInt(responses.length)], type: MessageType.markdown, sender: MessageSender.ai, timestamp: DateTime.now(), ); } String _imageGallery() { return '''### 智念度假酒店 · 环境实景 **大堂吧** — 全息投影 + 智能引导 ![大堂](https://picsum.photos/seed/zhinian-lobby/640/360) **无边泳池** — 山景一线,270° 全景视野 ![泳池](https://picsum.photos/seed/zhinian-pool/640/360) **SPA 养生** — 古法中医结合现代理疗 ![SPA](https://picsum.photos/seed/zhinian-spa/640/360) > 提示:可继续询问"客房实景""餐厅照片"查看更多。'''; } String _tableReport() { return '''### 今日订单明细 共 **5 条** 待跟进订单: | 订单号 | 客户 | 商品 | 金额 | 状态 | |---|---|---|---|---| | ZN20240507001 | 王先生 | 风景区成人票 ×2 | ¥128 | 🟡 待核销 | | ZN20240507002 | 李女士 | 豪华套房 ×1 | ¥888 | ⚪ 待支付 | | ZN20240507003 | 张 family | 亲子套票 ×3 | ¥388 | 🟢 已核销 | | ZN20240507004 | 陈先生 | SPA 养生套餐 | ¥598 | 🔴 退款中 | | ZN20240507005 | 赵女士 | 景区+酒店套餐 | ¥1588 | ⚫ 已退款 | **汇总** | 维度 | 数值 | |---|---| | 订单总数 | 5 | | 应收金额 | ¥3,590 | | 已退款 | ¥1,588 | | 净收入 | ¥2,002 | > 提示:点击订单行可跳转至详情,或继续询问"图表"查看可视化分析。'''; } String _chartReport() { return '''### 今日数据报表 总订单 **128 笔**,核销率 **75%**,环比上周 **+12.4%**。 ```chart type: bar title: 订单状态分布(笔) labels: 已核销,待处理,待支付,退款 data: 96,32,18,2 ``` ```chart type: line title: 近7日订单趋势 labels: 周一,周二,周三,周四,周五,周六,周日 data: 88,92,105,98,120,135,128 ``` ```chart type: pie title: 营收构成占比 labels: 客房,餐饮,SPA,门票 data: 58,22,12,8 ``` > 提示:可继续询问"工单趋势""营收对比"等查看更多分析。'''; } Future> getEvents() async { await Future.delayed(const Duration(milliseconds: 600)); return List.generate(8, (index) { final now = DateTime.now(); return EventItem( id: 'evt_$index', entityName: ['大堂吧', '游泳池', '健身房', '餐厅', 'SPA中心', '会议室', '停车场', '花园'][index], description: '这是关于${_getEntityName(index)}的维护通知,请相关人员注意安排时间。', images: [], publishTime: now.subtract(Duration(days: index)), effectiveTime: now.add(Duration(hours: index * 2)), endTime: now.add(Duration(hours: index * 2 + 4)), popupReminder: index % 2 == 0, status: ['published', 'draft', 'published', 'expired'][index % 4], creatorName: index % 2 == 0 ? '张老板' : '李员工', createdAt: now.subtract(Duration(days: index)), ); }); } String _getEntityName(int index) { return ['大堂吧', '游泳池', '健身房', '餐厅', 'SPA中心', '会议室', '停车场', '花园'][index]; } Future publishEvent(Map data) async { await Future.delayed(const Duration(milliseconds: 800)); return EventItem( id: 'evt_${DateTime.now().millisecondsSinceEpoch}', entityName: data['entityName'] ?? '', description: data['description'] ?? '', images: List.from(data['images'] ?? []), publishTime: DateTime.now(), effectiveTime: data['effectiveTime'] != null ? DateTime.parse(data['effectiveTime']) : null, endTime: data['endTime'] != null ? DateTime.parse(data['endTime']) : null, popupReminder: data['popupReminder'] ?? false, status: 'published', creatorName: '当前用户', createdAt: DateTime.now(), ); } Future> getWorkOrders(WorkOrderStatus status) async { await Future.delayed(const Duration(milliseconds: 600)); final allOrders = [ WorkOrder( id: 'wo_1', title: '客房空调维修', description: '308房间空调制冷效果不佳,需要安排维修人员检查。', status: WorkOrderStatus.pending, creatorName: '前台小王', assigneeName: '维修部', createdAt: DateTime.now().subtract(const Duration(hours: 2)), priority: 'high', category: '设备维修', images: [], location: '3楼308房间', ), WorkOrder( id: 'wo_2', title: '花园草坪修剪', description: '后花园草坪需要定期修剪,预计耗时2小时。', status: WorkOrderStatus.processing, creatorName: '张老板', assigneeName: '保洁部', createdAt: DateTime.now().subtract(const Duration(hours: 5)), priority: 'normal', category: '环境维护', images: [], location: '后花园', ), WorkOrder( id: 'wo_3', title: '餐厅设备清洁', description: '厨房排风系统需要深度清洁。', status: WorkOrderStatus.completed, creatorName: '厨师长', assigneeName: '保洁部', createdAt: DateTime.now().subtract(const Duration(days: 1)), completedAt: DateTime.now().subtract(const Duration(hours: 3)), priority: 'normal', category: '清洁', images: [], location: '主厨房', ), WorkOrder( id: 'wo_4', title: '游泳池水质检测', description: '每日例行水质检测,PH值和氯含量需要记录。', status: WorkOrderStatus.pending, creatorName: '救生员小张', createdAt: DateTime.now().subtract(const Duration(minutes: 30)), priority: 'high', category: '安全检查', images: [], location: '游泳池', ), WorkOrder( id: 'wo_5', title: '会议室投影仪调试', description: '下午有重要会议,需要提前调试投影设备。', status: WorkOrderStatus.processing, creatorName: '行政小刘', assigneeName: '行政部', createdAt: DateTime.now().subtract(const Duration(hours: 1)), priority: 'urgent', category: '设备调试', images: [], location: 'A座会议室', ), ]; if (status == WorkOrderStatus.all) return allOrders; return allOrders.where((o) => o.status == status).toList(); } Future getWorkOrderDetail(String id) async { await Future.delayed(const Duration(milliseconds: 400)); final orders = await getWorkOrders(WorkOrderStatus.all); return orders.firstWhere((o) => o.id == id, orElse: () => orders.first); } Future acceptWorkOrder(String id) async { await Future.delayed(const Duration(milliseconds: 700)); if (_random.nextInt(20) == 0) { throw Exception('网络异常,请稍后重试'); } final order = await getWorkOrderDetail(id); return order.copyWith( status: WorkOrderStatus.processing, assigneeName: order.assigneeName ?? '维修部', ); } Future transferWorkOrder(String id, String department) async { await Future.delayed(const Duration(milliseconds: 700)); if (_random.nextInt(20) == 0) { throw Exception('网络异常,请稍后重试'); } final order = await getWorkOrderDetail(id); return order.copyWith(assigneeName: department); } Future completeWorkOrder(String id) async { await Future.delayed(const Duration(milliseconds: 700)); if (_random.nextInt(20) == 0) { throw Exception('网络异常,请稍后重试'); } final order = await getWorkOrderDetail(id); return order.copyWith( status: WorkOrderStatus.completed, completedAt: DateTime.now(), ); } Future> getOrders(OrderStatus status) async { await Future.delayed(const Duration(milliseconds: 600)); final allOrders = [ OrderItem( id: 'ord_1', orderNo: 'ZN20240507001', customerName: '王先生', customerPhone: '138****8888', productName: '智念风景区成人票', amount: 128.00, status: OrderStatus.pendingVerification, createdAt: DateTime.now().subtract(const Duration(hours: 2)), paidAt: DateTime.now().subtract(const Duration(hours: 2)), verifyCode: 'VK8823', quantity: 2, scenicSpot: '智念风景区', ), OrderItem( id: 'ord_2', orderNo: 'ZN20240507002', customerName: '李女士', customerPhone: '139****6666', productName: '度假酒店豪华套房', amount: 888.00, status: OrderStatus.pendingPayment, createdAt: DateTime.now().subtract(const Duration(minutes: 30)), quantity: 1, scenicSpot: '智念度假酒店', ), OrderItem( id: 'ord_3', orderNo: 'ZN20240507003', customerName: '张 family', customerPhone: '137****5555', productName: '家庭亲子套票', amount: 388.00, status: OrderStatus.verified, createdAt: DateTime.now().subtract(const Duration(days: 1)), paidAt: DateTime.now().subtract(const Duration(days: 1)), verifiedAt: DateTime.now().subtract(const Duration(hours: 5)), verifyCode: 'VK9912', quantity: 3, scenicSpot: '智念风景区', ), OrderItem( id: 'ord_4', orderNo: 'ZN20240507004', customerName: '陈先生', customerPhone: '136****4444', productName: 'SPA养生套餐', amount: 598.00, status: OrderStatus.pendingRefund, createdAt: DateTime.now().subtract(const Duration(days: 2)), paidAt: DateTime.now().subtract(const Duration(days: 2)), verifyCode: 'VK7734', quantity: 1, remark: '客户行程变更申请退款', scenicSpot: '智念度假酒店', ), OrderItem( id: 'ord_5', orderNo: 'ZN20240507005', customerName: '赵女士', customerPhone: '135****3333', productName: '景区门票+酒店套餐', amount: 1588.00, status: OrderStatus.refunded, createdAt: DateTime.now().subtract(const Duration(days: 3)), paidAt: DateTime.now().subtract(const Duration(days: 3)), refundedAt: DateTime.now().subtract(const Duration(days: 1)), verifyCode: 'VK6651', quantity: 2, scenicSpot: '智念度假区', ), ]; if (status == OrderStatus.all) return allOrders; return allOrders.where((o) => o.status == status).toList(); } Future getOrderDetail(String id) async { await Future.delayed(const Duration(milliseconds: 400)); final orders = await getOrders(OrderStatus.all); return orders.firstWhere((o) => o.id == id, orElse: () => orders.first); } Future verifyOrder(String id) async { await Future.delayed(const Duration(milliseconds: 600)); final order = await getOrderDetail(id); return order.copyWith( status: OrderStatus.verified, verifiedAt: DateTime.now(), ); } Future scanVerify(String code) async { await Future.delayed(const Duration(milliseconds: 800)); final orders = await getOrders(OrderStatus.all); final order = orders.firstWhere( (o) => o.verifyCode == code || o.orderNo == code, orElse: () => OrderItem( id: 'ord_scan_${DateTime.now().millisecondsSinceEpoch}', orderNo: code, customerName: '扫码客户', customerPhone: '138****0000', productName: '景区门票', amount: 128.00, status: OrderStatus.pendingVerification, createdAt: DateTime.now(), verifyCode: code, quantity: 1, scenicSpot: '智念风景区', ), ); return order; } } final apiService = ApiService();