feat(messages): add invite list and detail screens

This commit is contained in:
qzl
2026-02-25 11:05:42 +08:00
parent 2541e10304
commit b5cce74f49
2 changed files with 429 additions and 0 deletions
@@ -0,0 +1,293 @@
import 'package:flutter/material.dart' hide BackButton;
import 'package:go_router/go_router.dart';
import '../../../../core/theme/design_tokens.dart';
import '../../../../shared/widgets/page_header.dart';
class MessageInviteDetailScreen extends StatefulWidget {
const MessageInviteDetailScreen({super.key});
@override
State<MessageInviteDetailScreen> createState() =>
_MessageInviteDetailScreenState();
}
class _MessageInviteDetailScreenState extends State<MessageInviteDetailScreen> {
final _reasonController = TextEditingController();
@override
void dispose() {
_reasonController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.messageBg,
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
PageHeader(leading: BackButton(onPressed: () => context.pop())),
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.only(left: 20, right: 20, bottom: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSummaryCard(),
const SizedBox(height: 14),
_buildCalendarTip(),
const SizedBox(height: 14),
_buildActionRow(),
const SizedBox(height: 14),
_buildRejectReasonCard(),
],
),
),
),
],
),
),
);
}
Widget _buildSummaryCard() {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: AppColors.messageCardBg,
borderRadius: BorderRadius.circular(16),
border: Border.all(color: AppColors.messageCardBorder),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text(
'日历邀请详情',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.slate900,
),
),
SizedBox(height: 10),
Text(
'事件:产品评审会',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColors.slate700,
),
),
SizedBox(height: 10),
Text(
'邀请人:李文浩(产品经理)',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.normal,
color: AppColors.slate500,
),
),
SizedBox(height: 10),
Text(
'时间:2026-02-12 14:00 - 15:30',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.normal,
color: AppColors.slate500,
),
),
SizedBox(height: 10),
Text(
'地点:3F-A 会议室 / 腾讯会议 231-889-100',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.normal,
color: AppColors.slate500,
),
),
SizedBox(height: 10),
Text(
'备注:请提前准备本周版本风险与排期结论。',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.normal,
color: AppColors.slate500,
),
),
],
),
);
}
Widget _buildCalendarTip() {
return Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
decoration: BoxDecoration(
color: AppColors.messageTipBg,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColors.messageTipBorder),
),
child: Row(
children: const [
Icon(Icons.info_outline, size: 14, color: AppColors.slate500),
SizedBox(width: 8),
Expanded(
child: Text(
'更多附件与相关链接,请在订阅后在日历中查看',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.normal,
color: AppColors.slate500,
),
),
),
],
),
);
}
Widget _buildActionRow() {
return SizedBox(
height: 46,
child: Row(
children: [
Expanded(
child: GestureDetector(
onTap: _handleReject,
child: Container(
decoration: BoxDecoration(
color: AppColors.messageCardBg,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColors.messageRejectBorder),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
'×',
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w700,
color: AppColors.red400,
),
),
SizedBox(width: 6),
Text(
'拒绝',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: AppColors.red400,
),
),
],
),
),
),
),
const SizedBox(width: 10),
Expanded(
child: GestureDetector(
onTap: _handleAccept,
child: Container(
decoration: BoxDecoration(
color: AppColors.messageTagBg,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColors.messageAcceptBorder),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
'',
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w700,
color: AppColors.blue600,
),
),
SizedBox(width: 6),
Text(
'同意',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: AppColors.blue600,
),
),
],
),
),
),
),
],
),
);
}
Widget _buildRejectReasonCard() {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: AppColors.messageCardBg,
borderRadius: BorderRadius.circular(14),
border: Border.all(color: AppColors.messageReasonBorder),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'拒绝补充信息(可选)',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
color: AppColors.slate600,
),
),
const SizedBox(height: 8),
Container(
height: 92,
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: AppColors.messageBtnWrap,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: AppColors.messageInputBorder),
),
child: TextField(
controller: _reasonController,
maxLines: null,
expands: true,
style: const TextStyle(fontSize: 12, color: AppColors.slate700),
decoration: const InputDecoration(
border: InputBorder.none,
hintText: '可填写拒绝原因,例如:该时间段已有客户会议,无法参加。',
hintStyle: TextStyle(
fontSize: 12,
fontWeight: FontWeight.normal,
color: AppColors.messagePlaceholder,
),
contentPadding: EdgeInsets.zero,
),
),
),
],
),
);
}
void _handleReject() {
final reason = _reasonController.text;
debugPrint('Reject with reason: $reason');
context.pop();
}
void _handleAccept() {
debugPrint('Accept invitation');
context.pop();
}
}
@@ -0,0 +1,136 @@
import 'package:flutter/material.dart' hide BackButton;
import 'package:go_router/go_router.dart';
import '../../../../core/theme/design_tokens.dart';
import '../../../../shared/widgets/page_header.dart';
class MessageInviteListScreen extends StatelessWidget {
const MessageInviteListScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.messageBg,
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
PageHeader(leading: BackButton(onPressed: () => context.pop())),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 20, right: 20, bottom: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildRemindTag(),
const SizedBox(height: 12),
_buildInviteCard(context),
const Spacer(),
],
),
),
),
],
),
),
);
}
Widget _buildRemindTag() {
return Container(
height: 24,
padding: const EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
color: AppColors.messageTagBg,
borderRadius: BorderRadius.circular(12),
),
child: const Center(
child: Text(
'消息提醒',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: AppColors.blue600,
),
),
),
);
}
Widget _buildInviteCard(BuildContext context) {
return GestureDetector(
onTap: () => context.push('/messages/invite/detail'),
child: Container(
width: double.infinity,
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: AppColors.messageCardBg,
borderRadius: BorderRadius.circular(16),
border: Border.all(color: AppColors.messageCardBorder),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
Container(
width: 44,
height: 44,
decoration: BoxDecoration(
color: AppColors.messageCalendarBg,
borderRadius: BorderRadius.circular(12),
),
child: const Icon(
Icons.calendar_today_outlined,
size: 20,
color: AppColors.blue500,
),
),
],
),
const SizedBox(height: 8),
const Text(
'事件:产品评审会 2026-02-12 14:00',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: AppColors.slate700,
),
),
const SizedBox(height: 8),
const Text(
'邀请人:李文浩',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.normal,
color: AppColors.slate500,
),
),
const SizedBox(height: 8),
const Text(
'点击查看详情并处理邀请',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.normal,
color: AppColors.slate400,
),
),
],
),
),
const SizedBox(width: 8),
Icon(
Icons.chevron_right,
size: 16,
color: AppColors.messageArrowColor,
),
],
),
),
);
}
}