From 5bca96a4cf7f7a7fca1c96fc1aad9c7000d543be Mon Sep 17 00:00:00 2001 From: liyi Date: Fri, 5 Sep 2025 09:20:35 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E9=A1=B5=E3=80=81=E5=9B=A2=E9=98=9F=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/app.dart | 4 + lib/base/app_initialization.dart | 5 +- lib/common/constant/app_colors.dart | 5 + lib/common/constant/device_type.dart | 33 ++ lib/routes/app_pages.dart | 21 + lib/routes/app_routes.dart | 3 + .../confirm_pair_device_binding.dart | 9 + .../confirm_pair_device_controller.dart | 5 + .../confirm_pair_device_view.dart | 109 +++++ .../search_device_controller.dart | 56 ++- .../searchDevice/search_device_model.dart | 16 + .../searchDevice/search_device_view.dart | 186 +++++++- .../widget/home_team_notice_row_widget.dart | 58 +-- .../team_notice_details_binding.dart | 10 + .../team_notice_details_controller.dart | 3 + .../team_notice_details_view.dart | 13 + .../main/teamNotice/team_notice_binding.dart | 9 + .../teamNotice/team_notice_controller.dart | 27 ++ .../main/teamNotice/team_notice_view.dart | 405 ++++++++++++++++++ pubspec.lock | 79 ++++ pubspec.yaml | 3 + 21 files changed, 1017 insertions(+), 42 deletions(-) create mode 100644 lib/common/constant/app_colors.dart create mode 100644 lib/common/constant/device_type.dart create mode 100644 lib/views/device/confirmPairDevice/confirm_pair_device_binding.dart create mode 100644 lib/views/device/confirmPairDevice/confirm_pair_device_controller.dart create mode 100644 lib/views/device/confirmPairDevice/confirm_pair_device_view.dart create mode 100644 lib/views/device/searchDevice/search_device_model.dart create mode 100644 lib/views/main/teamNotice/teamNoticeDetails/team_notice_details_binding.dart create mode 100644 lib/views/main/teamNotice/teamNoticeDetails/team_notice_details_controller.dart create mode 100644 lib/views/main/teamNotice/teamNoticeDetails/team_notice_details_view.dart create mode 100644 lib/views/main/teamNotice/team_notice_binding.dart create mode 100644 lib/views/main/teamNotice/team_notice_controller.dart create mode 100644 lib/views/main/teamNotice/team_notice_view.dart diff --git a/lib/app.dart b/lib/app.dart index fad42fa..46632e0 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -39,6 +39,10 @@ class _AppState extends State { dialogBackgroundColor: Colors.white, appBarTheme: AppBarTheme( backgroundColor: Colors.white, + elevation: 0, + surfaceTintColor: Colors.transparent, + shadowColor: Colors.transparent, + scrolledUnderElevation: 0, )), // 必须配置以下三个本地化代理 localizationsDelegates: const [ diff --git a/lib/base/app_initialization.dart b/lib/base/app_initialization.dart index 99467f8..3a35165 100644 --- a/lib/base/app_initialization.dart +++ b/lib/base/app_initialization.dart @@ -4,12 +4,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:get/get.dart'; -import 'package:shared_preferences/shared_preferences.dart'; +import 'package:starcloud/sdk/starcloud.dart'; import 'package:starwork_flutter/api/base_api_service.dart'; import 'package:starwork_flutter/api/service/common_api_service.dart'; import 'package:starwork_flutter/api/service/user_api_service.dart'; import 'package:starwork_flutter/common/utils/shared_preferences_utils.dart'; -import 'package:starwork_flutter/i18n/app_i18n.dart'; import 'package:starwork_flutter/views/login/login_controller.dart'; import 'package:starwork_flutter/views/main/main_controller.dart'; @@ -20,7 +19,7 @@ class AppInitialization { setSystemStatusBar(); await SharedPreferencesUtils.init(); initEasyLoading(); - + StarCloudSDK.init(clientId: 'clientId', clientSecret: 'clientSecret'); Get.put(BaseApiService()); Get.put(CommonApiService(Get.find())); Get.put(UserApiService(Get.find())); diff --git a/lib/common/constant/app_colors.dart b/lib/common/constant/app_colors.dart new file mode 100644 index 0000000..f2203ee --- /dev/null +++ b/lib/common/constant/app_colors.dart @@ -0,0 +1,5 @@ +import 'dart:ui'; + +class AppColors { + static Color scaffoldBackgroundColor = const Color(0xFFF6F7FB); +} diff --git a/lib/common/constant/device_type.dart b/lib/common/constant/device_type.dart new file mode 100644 index 0000000..e807d9a --- /dev/null +++ b/lib/common/constant/device_type.dart @@ -0,0 +1,33 @@ +class DeviceType { + static const lock = DeviceType('1', '锁'); + static const gateway = DeviceType('2', '网关'); + static const attendanceMachine = DeviceType('3', '考勤机'); + final String value; + final String label; + + const DeviceType(this.value, this.label); + + // 支持通过字符串值查找枚举实例 + static DeviceType? fromValue(String? value) { + return { + '1': lock, + '2': gateway, + '3': attendanceMachine, + }[value]; + } + + // 支持 toString() 直接输出 value + @override + String toString() => value; + + // 可选:支持 == 比较 + @override + bool operator ==(Object other) => + identical(this, other) || + other is DeviceType && + runtimeType == other.runtimeType && + value == other.value; + + @override + int get hashCode => value.hashCode; +} diff --git a/lib/routes/app_pages.dart b/lib/routes/app_pages.dart index 52444d6..e2e1e9d 100644 --- a/lib/routes/app_pages.dart +++ b/lib/routes/app_pages.dart @@ -1,5 +1,7 @@ import 'package:get/get.dart'; import 'package:starwork_flutter/routes/app_routes.dart'; +import 'package:starwork_flutter/views/device/confirmPairDevice/confirm_pair_device_binding.dart'; +import 'package:starwork_flutter/views/device/confirmPairDevice/confirm_pair_device_view.dart'; import 'package:starwork_flutter/views/device/searchDevice/search_device_binding.dart'; import 'package:starwork_flutter/views/device/searchDevice/search_device_view.dart'; import 'package:starwork_flutter/views/home/home_binding.dart'; @@ -14,6 +16,10 @@ import 'package:starwork_flutter/views/login/login_binding.dart'; import 'package:starwork_flutter/views/login/login_view.dart'; import 'package:starwork_flutter/views/main/main_binding.dart'; import 'package:starwork_flutter/views/main/main_view.dart'; +import 'package:starwork_flutter/views/main/teamNotice/teamNoticeDetails/team_notice_details_binding.dart'; +import 'package:starwork_flutter/views/main/teamNotice/teamNoticeDetails/team_notice_details_view.dart'; +import 'package:starwork_flutter/views/main/teamNotice/team_notice_binding.dart'; +import 'package:starwork_flutter/views/main/teamNotice/team_notice_view.dart'; import 'package:starwork_flutter/views/messages/messages_binding.dart'; import 'package:starwork_flutter/views/messages/messages_view.dart'; import 'package:starwork_flutter/views/mine/mine_binding.dart'; @@ -67,5 +73,20 @@ class AppPages { page: () => const SearchDeviceView(), binding: SearchDeviceBinding(), ), + GetPage( + name: AppRoutes.confirmPairDevice, + page: () => const ConfirmPairDeviceView(), + binding: ConfirmPairDeviceBinding(), + ), + GetPage( + name: AppRoutes.teamNotice, + page: () => const TeamNoticeView(), + binding: TeamNoticeBinding(), + ), + GetPage( + name: AppRoutes.teamNoticeDetails, + page: () => const TeamNoticeDetailsView(), + binding: TeamNoticeDetailsBinding(), + ), ]; } diff --git a/lib/routes/app_routes.dart b/lib/routes/app_routes.dart index 1994e8b..4a457fd 100644 --- a/lib/routes/app_routes.dart +++ b/lib/routes/app_routes.dart @@ -9,4 +9,7 @@ class AppRoutes{ static const String forgotPassword = '/forgotPassword'; static const String setNewPassword = '/setNewPassword'; static const String searchDevice = '/searchDevice'; + static const String confirmPairDevice = '/confirmPairDevice'; + static const String teamNotice = '/teamNotice'; + static const String teamNoticeDetails = '/teamNoticeDetails'; } \ No newline at end of file diff --git a/lib/views/device/confirmPairDevice/confirm_pair_device_binding.dart b/lib/views/device/confirmPairDevice/confirm_pair_device_binding.dart new file mode 100644 index 0000000..ce56d27 --- /dev/null +++ b/lib/views/device/confirmPairDevice/confirm_pair_device_binding.dart @@ -0,0 +1,9 @@ +import 'package:get/get.dart'; +import 'package:starwork_flutter/views/device/confirmPairDevice/confirm_pair_device_controller.dart'; + +class ConfirmPairDeviceBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => ConfirmPairDeviceController()); + } +} diff --git a/lib/views/device/confirmPairDevice/confirm_pair_device_controller.dart b/lib/views/device/confirmPairDevice/confirm_pair_device_controller.dart new file mode 100644 index 0000000..1fb8cfd --- /dev/null +++ b/lib/views/device/confirmPairDevice/confirm_pair_device_controller.dart @@ -0,0 +1,5 @@ +import 'package:starwork_flutter/base/base_controller.dart'; + +class ConfirmPairDeviceController extends BaseController{ + +} \ No newline at end of file diff --git a/lib/views/device/confirmPairDevice/confirm_pair_device_view.dart b/lib/views/device/confirmPairDevice/confirm_pair_device_view.dart new file mode 100644 index 0000000..9bcafd9 --- /dev/null +++ b/lib/views/device/confirmPairDevice/confirm_pair_device_view.dart @@ -0,0 +1,109 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:starwork_flutter/views/device/confirmPairDevice/confirm_pair_device_controller.dart'; + +class ConfirmPairDeviceView extends GetView { + const ConfirmPairDeviceView({super.key}); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + FocusScope.of(context).unfocus(); + }, + child: Scaffold( + backgroundColor: const Color(0xFFF6F7FB), + appBar: AppBar( + title: Row( + children: [ + Text( + '确认连接设备'.tr, + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.w500, + color: Colors.black87, + ), + ), + ], + ), + ), + body: Column( + children: [ + SizedBox( + height: 30.h, + ), + Container( + padding: EdgeInsets.symmetric( + horizontal: 30.w, + ), + child: TextField( + decoration: InputDecoration( + hintText: '请输入内容', + // --- 边框设置 --- + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.r), // 圆角 + borderSide: const BorderSide( + color: Colors.blue, // 边框颜色 + width: 1.5, // 边框宽度 + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.r), + borderSide: const BorderSide( + color: Colors.grey, // 未获得焦点时的边框颜色 + width: 1.5, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.r), + borderSide: const BorderSide( + color: Colors.blue, // 获得焦点时的边框颜色 + width: 2.0, + ), + ), + // --- 内边距(可选,让文字不贴边)--- + contentPadding: EdgeInsets.symmetric( + horizontal: 10.w, + vertical: 14.h, + ), + ), + // --- 文字居中对齐 --- + textAlign: TextAlign.center, + // 可选:输入文本样式 + style: TextStyle( + fontSize: 16.sp, + color: Colors.black87, + fontWeight: FontWeight.w400, + ), + ), + ), + SizedBox( + height: 30.h, + ), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.r), + ), + padding: EdgeInsets.symmetric(horizontal: 80.w, vertical: 12.h), + // 或使用 EdgeInsets.all(16) 等 + ), + onPressed: () {}, + child: Text( + '确认连接'.tr, + style: TextStyle( + fontSize: 18.sp, + color: Colors.white, + ), + ), + ) + ], + ), + ), + ); + } +} diff --git a/lib/views/device/searchDevice/search_device_controller.dart b/lib/views/device/searchDevice/search_device_controller.dart index 16d9a66..83e9486 100644 --- a/lib/views/device/searchDevice/search_device_controller.dart +++ b/lib/views/device/searchDevice/search_device_controller.dart @@ -1,22 +1,64 @@ -import 'dart:ui'; - -import 'package:flutter/material.dart'; -import 'package:flutter_blue_plus/flutter_blue_plus.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import 'package:permission_handler/permission_handler.dart'; -import 'package:starwork_flutter/base/app_permission.dart'; import 'package:starwork_flutter/base/base_controller.dart'; +import 'package:starwork_flutter/routes/app_routes.dart'; +import 'package:starwork_flutter/views/device/searchDevice/search_device_model.dart'; class SearchDeviceController extends BaseController { // 搜索状态管理 final RxBool _isSearching = false.obs; + // 设备列表管理 + final RxList deviceList = [].obs; + // Getter bool get isSearching => _isSearching.value; @override void onInit() async { super.onInit(); + _initializeDevices(); + } + + // 初始化设备数据 + void _initializeDevices() { + deviceList.value = [ + SearchDeviceItem( + id: 'TMH_4564sa121dfsda', + name: 'TMH_4564sa121dfsda', + deviceType: '门禁设备', + isOnline: true, + ), + SearchDeviceItem( + id: 'TMH_4564sa121dfsdv', + name: 'TMH_4564sa121dfsdv', + deviceType: '门禁设备', + isOnline: true, + ), + ]; + } + + // 刷新设备数据 + Future refreshDevices() async { + // 设置搜索状态 + _isSearching.value = true; + showLoading(); + + // 模拟网络请求延迟 + await Future.delayed(const Duration(seconds: 2)); + + // 这里可以添加实际的设备搜索API调用 + // 模拟刷新数据 + _initializeDevices(); + + // 结束搜索状态 + _isSearching.value = false; + + hideLoading(); + print('设备搜索刷新完成'); + } + + // 连接设备 + void connectingDevices() async { + Get.toNamed(AppRoutes.confirmPairDevice); } } diff --git a/lib/views/device/searchDevice/search_device_model.dart b/lib/views/device/searchDevice/search_device_model.dart new file mode 100644 index 0000000..5c72a59 --- /dev/null +++ b/lib/views/device/searchDevice/search_device_model.dart @@ -0,0 +1,16 @@ + + +// 设备模型类 +class SearchDeviceItem { + final String id; + final String name; + final String deviceType; + final bool isOnline; + + SearchDeviceItem({ + required this.id, + required this.name, + required this.deviceType, + required this.isOnline, + }); +} \ No newline at end of file diff --git a/lib/views/device/searchDevice/search_device_view.dart b/lib/views/device/searchDevice/search_device_view.dart index 8ec92f2..66d7f32 100644 --- a/lib/views/device/searchDevice/search_device_view.dart +++ b/lib/views/device/searchDevice/search_device_view.dart @@ -12,12 +12,18 @@ class SearchDeviceView extends GetView { @override Widget build(BuildContext context) { return Scaffold( + backgroundColor: const Color(0xFFF6F7FB), appBar: AppBar( title: Row( children: [ - Obx(() => Text( - controller.isSearching ? '搜索设备中'.tr : '搜索设备'.tr, - )), + Text( + '搜索设备中'.tr, + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.w500, + color: Colors.black87, + ), + ), SizedBox( width: 8.w, ), @@ -30,11 +36,177 @@ class SearchDeviceView extends GetView { ), ], ), + actions: [ + TextButton( + onPressed: _onRefresh, + child: Text( + '刷新'.tr, + style: TextStyle( + fontSize: 16.sp, + color: Colors.black87, + fontWeight: FontWeight.w500, + ), + ), + ) + ], ), - body: Container( - // TODO: 添加设备搜索结果列表 - child: Center( - child: Text('设备搜索页面'), + body: Column( + children: [ + // 设备列表 + Expanded( + child: _buildRefreshableDeviceList(), + ), + // 固定在底部的提示信息 + _buildDeviceTip(), + ], + ), + ); + } + + // 构建下拉刷新的设备列表 + _buildRefreshableDeviceList() { + return RefreshIndicator( + onRefresh: _onRefresh, + // 基础样式配置 + color: const Color(0xFF4A90E2), + // 刷新指示器颜色 + backgroundColor: Colors.white, + // 背景颜色 + + // 控制下拉触发距离的关键属性 + displacement: 60.0, + // 刷新指示器距离顶部的距离 + + // 控制下拉幅度的关键属性 + triggerMode: RefreshIndicatorTriggerMode.onEdge, + // 触发模式 + + // 描边宽度 + strokeWidth: 2.5, + // 刷新指示器的描边宽度 + + // 语义标签(用于无障碍功能) + semanticsLabel: '下拉刷新设备列表', + semanticsValue: '刷新中...', + + child: SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics( + // 控制滚动物理特性 + parent: BouncingScrollPhysics(), // 添加弹性滚动效果 + ), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: MediaQuery.of(Get.context!).size.height - + MediaQuery.of(Get.context!).padding.top - + kToolbarHeight - + 60.h, // 减去AppBar高度、状态栏高度和底部提示区域高度 + ), + child: Column( + children: [ + _buildDeviceList(), + SizedBox(height: 16.h), + ], + ), + ), + ), + ); + } + + // 刷新方法 + Future _onRefresh() async { + // 调用controller的刷新方法 + await controller.refreshDevices(); + } + + // 构建设备列表 + _buildDeviceList() { + return Obx( + () => Column( + children: [ + // 动态生成设备列表项 + ...controller.deviceList.asMap().entries.map((entry) { + int index = entry.key; + var device = entry.value; + + return Column( + children: [ + // 如果是第一项,显示间距 + if (index == 0) SizedBox(height: 10.h), + _buildItem(device: device, index: index), + // 如果不是最后一项,显示间距 + if (index < controller.deviceList.length - 1) + SizedBox(height: 10.h), + ], + ); + }).toList(), + ], + ), + ); + } + + // 构建底部提示信息 + _buildDeviceTip() { + return Container( + padding: EdgeInsets.symmetric(vertical: 10.h), + child: Text( + '没有更多设备', + style: TextStyle( + fontSize: 12.sp, + color: Colors.grey[500], + fontWeight: FontWeight.w400, + ), + ), + ); + } + + _buildItem({required device, required int index}) { + return GestureDetector( + onTap: () { + controller.connectingDevices(); + }, + child: Container( + margin: EdgeInsets.symmetric(horizontal: 10.w), + padding: EdgeInsets.all(10.w), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all( + Radius.circular(8.r), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + const Icon( + Icons.lock, + color: Colors.blue, + ), + SizedBox( + width: 8.w, + ), + Text( + device.name, + style: TextStyle( + fontSize: 16.sp, + color: Colors.black87, + fontWeight: FontWeight.w400, + ), + ) + ], + ), + GestureDetector( + onTap: () { + // 处理添加设备事件 + print('添加设备 ${device.name}'); + // 这里可以添加具体的添加设备逻辑 + }, + child: const Icon( + Icons.add, + color: Colors.blue, + ), + ) + ], ), ), ); diff --git a/lib/views/home/widget/home_team_notice_row_widget.dart b/lib/views/home/widget/home_team_notice_row_widget.dart index bb48a0f..721b4b0 100644 --- a/lib/views/home/widget/home_team_notice_row_widget.dart +++ b/lib/views/home/widget/home_team_notice_row_widget.dart @@ -1,13 +1,16 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; +import 'package:starwork_flutter/routes/app_routes.dart'; class HomeTeamNoticeRowWidget extends StatefulWidget { const HomeTeamNoticeRowWidget({super.key}); @override - State createState() => _HomeTeamNoticeRowWidgetState(); + State createState() => + _HomeTeamNoticeRowWidgetState(); } class _HomeTeamNoticeRowWidgetState extends State { @@ -67,32 +70,37 @@ class _HomeTeamNoticeRowWidgetState extends State { ], ), ), - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - RichText( - text: TextSpan( - children: [ - TextSpan( - text: '全部'.tr, - style: TextStyle( - color: Colors.grey, - fontSize: 14.sp, - fontWeight: FontWeight.w400, + GestureDetector( + onTap: () { + Get.toNamed(AppRoutes.teamNotice); + }, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + RichText( + text: TextSpan( + children: [ + TextSpan( + text: '全部'.tr, + style: TextStyle( + color: Colors.grey, + fontSize: 14.sp, + fontWeight: FontWeight.w400, + ), ), - ), - ], + ], + ), ), - ), - SizedBox( - width: 4.w, - ), - Icon( - Icons.arrow_forward_ios_rounded, - color: Colors.grey, - size: 12.sp, - ) - ], + SizedBox( + width: 4.w, + ), + Icon( + Icons.arrow_forward_ios_rounded, + color: Colors.grey, + size: 12.sp, + ) + ], + ), ), ], ), diff --git a/lib/views/main/teamNotice/teamNoticeDetails/team_notice_details_binding.dart b/lib/views/main/teamNotice/teamNoticeDetails/team_notice_details_binding.dart new file mode 100644 index 0000000..c7fa0a8 --- /dev/null +++ b/lib/views/main/teamNotice/teamNoticeDetails/team_notice_details_binding.dart @@ -0,0 +1,10 @@ +import 'package:get/get.dart'; +import 'package:starwork_flutter/views/main/teamNotice/teamNoticeDetails/team_notice_details_controller.dart'; + +class TeamNoticeDetailsBinding extends Bindings{ + @override + void dependencies() { + Get.lazyPut(() => TeamNoticeDetailsController()); + } + +} \ No newline at end of file diff --git a/lib/views/main/teamNotice/teamNoticeDetails/team_notice_details_controller.dart b/lib/views/main/teamNotice/teamNoticeDetails/team_notice_details_controller.dart new file mode 100644 index 0000000..7b7fb6b --- /dev/null +++ b/lib/views/main/teamNotice/teamNoticeDetails/team_notice_details_controller.dart @@ -0,0 +1,3 @@ +import 'package:starwork_flutter/base/base_controller.dart'; + +class TeamNoticeDetailsController extends BaseController{} \ No newline at end of file diff --git a/lib/views/main/teamNotice/teamNoticeDetails/team_notice_details_view.dart b/lib/views/main/teamNotice/teamNoticeDetails/team_notice_details_view.dart new file mode 100644 index 0000000..4c1cbc0 --- /dev/null +++ b/lib/views/main/teamNotice/teamNoticeDetails/team_notice_details_view.dart @@ -0,0 +1,13 @@ +import 'package:flutter/src/widgets/framework.dart'; +import 'package:get/get.dart'; +import 'package:starwork_flutter/views/main/teamNotice/teamNoticeDetails/team_notice_details_controller.dart'; + +class TeamNoticeDetailsView extends GetView { + const TeamNoticeDetailsView({super.key}); + + @override + Widget build(BuildContext context) { + // TODO: implement build + throw UnimplementedError(); + } +} diff --git a/lib/views/main/teamNotice/team_notice_binding.dart b/lib/views/main/teamNotice/team_notice_binding.dart new file mode 100644 index 0000000..eb54104 --- /dev/null +++ b/lib/views/main/teamNotice/team_notice_binding.dart @@ -0,0 +1,9 @@ +import 'package:get/get.dart'; +import 'package:starwork_flutter/views/main/teamNotice/team_notice_controller.dart'; + +class TeamNoticeBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => TeamNoticeController()); + } +} diff --git a/lib/views/main/teamNotice/team_notice_controller.dart b/lib/views/main/teamNotice/team_notice_controller.dart new file mode 100644 index 0000000..6f272e0 --- /dev/null +++ b/lib/views/main/teamNotice/team_notice_controller.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:get/get_state_manager/src/rx_flutter/rx_ticket_provider_mixin.dart'; +import 'package:starwork_flutter/base/base_controller.dart'; + +class TeamNoticeController extends BaseController + with GetSingleTickerProviderStateMixin { + late TabController tabController; + + // TabBar选项列表 + final List functionOptionList = ['公告管理', '公告栏']; + + @override + void onInit() { + super.onInit(); + // 初始化TabController + tabController = TabController( + length: functionOptionList.length, + vsync: this, + ); + } + + @override + void onClose() { + tabController.dispose(); + super.onClose(); + } +} diff --git a/lib/views/main/teamNotice/team_notice_view.dart b/lib/views/main/teamNotice/team_notice_view.dart new file mode 100644 index 0000000..7772bcf --- /dev/null +++ b/lib/views/main/teamNotice/team_notice_view.dart @@ -0,0 +1,405 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:starwork_flutter/common/constant/app_colors.dart'; +import 'package:starwork_flutter/views/main/teamNotice/team_notice_controller.dart'; + +class TeamNoticeView extends GetView { + const TeamNoticeView({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Colors.white, + elevation: 0, + surfaceTintColor: Colors.transparent, + shadowColor: Colors.transparent, + scrolledUnderElevation: 0, + leading: null, + automaticallyImplyLeading: false, + title: Row( + children: [ + Text( + '公告'.tr, + style: TextStyle( + fontSize: 18.sp, + fontWeight: FontWeight.w500, + color: Colors.black87, + ), + ), + ], + ), + ), + body: Column( + children: [ + TabBar( + controller: controller.tabController, + isScrollable: false, + // 改为false让TabBar占满宽度 + labelColor: Colors.blue, + // 选中文字颜色改为蓝色 + unselectedLabelColor: Colors.grey, + labelStyle: TextStyle( + fontSize: 16.sp, + fontWeight: FontWeight.w600, + ), + unselectedLabelStyle: TextStyle( + fontSize: 14.sp, + fontWeight: FontWeight.w400, + ), + indicatorColor: Colors.blue, + // 下划线颜色改为蓝色 + indicatorWeight: 2.h, + // 稍微增加下划线粗细 + indicatorSize: TabBarIndicatorSize.tab, + // 改为tab让指示器占满每个选项卡宽度 + dividerColor: Colors.transparent, + tabs: controller.functionOptionList + .map((title) => Tab(text: title)) + .toList(), + ), + Expanded( + child: TabBarView( + controller: controller.tabController, + children: [ + _buildNoticeManagementPage(), + _buildNoticeBoardPage(), + ], + ), + ), + ], + ), + ); + } + + /// 构建公告管理页面 + Widget _buildNoticeManagementPage() { + return Scaffold( + backgroundColor: AppColors.scaffoldBackgroundColor, + body: Column( + children: [ + // 列表区域(可滚动) + Expanded( + child: _buildNoticeManageList(), + ), + // 底部按钮(固定) + _buildBottomButtons(), + ], + ), + ); + } + + /// 构建公告管理列表 + Widget _buildNoticeManageList() { + return RefreshIndicator( + onRefresh: () async { + // 模拟下拉刷新 + await Future.delayed(const Duration(seconds: 2)); + Get.snackbar('提示', '刷新成功'); + }, + color: Colors.blue, + displacement: 60.0, + child: ListView.separated( + physics: const AlwaysScrollableScrollPhysics(), + padding: EdgeInsets.symmetric( + horizontal: 16.w, + vertical: 16.h, + ), + itemCount: 8, + // 模拟8条记录 + separatorBuilder: (context, index) => SizedBox(height: 12.h), + itemBuilder: (context, index) { + return _buildNoticeManageListItem(); + }, + ), + ); + } + + /// 构建底部按钮区域 + Widget _buildBottomButtons() { + return Container( + padding: EdgeInsets.all(16.w), + decoration: BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.1), + spreadRadius: 0, + blurRadius: 4, + offset: const Offset(0, -2), + ), + ], + ), + child: Row( + children: [ + // 草稿箱按钮 + Expanded( + flex: 1, + child: OutlinedButton( + onPressed: () { + // 草稿箱功能 + Get.snackbar('提示', '保存到草稿箱'); + }, + style: OutlinedButton.styleFrom( + padding: EdgeInsets.symmetric(vertical: 12.h), + side: BorderSide(color: Colors.grey[300]!), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.r), + ), + ), + child: Text( + '草稿箱', + style: TextStyle( + fontSize: 16.sp, + color: Colors.grey[700], + ), + ), + ), + ), + + SizedBox(width: 12.w), + + // 发布公告按钮 + Expanded( + flex: 2, + child: ElevatedButton( + onPressed: () { + // 发布公告功能 + Get.snackbar('提示', '公告发布成功'); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + padding: EdgeInsets.symmetric(vertical: 12.h), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.r), + ), + elevation: 0, + ), + child: Text( + '发布公告', + style: TextStyle( + fontSize: 16.sp, + color: Colors.white, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + ], + ), + ); + } + + /// 构建公告栏页面 + Widget _buildNoticeBoardPage() { + return Container( + padding: EdgeInsets.all(16.w), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '公告栏', + style: TextStyle( + fontSize: 20.sp, + fontWeight: FontWeight.w600, + color: Colors.black87, + ), + ), + SizedBox(height: 16.h), + Expanded( + child: ListView.builder( + itemCount: 5, // 模拟5条公告 + itemBuilder: (context, index) { + return Container( + margin: EdgeInsets.only(bottom: 12.h), + padding: EdgeInsets.all(16.w), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.r), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.1), + spreadRadius: 1, + blurRadius: 3, + offset: const Offset(0, 1), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + padding: EdgeInsets.symmetric( + horizontal: 8.w, + vertical: 4.h, + ), + decoration: BoxDecoration( + color: Colors.red[50], + borderRadius: BorderRadius.circular(4.r), + ), + child: Text( + '重要', + style: TextStyle( + fontSize: 12.sp, + color: Colors.red, + fontWeight: FontWeight.w500, + ), + ), + ), + SizedBox(width: 8.w), + Expanded( + child: Text( + '公告标题 ${index + 1}', + style: TextStyle( + fontSize: 16.sp, + fontWeight: FontWeight.w600, + color: Colors.black87, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + SizedBox(height: 8.h), + Text( + '这里是公告的详细内容,包含了重要的信息和通知事项。请各位同事仔细阅读并遵照执行。', + style: TextStyle( + fontSize: 14.sp, + color: Colors.grey[700], + height: 1.5, + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + SizedBox(height: 12.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '2024-01-${15 + index}', + style: TextStyle( + fontSize: 12.sp, + color: Colors.grey[500], + ), + ), + Row( + children: [ + Icon( + Icons.visibility_outlined, + size: 16.w, + color: Colors.grey[500], + ), + SizedBox(width: 4.w), + Text( + '${(index + 1) * 23}', + style: TextStyle( + fontSize: 12.sp, + color: Colors.grey[500], + ), + ), + ], + ), + ], + ), + ], + ), + ); + }, + ), + ), + ], + ), + ); + } + + _buildNoticeManageListItem() { + return Stack( + children: [ + Container( + padding: EdgeInsets.symmetric( + horizontal: 10.w, + vertical: 10.h, + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.r), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 0.8.sw, // 限制最大宽度 + child: Text( + '1', + maxLines: 1, // 限制为一行 + overflow: TextOverflow.ellipsis, // 超出部分显示省略号 + style: TextStyle( + fontSize: 24.sp, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + ), + SizedBox( + height: 4.h, + ), + SizedBox( + width: 0.8.sw, // 限制最大宽度 + child: Text( + '112312', + maxLines: 3, // 限制为一行 + overflow: TextOverflow.ellipsis, // 超出部分显示省略号 + style: TextStyle( + fontSize: 16.sp, + color: Colors.black87, + ), + ), + ), + SizedBox( + height: 4.h, + ), + Text( + 'HHMMail 30015524 2024-12-17', + style: TextStyle( + fontSize: 12.sp, + color: Colors.grey[600], + ), + ), + ], + ), + ], + ), + ), + Positioned( + right: 0.w, + top: 0.h, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 4.w, vertical: 4.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(8.r), + topRight: Radius.circular(8.r), + ), + color: Colors.grey[300], + ), + child: Text( + '已撤回'.tr, + style: TextStyle( + fontSize: 10.sp, + color: Colors.grey, + ), + ), + ), + ) + ], + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index a921ca1..22b2e0b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -25,6 +25,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.11.0" + bluez: + dependency: transitive + description: + name: bluez + sha256: "61a7204381925896a374301498f2f5399e59827c6498ae1e924aaa598751b545" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.8.3" boolean_selector: dependency: transitive description: @@ -89,6 +97,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.0.8" + dbus: + dependency: transitive + description: + name: dbus + sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.7.11" dio: dependency: "direct main" description: @@ -134,6 +150,54 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_blue_plus: + dependency: transitive + description: + name: flutter_blue_plus + sha256: bfae0d24619940516261045d8b3c74b4c80ca82222426e05ffbf7f3ea9dbfb1a + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.35.5" + flutter_blue_plus_android: + dependency: transitive + description: + name: flutter_blue_plus_android + sha256: "9723dd4ba7dcc3f27f8202e1159a302eb4cdb88ae482bb8e0dd733b82230a258" + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.0.5" + flutter_blue_plus_darwin: + dependency: transitive + description: + name: flutter_blue_plus_darwin + sha256: f34123795352a9761e321589aa06356d3b53f007f13f7e23e3c940e733259b2d + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.0.1" + flutter_blue_plus_linux: + dependency: transitive + description: + name: flutter_blue_plus_linux + sha256: "635443d1d333e3695733fd70e81ee0d87fa41e78aa81844103d2a8a854b0d593" + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.2" + flutter_blue_plus_platform_interface: + dependency: transitive + description: + name: flutter_blue_plus_platform_interface + sha256: a4bb70fa6fd09e0be163b004d773bf19e31104e257a4eb846b67f884ddd87de2 + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.0.2" + flutter_blue_plus_web: + dependency: transitive + description: + name: flutter_blue_plus_web + sha256: "03023c259dbbba1bc5ce0fcd4e88b364f43eec01d45425f393023b9b2722cf4d" + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.1" flutter_easyloading: dependency: "direct main" description: @@ -421,6 +485,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "6.0.3" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.28.0" shared_preferences: dependency: "direct main" description: @@ -506,6 +578,13 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.11.1" + starcloud: + dependency: "direct main" + description: + path: "../starcloud-sdk-flutter" + relative: true + source: path + version: "0.1.2" stream_channel: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 49c5c39..2a75e8f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,6 +36,9 @@ dependencies: carousel_slider: ^5.1.1 # 气泡提示框 super_tooltip: ^2.0.8 + # 星云flutter SDK + starcloud: + path: ../starcloud-sdk-flutter dev_dependencies: