feat: 增加搜索设备页、团队管理页
This commit is contained in:
parent
8501b5ea48
commit
5bca96a4cf
@ -39,6 +39,10 @@ class _AppState extends State<App> {
|
||||
dialogBackgroundColor: Colors.white,
|
||||
appBarTheme: AppBarTheme(
|
||||
backgroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
scrolledUnderElevation: 0,
|
||||
)),
|
||||
// 必须配置以下三个本地化代理
|
||||
localizationsDelegates: const [
|
||||
|
||||
@ -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<BaseApiService>()));
|
||||
Get.put(UserApiService(Get.find<BaseApiService>()));
|
||||
|
||||
5
lib/common/constant/app_colors.dart
Normal file
5
lib/common/constant/app_colors.dart
Normal file
@ -0,0 +1,5 @@
|
||||
import 'dart:ui';
|
||||
|
||||
class AppColors {
|
||||
static Color scaffoldBackgroundColor = const Color(0xFFF6F7FB);
|
||||
}
|
||||
33
lib/common/constant/device_type.dart
Normal file
33
lib/common/constant/device_type.dart
Normal file
@ -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;
|
||||
}
|
||||
@ -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(),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@ -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';
|
||||
}
|
||||
@ -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>(() => ConfirmPairDeviceController());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
import 'package:starwork_flutter/base/base_controller.dart';
|
||||
|
||||
class ConfirmPairDeviceController extends BaseController{
|
||||
|
||||
}
|
||||
109
lib/views/device/confirmPairDevice/confirm_pair_device_view.dart
Normal file
109
lib/views/device/confirmPairDevice/confirm_pair_device_view.dart
Normal file
@ -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<ConfirmPairDeviceController> {
|
||||
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,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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<SearchDeviceItem> deviceList = <SearchDeviceItem>[].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<void> 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);
|
||||
}
|
||||
}
|
||||
|
||||
16
lib/views/device/searchDevice/search_device_model.dart
Normal file
16
lib/views/device/searchDevice/search_device_model.dart
Normal file
@ -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,
|
||||
});
|
||||
}
|
||||
@ -12,12 +12,18 @@ class SearchDeviceView extends GetView<SearchDeviceController> {
|
||||
@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<SearchDeviceController> {
|
||||
),
|
||||
],
|
||||
),
|
||||
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<void> _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,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@ -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<HomeTeamNoticeRowWidget> createState() => _HomeTeamNoticeRowWidgetState();
|
||||
State<HomeTeamNoticeRowWidget> createState() =>
|
||||
_HomeTeamNoticeRowWidgetState();
|
||||
}
|
||||
|
||||
class _HomeTeamNoticeRowWidgetState extends State<HomeTeamNoticeRowWidget> {
|
||||
@ -67,32 +70,37 @@ class _HomeTeamNoticeRowWidgetState extends State<HomeTeamNoticeRowWidget> {
|
||||
],
|
||||
),
|
||||
),
|
||||
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,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@ -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>(() => TeamNoticeDetailsController());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
import 'package:starwork_flutter/base/base_controller.dart';
|
||||
|
||||
class TeamNoticeDetailsController extends BaseController{}
|
||||
@ -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<TeamNoticeDetailsController> {
|
||||
const TeamNoticeDetailsView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// TODO: implement build
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
9
lib/views/main/teamNotice/team_notice_binding.dart
Normal file
9
lib/views/main/teamNotice/team_notice_binding.dart
Normal file
@ -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>(() => TeamNoticeController());
|
||||
}
|
||||
}
|
||||
27
lib/views/main/teamNotice/team_notice_controller.dart
Normal file
27
lib/views/main/teamNotice/team_notice_controller.dart
Normal file
@ -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<String> functionOptionList = ['公告管理', '公告栏'];
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
// 初始化TabController
|
||||
tabController = TabController(
|
||||
length: functionOptionList.length,
|
||||
vsync: this,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
tabController.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
405
lib/views/main/teamNotice/team_notice_view.dart
Normal file
405
lib/views/main/teamNotice/team_notice_view.dart
Normal file
@ -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<TeamNoticeController> {
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
79
pubspec.lock
79
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:
|
||||
|
||||
@ -36,6 +36,9 @@ dependencies:
|
||||
carousel_slider: ^5.1.1
|
||||
# 气泡提示框
|
||||
super_tooltip: ^2.0.8
|
||||
# 星云flutter SDK
|
||||
starcloud:
|
||||
path: ../starcloud-sdk-flutter
|
||||
|
||||
|
||||
dev_dependencies:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user