- 登录:工号+密码走 account-service /api/login,自动登录、被踢下线回登录页 - 消息:会话列表(未读角标/免打扰/时间)、单聊群聊、文字/语音/图片/文件消息、失败重发、历史分页 - 通讯录:新的同事/我的群聊入口、按部门分组(好友 ex 字段)、搜索 - 通话:一对一语音通话(信令走 OpenIM 自定义消息 + LiveKit,token 走 /api/rtc_token) - 界面按确认效果图 m1/m2/m3 实现,主色 #3B87F5,四态视图齐全,无英文残留
135 lines
4.6 KiB
Dart
135 lines
4.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../theme.dart';
|
|
|
|
/// 空 / 加载中 / 加载失败 / 断网 四态组件,文案严格按效果图 states.png。
|
|
|
|
/// 空态:还没有消息
|
|
class EmptyConversations extends StatelessWidget {
|
|
/// 「去找同事」按钮点击(跳到通讯录 Tab)
|
|
final VoidCallback? onFindContacts;
|
|
|
|
const EmptyConversations({super.key, this.onFindContacts});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Center(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
const Icon(Icons.chat_bubble_outline, size: 64, color: AppColors.divider),
|
|
const SizedBox(height: AppGap.x6),
|
|
const Text('还没有消息', style: TextStyle(fontSize: AppFont.body, color: AppColors.textPrimary)),
|
|
const SizedBox(height: AppGap.x2),
|
|
const Text('去通讯录找同事聊聊吧', style: TextStyle(fontSize: AppFont.sub, color: AppColors.textSecondary)),
|
|
const SizedBox(height: AppGap.x6),
|
|
FilledButton(
|
|
onPressed: onFindContacts,
|
|
style: FilledButton.styleFrom(
|
|
backgroundColor: AppColors.primary,
|
|
padding: const EdgeInsets.symmetric(horizontal: AppGap.x6, vertical: AppGap.x3),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
),
|
|
child: const Text('去找同事', style: TextStyle(fontSize: AppFont.body)),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 加载中
|
|
class LoadingConversations extends StatelessWidget {
|
|
const LoadingConversations({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return const Center(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
SizedBox(
|
|
width: 32,
|
|
height: 32,
|
|
child: CircularProgressIndicator(strokeWidth: 3, color: AppColors.primary),
|
|
),
|
|
SizedBox(height: AppGap.x6),
|
|
Text('正在加载', style: TextStyle(fontSize: AppFont.body, color: AppColors.textPrimary)),
|
|
SizedBox(height: AppGap.x2),
|
|
Text('消息马上就好,请稍等', style: TextStyle(fontSize: AppFont.sub, color: AppColors.textSecondary)),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 加载失败
|
|
class ErrorConversations extends StatelessWidget {
|
|
final VoidCallback? onRetry;
|
|
|
|
const ErrorConversations({super.key, this.onRetry});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Center(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
const Icon(Icons.error_outline, size: 64, color: AppColors.divider),
|
|
const SizedBox(height: AppGap.x6),
|
|
const Text('消息没加载出来', style: TextStyle(fontSize: AppFont.body, color: AppColors.textPrimary)),
|
|
const SizedBox(height: AppGap.x2),
|
|
const Text('检查一下网络,再点重试', style: TextStyle(fontSize: AppFont.sub, color: AppColors.textSecondary)),
|
|
const SizedBox(height: AppGap.x6),
|
|
OutlinedButton(
|
|
onPressed: onRetry,
|
|
style: OutlinedButton.styleFrom(
|
|
foregroundColor: AppColors.primary,
|
|
side: const BorderSide(color: AppColors.primary),
|
|
padding: const EdgeInsets.symmetric(horizontal: AppGap.x6, vertical: AppGap.x3),
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
|
),
|
|
child: const Text('重试', style: TextStyle(fontSize: AppFont.body)),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 断网时顶部的深色横幅
|
|
class OfflineBanner extends StatelessWidget {
|
|
const OfflineBanner({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
width: double.infinity,
|
|
color: AppColors.bannerBg,
|
|
padding: const EdgeInsets.symmetric(horizontal: AppGap.x4, vertical: AppGap.x2),
|
|
child: const Row(
|
|
children: [
|
|
Icon(Icons.error_outline, size: 16, color: Colors.white),
|
|
SizedBox(width: AppGap.x2),
|
|
Text('当前网络不可用,请检查网络连接', style: TextStyle(fontSize: AppFont.sub, color: Colors.white)),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 断网时列表底部的灰字提示
|
|
class OfflineFooter extends StatelessWidget {
|
|
const OfflineFooter({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return const Padding(
|
|
padding: EdgeInsets.symmetric(vertical: AppGap.x4),
|
|
child: Center(
|
|
child: Text('老消息还能看,新消息联网后自动收到', style: TextStyle(fontSize: AppFont.small, color: AppColors.textSecondary)),
|
|
),
|
|
);
|
|
}
|
|
}
|