From a0131636a52f8afd336c02f93d38e4ca5374b302 Mon Sep 17 00:00:00 2001 From: "DESKTOP-I3JPKHK\\wy" <1111> Date: Mon, 15 Sep 2025 10:21:14 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=B8=80=E6=89=B9=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../.vscode/settings.json | 3 +- .../lib/common/utils/platform_utils.dart | 11 + making_school_asignment_app/lib/main.dart | 11 +- .../global_widget/desktop_page_template.dart | 125 +++++ .../page/global_widget/desktop_scaffold.dart | 100 ++++ .../global_widget/other_desktop_page.dart | 159 ++++++ .../page/global_widget/other_mobile_page.dart | 189 +++++++ .../lib/page/global_widget/other_page.dart | 196 +------- .../lib/page/global_widget/start_page.dart | 132 ++--- .../class_student_desktop_view.dart | 183 +++++++ .../class_student_mobile_view.dart | 341 +++++++++++++ .../class_student/class_student_view.dart | 436 +--------------- .../lib/page/home_page/children/my_info.dart | 244 +-------- .../home_page/children/my_info_desktop.dart | 229 +++++++++ .../home_page/children/my_info_mobile.dart | 247 +++++++++ .../read_over/read_over_desktop_view.dart | 175 +++++++ .../read_over/read_over_mobile_view.dart | 174 +++++++ .../children/read_over/read_over_view.dart | 194 +------ .../lib/page/home_page/home_desktop_view.dart | 217 ++++++++ .../lib/page/home_page/home_mobile_view.dart | 436 ++++++++++++++++ .../lib/page/home_page/home_view.dart | 473 +----------------- .../children/agreement_desktop.dart | 65 +++ .../login_page/children/agreement_mobile.dart | 29 ++ .../login_page/children/agreement_page.dart | 24 +- .../page/login_page/children/register.dart | 288 +---------- .../login_page/children/register_desktop.dart | 207 ++++++++ .../login_page/children/register_mobile.dart | 292 +++++++++++ .../page/login_page/login_desktop_view.dart | 231 +++++++++ .../page/login_page/login_mobile_view.dart | 404 +++++++++++++++ .../lib/page/login_page/login_view.dart | 392 +-------------- .../lib/page/work_page/work_desktop_view.dart | 118 +++++ .../lib/page/work_page/work_mobile_view.dart | 141 ++++++ .../lib/page/work_page/work_view.dart | 140 +----- 33 files changed, 4198 insertions(+), 2408 deletions(-) create mode 100644 making_school_asignment_app/lib/common/utils/platform_utils.dart create mode 100644 making_school_asignment_app/lib/page/global_widget/desktop_page_template.dart create mode 100644 making_school_asignment_app/lib/page/global_widget/desktop_scaffold.dart create mode 100644 making_school_asignment_app/lib/page/global_widget/other_desktop_page.dart create mode 100644 making_school_asignment_app/lib/page/global_widget/other_mobile_page.dart create mode 100644 making_school_asignment_app/lib/page/home_page/children/class_student/class_student_desktop_view.dart create mode 100644 making_school_asignment_app/lib/page/home_page/children/class_student/class_student_mobile_view.dart create mode 100644 making_school_asignment_app/lib/page/home_page/children/my_info_desktop.dart create mode 100644 making_school_asignment_app/lib/page/home_page/children/my_info_mobile.dart create mode 100644 making_school_asignment_app/lib/page/home_page/children/read_over/read_over_desktop_view.dart create mode 100644 making_school_asignment_app/lib/page/home_page/children/read_over/read_over_mobile_view.dart create mode 100644 making_school_asignment_app/lib/page/home_page/home_desktop_view.dart create mode 100644 making_school_asignment_app/lib/page/home_page/home_mobile_view.dart create mode 100644 making_school_asignment_app/lib/page/login_page/children/agreement_desktop.dart create mode 100644 making_school_asignment_app/lib/page/login_page/children/agreement_mobile.dart create mode 100644 making_school_asignment_app/lib/page/login_page/children/register_desktop.dart create mode 100644 making_school_asignment_app/lib/page/login_page/children/register_mobile.dart create mode 100644 making_school_asignment_app/lib/page/login_page/login_desktop_view.dart create mode 100644 making_school_asignment_app/lib/page/login_page/login_mobile_view.dart create mode 100644 making_school_asignment_app/lib/page/work_page/work_desktop_view.dart create mode 100644 making_school_asignment_app/lib/page/work_page/work_mobile_view.dart diff --git a/making_school_asignment_app/.vscode/settings.json b/making_school_asignment_app/.vscode/settings.json index 17f2bdf..ba7ae34 100644 --- a/making_school_asignment_app/.vscode/settings.json +++ b/making_school_asignment_app/.vscode/settings.json @@ -1,3 +1,4 @@ { - "dart.flutterSdkPath": ".fvm/versions/3.32.0" + "dart.flutterSdkPath": ".fvm/versions/3.32.0", + "java.configuration.updateBuildConfiguration": "interactive" } \ No newline at end of file diff --git a/making_school_asignment_app/lib/common/utils/platform_utils.dart b/making_school_asignment_app/lib/common/utils/platform_utils.dart new file mode 100644 index 0000000..1520787 --- /dev/null +++ b/making_school_asignment_app/lib/common/utils/platform_utils.dart @@ -0,0 +1,11 @@ +import 'package:flutter/foundation.dart'; + +class PlatformUtils { + static bool get isDesktop => + defaultTargetPlatform == TargetPlatform.windows || + defaultTargetPlatform == TargetPlatform.linux || + defaultTargetPlatform == TargetPlatform.macOS; + + static bool get isMobile => + defaultTargetPlatform == TargetPlatform.android || defaultTargetPlatform == TargetPlatform.iOS; +} diff --git a/making_school_asignment_app/lib/main.dart b/making_school_asignment_app/lib/main.dart index 12dc883..b40be6f 100644 --- a/making_school_asignment_app/lib/main.dart +++ b/making_school_asignment_app/lib/main.dart @@ -11,6 +11,7 @@ import 'package:get/get.dart'; import 'package:making_school_asignment_app/common/config/app_config.dart'; import 'package:making_school_asignment_app/common/config/colorUtils.dart'; import 'package:making_school_asignment_app/common/store/user_store.dart'; +import 'package:making_school_asignment_app/common/utils/platform_utils.dart'; import 'package:making_school_asignment_app/common/utils/storage.dart'; import 'package:making_school_asignment_app/common/utils/utils.dart'; import 'package:making_school_asignment_app/routes/app_pages.dart'; @@ -41,8 +42,11 @@ void main() async { statusBarColor: Colors.transparent, //状态栏背景颜色 statusBarIconBrightness: Brightness.light // dark:一般显示黑色 light:一般显示白色 )); - SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky, overlays: [SystemUiOverlay.top]); // 屏幕刘海 - await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); // 屏幕强制竖屏 + if (PlatformUtils.isMobile) { + SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky, overlays: [SystemUiOverlay.top]); // 屏幕刘海 + await SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); // 屏幕强制竖屏 + } runApp(const MyApp()); Future.delayed(const Duration(seconds: 3), () => FlutterNativeSplash.remove()); @@ -57,7 +61,8 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { // String? oldRouter; return ScreenUtilInit( - designSize: const Size(AppConfig.UI_WIDTH, AppConfig.UI_HEIGHT), + designSize: + PlatformUtils.isDesktop ? const Size(1920, 1080) : const Size(AppConfig.UI_WIDTH, AppConfig.UI_HEIGHT), /* minTextAdapt: true, splitScreenMode: true,*/ builder: () => GetMaterialApp( diff --git a/making_school_asignment_app/lib/page/global_widget/desktop_page_template.dart b/making_school_asignment_app/lib/page/global_widget/desktop_page_template.dart new file mode 100644 index 0000000..9931fcc --- /dev/null +++ b/making_school_asignment_app/lib/page/global_widget/desktop_page_template.dart @@ -0,0 +1,125 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +class DesktopPageTemplate extends StatelessWidget { + final String title; + final Widget? child; + final List? actions; + final String? subtitle; + + const DesktopPageTemplate({ + super.key, + required this.title, + this.child, + this.actions, + this.subtitle, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color(0xFFF0F2F5), + body: Column( + children: [ + _buildHeader(context), + Expanded( + child: child ?? _buildPlaceholder(), + ), + ], + ), + ); + } + + Widget _buildHeader(BuildContext context) { + return Container( + padding: EdgeInsets.all(24.r), + color: Colors.white, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + title, + style: TextStyle( + fontSize: 24.sp, + fontWeight: FontWeight.bold, + color: const Color(0xFF333333), + ), + ), + if (subtitle != null) ...[ + SizedBox(height: 4.h), + Text( + subtitle!, + style: TextStyle( + fontSize: 14.sp, + color: Colors.grey[600], + ), + ), + ], + ], + ), + if (actions != null) + Row(children: actions!) + else + IconButton( + onPressed: () => Navigator.of(context).pop(), + icon: Icon(Icons.close, size: 24.sp, color: Colors.grey[600]), + tooltip: '关闭', + ), + ], + ), + ); + } + + Widget _buildPlaceholder() { + return Center( + child: Card( + elevation: 2, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)), + child: Container( + padding: EdgeInsets.all(48.r), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.desktop_windows_outlined, + size: 64.r, + color: Colors.grey[400], + ), + SizedBox(height: 16.h), + Text( + '桌面版 $title', + style: TextStyle( + fontSize: 20.sp, + fontWeight: FontWeight.bold, + color: const Color(0xFF333333), + ), + ), + SizedBox(height: 8.h), + Text( + '此页面已针对 Windows 桌面环境进行优化', + style: TextStyle( + fontSize: 14.sp, + color: Colors.grey[600], + ), + textAlign: TextAlign.center, + ), + SizedBox(height: 24.h), + ElevatedButton( + onPressed: () {}, + style: ElevatedButton.styleFrom( + padding: EdgeInsets.symmetric(horizontal: 32.w, vertical: 12.h), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.r)), + ), + child: const Text('返回'), + ), + ], + ), + ), + ), + ); + } +} diff --git a/making_school_asignment_app/lib/page/global_widget/desktop_scaffold.dart b/making_school_asignment_app/lib/page/global_widget/desktop_scaffold.dart new file mode 100644 index 0000000..9ad23a0 --- /dev/null +++ b/making_school_asignment_app/lib/page/global_widget/desktop_scaffold.dart @@ -0,0 +1,100 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:making_school_asignment_app/page/home_page/children/my_info.dart'; + +import '../home_page/home_view.dart'; + +class DesktopScaffold extends StatefulWidget { + const DesktopScaffold({super.key}); + + @override + State createState() => _DesktopScaffoldState(); +} + +class _DesktopScaffoldState extends State { + int _selectedIndex = 0; + final List _pages = [const HomePage(), const MyInfo()]; + bool _isExpanded = false; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color(0xFFF0F2F5), + body: Row( + children: [ + Container( + decoration: BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 10, + offset: const Offset(2, 0), + ), + ], + ), + child: NavigationRail( + selectedIndex: _selectedIndex, + onDestinationSelected: (int index) { + setState(() { + _selectedIndex = index; + }); + }, + extended: _isExpanded, + minWidth: 72.w, + minExtendedWidth: 200.w, + labelType: _isExpanded ? NavigationRailLabelType.none : NavigationRailLabelType.selected, + backgroundColor: Colors.white, + selectedIconTheme: IconThemeData( + color: Theme.of(context).primaryColor, + size: 28.r, + ), + unselectedIconTheme: IconThemeData( + color: Colors.grey[600], + size: 24.r, + ), + selectedLabelTextStyle: TextStyle( + color: Theme.of(context).primaryColor, + fontWeight: FontWeight.w600, + fontSize: 12.sp, + ), + unselectedLabelTextStyle: TextStyle( + color: Colors.grey[600], + fontSize: 12.sp, + ), + leading: Padding( + padding: EdgeInsets.symmetric(vertical: 16.h), + child: FloatingActionButton.small( + onPressed: () { + setState(() { + _isExpanded = !_isExpanded; + }); + }, + backgroundColor: Colors.grey[100], + foregroundColor: Colors.grey[700], + elevation: 0, + child: Icon(_isExpanded ? Icons.chevron_left : Icons.menu, size: 20.r), + ), + ), + destinations: const [ + NavigationRailDestination( + icon: Icon(Icons.assignment_outlined), + selectedIcon: Icon(Icons.assignment), + label: Text('作业管理'), + ), + NavigationRailDestination( + icon: Icon(Icons.person_outline), + selectedIcon: Icon(Icons.person), + label: Text('个人信息'), + ), + ], + ), + ), + Expanded( + child: _pages[_selectedIndex], + ), + ], + ), + ); + } +} diff --git a/making_school_asignment_app/lib/page/global_widget/other_desktop_page.dart b/making_school_asignment_app/lib/page/global_widget/other_desktop_page.dart new file mode 100644 index 0000000..aa1d6d7 --- /dev/null +++ b/making_school_asignment_app/lib/page/global_widget/other_desktop_page.dart @@ -0,0 +1,159 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/const_text.dart'; +import 'package:making_school_asignment_app/common/job/user_info_detail.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/store/user_store.dart'; +import 'package:making_school_asignment_app/common/utils/storage.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; +import 'package:package_info_plus/package_info_plus.dart'; + +class OtherDesktopPage extends StatefulWidget { + const OtherDesktopPage({super.key}); + + @override + State createState() => _OtherDesktopPageState(); +} + +class _OtherDesktopPageState extends State with RequestToolMixin { + late Rx userInfo = UserStore.to.userDetailInfo; + RxString localVersion = ''.obs; + + @override + void initState() { + super.initState(); + getPageInfo(); + } + + getPageInfo() async { + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + localVersion.value = packageInfo.version; + } + + _showLogoutDialog(BuildContext context) async { + return showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('账户注销'), + content: const Text('账户注销无法恢复,您确定要注销账户吗?'), + actions: [ + TextButton( + child: const Text('取消'), + onPressed: () => Navigator.of(context).pop(false), + ), + TextButton( + child: const Text('确定'), + onPressed: () async { + await getClient().toUserLogout(userInfo.value!.id); + try { + UserStore.to.erase(); + await StorageService.to.erase(); + Navigator.of(context).pop(true); + Get.offAllNamed(Routes.login); + } catch (e) { + print(e); + } + }, + ), + ], + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color(0xFFF0F2F5), + body: SingleChildScrollView( + padding: EdgeInsets.all(24.r), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildHeader(), + SizedBox(height: 24.h), + _buildSettingsCards(), + SizedBox(height: 24.h), + _buildVersionInfo(), + SizedBox(height: 24.h), + _buildLogoutSection(), + ], + ), + ), + ); + } + + Widget _buildHeader() { + return Text( + '其他设置', + style: TextStyle(fontSize: 24.sp, fontWeight: FontWeight.bold, color: const Color(0xFF333333)), + ); + } + + Widget _buildSettingsCards() { + return Card( + elevation: 2, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)), + child: Column( + children: [ + ListTile( + leading: Icon(Icons.privacy_tip_outlined, color: Colors.grey[600]), + title: const Text('用户隐私协议'), + trailing: const Icon(Icons.arrow_forward_ios, size: 16), + onTap: () { + Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.PRIVACY_GREEMENT.name}); + }, + ), + const Divider(height: 1), + ListTile( + leading: Icon(Icons.description_outlined, color: Colors.grey[600]), + title: const Text('用户协议'), + trailing: const Icon(Icons.arrow_forward_ios, size: 16), + onTap: () { + Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.USER_AGREEMENT.name}); + }, + ), + ], + ), + ); + } + + Widget _buildVersionInfo() { + return Card( + elevation: 2, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)), + child: ListTile( + leading: Icon(Icons.info_outline, color: Colors.grey[600]), + title: const Text('APP版本'), + trailing: Obx(() => Text(localVersion.value, style: TextStyle(color: Colors.grey[600]))), + ), + ); + } + + Widget _buildLogoutSection() { + return Card( + elevation: 2, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)), + child: Column( + children: [ + ListTile( + leading: Icon(Icons.logout, color: Colors.red[600]), + title: Text('账户注销', style: TextStyle(color: Colors.red[600])), + trailing: Icon(Icons.arrow_forward_ios, size: 16, color: Colors.red[600]), + onTap: () => _showLogoutDialog(context), + ), + Padding( + padding: EdgeInsets.all(16.r), + child: Text( + 'APP备案号: 渝ICP备17007225号-4A', + style: TextStyle(fontSize: 12.sp, color: Colors.grey[500]), + ), + ), + ], + ), + ); + } +} diff --git a/making_school_asignment_app/lib/page/global_widget/other_mobile_page.dart b/making_school_asignment_app/lib/page/global_widget/other_mobile_page.dart new file mode 100644 index 0000000..8c1fc7d --- /dev/null +++ b/making_school_asignment_app/lib/page/global_widget/other_mobile_page.dart @@ -0,0 +1,189 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/const_text.dart'; +import 'package:making_school_asignment_app/common/job/user_info_detail.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/store/user_store.dart'; +import 'package:making_school_asignment_app/common/utils/storage.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; +import 'package:package_info_plus/package_info_plus.dart'; + +class OtherMobilePage extends StatefulWidget { + const OtherMobilePage({super.key}); + + @override + State createState() => _OtherMobilePageState(); +} + +class _OtherMobilePageState extends State with RequestToolMixin { + late Rx userInfo = UserStore.to.userDetailInfo; + RxString localVersion = ''.obs; + + @override + void initState() { + super.initState(); + getPageInfo(); + } + + // 获取当前版本号 + getPageInfo() async { + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + localVersion.value = packageInfo.version; + } + + // 确认对话框 + _showAlertDialog(context1) async { + await showDialog( + barrierDismissible: false, + context: context1, + builder: (context) { + return AlertDialog(title: quickText("提示信息"), content: quickText("账户注销无法恢复,您确定要注销账户吗?"), actions: [ + TextButton( + child: quickText("取消"), + onPressed: () { + Navigator.pop(context, 'Cancle'); + }, + ), + TextButton( + child: quickText("确定"), + onPressed: () async { + await getClient().toUserLogout(userInfo.value!.id); + try { + UserStore.to.erase(); + var msg = await StorageService.to.erase(); + print(msg); + Navigator.pop(context, "Ok"); + Get.offAllNamed(Routes.login); + } catch (e) { + print(e); + } + }) + ]); + }); + } + + @override + Widget build(BuildContext context) { + final personalInfoTitleStly = TextStyle( + color: const Color.fromRGBO(80, 87, 103, 1), + fontSize: 16.sp, + ); + + return Scaffold( + backgroundColor: const Color.fromRGBO(248, 248, 248, 1), + appBar: AppBar( + backgroundColor: Theme.of(context).primaryColor, + title: quickText('其他', color: Colors.white), + ), + body: Stack( + alignment: const FractionalOffset(0.5, 0.98), + children: [ + ListView( + children: [ + Container( + margin: EdgeInsets.symmetric(vertical: 22.h, horizontal: 16.w), + padding: EdgeInsets.symmetric(vertical: 22.h, horizontal: 16.w), + height: 130.h, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(6.w)), + color: Colors.white, + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(46, 91, 255, 0.1), + offset: Offset.zero, + blurRadius: 20, + spreadRadius: 10, + ) + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + InkWell( + onTap: () { + Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.PRIVACY_GREEMENT.name}); + }, + child: Container( + padding: EdgeInsets.only(bottom: 4.h), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('用户隐私协议', style: personalInfoTitleStly), + Icon( + Icons.arrow_forward_ios, + color: const Color.fromRGBO(80, 87, 103, 1), + size: 16.sp, + ) + ], + ), + ), + ), + Container( + height: 1.w, + color: const Color.fromRGBO(240, 243, 255, 1), + ), + SizedBox(height: 8.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('APP版本', style: personalInfoTitleStly), + Obx(() { + return quickText(localVersion); + }) + ], + ) + ], + ), + ), + ], + ), + Positioned( + bottom: 50.h, + child: InkWell( + child: Container( + height: 46.h, + width: ScreenUtil().screenWidth - 60.w, + padding: EdgeInsets.symmetric(vertical: 14.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(6.w)), + color: Colors.white, + boxShadow: [ + BoxShadow( + color: const Color.fromRGBO(46, 91, 255, 0.2), + offset: Offset(2.w, 2.h), + blurRadius: 14, + spreadRadius: 0.5, + ) + ], + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.exit_to_app_outlined, + size: 13.sp, + color: const Color.fromRGBO(148, 163, 182, 1), + ), + Container(width: 6.w), + Text( + '账户注销', + style: TextStyle(color: const Color.fromRGBO(148, 163, 182, 1), fontSize: 13.sp), + ), + ], + ), + ), + onTap: () => _showAlertDialog(context), + ), + ), + Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [Text('APP备案号: ', style: personalInfoTitleStly), quickText('渝ICP备17007225号-4A', size: 14.sp)], + ), + ], + )); + } +} diff --git a/making_school_asignment_app/lib/page/global_widget/other_page.dart b/making_school_asignment_app/lib/page/global_widget/other_page.dart index dcde7de..a55879e 100644 --- a/making_school_asignment_app/lib/page/global_widget/other_page.dart +++ b/making_school_asignment_app/lib/page/global_widget/other_page.dart @@ -1,199 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:making_school_asignment_app/common/const_text.dart'; -import 'package:making_school_asignment_app/common/job/user_info_detail.dart'; -import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; -import 'package:making_school_asignment_app/common/store/user_store.dart'; -import 'package:making_school_asignment_app/common/utils/storage.dart'; -import 'package:making_school_asignment_app/routes/app_pages.dart'; -import 'package:package_info_plus/package_info_plus.dart'; -import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; -// 其他页面 +import 'package:making_school_asignment_app/common/utils/platform_utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/other_desktop_page.dart'; +import 'package:making_school_asignment_app/page/global_widget/other_mobile_page.dart'; -class OhterPage extends StatefulWidget { +class OhterPage extends StatelessWidget { const OhterPage({super.key}); - @override - State createState() => _OhterPageState(); -} - -class _OhterPageState extends State with RequestToolMixin { - late Rx userInfo = UserStore.to.userDetailInfo; - RxString localVersion = ''.obs; - - @override - void initState() { - super.initState(); - getPageInfo(); - } - - // 获取当前版本号 - getPageInfo() async { - PackageInfo packageInfo = await PackageInfo.fromPlatform(); - localVersion.value = packageInfo.version; - } - - // 确认对话框 - _showAlertDialog(context1) async { - await showDialog( - // 表示点击灰色背景的时候是否消失弹出框 - barrierDismissible: false, - context: context1, - builder: (context) { - return AlertDialog(title: quickText("提示信息"), content: quickText("账户注销无法恢复,您确定要注销账户吗?"), actions: [ - TextButton( - child: quickText("取消"), - onPressed: () { - Navigator.pop(context, 'Cancle'); - }, - ), - TextButton( - child: quickText("确定"), - onPressed: () async { - /* ref.read(markingKeyboardProvider.notifier).clean(); - ref.read(markingSubtopicSwitchingProvider.notifier).clean(); - ref.read(userTokenProvider.notifier).clean(); - ref.read(userProvider.notifier).clean();*/ - await getClient().toUserLogout(userInfo.value!.id); - try { - UserStore.to.erase(); - var msg = await StorageService.to.erase(); - print(msg); - Navigator.pop(context, "Ok"); - Get.offAllNamed(Routes.login); - } catch (e) { - print(e); - } - }) - ]); - }); - } - @override Widget build(BuildContext context) { - final personalInfoTitleStly = TextStyle( - color: const Color.fromRGBO(80, 87, 103, 1), - fontSize: 16.sp, - ); - - return Scaffold( - backgroundColor: const Color.fromRGBO(248, 248, 248, 1), - appBar: AppBar( - backgroundColor: Theme.of(context).primaryColor, - title: quickText('其他', color: Colors.white), - ), - body: Stack( - alignment: const FractionalOffset(0.5, 0.98), - children: [ - ListView( - children: [ - Container( - margin: EdgeInsets.symmetric(vertical: 22.h, horizontal: 16.w), - padding: EdgeInsets.symmetric(vertical: 22.h, horizontal: 16.w), - height: 130.h, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(6.w)), - color: Colors.white, - boxShadow: const [ - BoxShadow( - color: Color.fromRGBO(46, 91, 255, 0.1), - offset: Offset.zero, //阴影y轴偏移量 - blurRadius: 20, //阴影模糊程度 - spreadRadius: 10, //阴影扩散程度 - ) - ], - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - InkWell( - onTap: () { - Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.PRIVACY_GREEMENT.name}); - }, - child: Container( - padding: EdgeInsets.only(bottom: 4.h), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('用户隐私协议', style: personalInfoTitleStly), - Icon( - Icons.arrow_forward_ios, - color: const Color.fromRGBO(80, 87, 103, 1), - size: 16.sp, - ) - ], - ), - ), - ), - Container( - height: 1.w, - color: const Color.fromRGBO(240, 243, 255, 1), - ), - SizedBox(height: 8.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('APP版本', style: personalInfoTitleStly), - Obx(() { - return quickText(localVersion); - }) - ], - ) - ], - ), - ), - ], - ), - Positioned( - bottom: 50.h, - child: InkWell( - child: Container( - height: 46.h, - width: ScreenUtil().screenWidth - 60.w, - padding: EdgeInsets.symmetric(vertical: 14.h), - decoration: BoxDecoration( - borderRadius: BorderRadius.all( - Radius.circular(6.w), - ), - color: Colors.white, - boxShadow: [ - BoxShadow( - color: const Color.fromRGBO(46, 91, 255, 0.2), - offset: Offset(2.w, 2.h), //阴影y轴偏移量 - blurRadius: 14, //阴影模糊程度 - spreadRadius: 0.5, //阴影扩散程度 - ) - ], - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.exit_to_app_outlined, - size: 13.sp, - color: const Color.fromRGBO(148, 163, 182, 1), - ), - Container( - width: 6.w, - ), - Text( - '账户注销', - style: TextStyle(color: const Color.fromRGBO(148, 163, 182, 1), fontSize: 13.sp), - ), - ], - ), - ), - onTap: () => _showAlertDialog(context), - ), - ), - Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [Text('APP备案号: ', style: personalInfoTitleStly), quickText('渝ICP备17007225号-4A', size: 14.sp)], - ), - ], - )); + return PlatformUtils.isDesktop ? const OtherDesktopPage() : const OtherMobilePage(); } } diff --git a/making_school_asignment_app/lib/page/global_widget/start_page.dart b/making_school_asignment_app/lib/page/global_widget/start_page.dart index ff771ae..2ea762f 100644 --- a/making_school_asignment_app/lib/page/global_widget/start_page.dart +++ b/making_school_asignment_app/lib/page/global_widget/start_page.dart @@ -10,8 +10,10 @@ import 'package:making_school_asignment_app/common/job/user_info_detail.dart'; import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; import 'package:making_school_asignment_app/common/store/user_store.dart'; import 'package:making_school_asignment_app/common/utils/app_upgrade/upgradeLogic.dart'; +import 'package:making_school_asignment_app/common/utils/platform_utils.dart'; import 'package:making_school_asignment_app/common/utils/storage.dart'; import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/desktop_scaffold.dart'; import 'package:making_school_asignment_app/page/home_page/children/my_info.dart'; import 'package:making_school_asignment_app/page/home_page/home_view.dart'; import 'package:making_school_asignment_app/routes/app_pages.dart'; @@ -89,73 +91,75 @@ class _StartPageState extends State with RequestToolMixin { @override Widget build(BuildContext context) { - return PopScope( - canPop: false, - child: Scaffold( - body: PageView( - controller: _pageController._pageIndexState.pageController, - physics: const BouncingScrollPhysics(), - onPageChanged: (index) { - _pageController._pageIndexState.pageIndex.value = index; - // if (index == 2) { - // SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(statusBarIconBrightness: Brightness.light)); - // } else { - // SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(statusBarIconBrightness: Brightness.dark)); - // } - }, - children: _bodyList, - ), - bottomNavigationBar: Obx(() { - return BottomNavigationBar( - backgroundColor: Colors.white, - items: [ - BottomNavigationBarItem( - label: '作业', - icon: getItemIcon('assets/images/ic_home_normal.png'), - activeIcon: getItemIcon('assets/images/ic_home_active.png'), + return PlatformUtils.isDesktop + ? const DesktopScaffold() + : PopScope( + canPop: false, + child: Scaffold( + body: PageView( + controller: _pageController._pageIndexState.pageController, + physics: const BouncingScrollPhysics(), + onPageChanged: (index) { + _pageController._pageIndexState.pageIndex.value = index; + // if (index == 2) { + // SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(statusBarIconBrightness: Brightness.light)); + // } else { + // SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(statusBarIconBrightness: Brightness.dark)); + // } + }, + children: _bodyList, ), - // BottomNavigationBarItem( - // label: '考试', - // icon: getItemIcon('assets/images/ic_work_normal.png'), - // activeIcon: getItemIcon('assets/images/ic_work_active.png'), - // ), - BottomNavigationBarItem( - label: '我的', - icon: getItemIcon('assets/images/ic_mine_normal.png'), - activeIcon: getItemIcon('assets/images/ic_mine_active.png'), - ), - ], - //设置显示的模式 - type: BottomNavigationBarType.fixed, - fixedColor: Theme.of(context).primaryColor, - unselectedItemColor: Colors.grey, - // unselectedItemColor: const Color.fromRGBO(80, 87, 103, 1), - // backgroundColor: Colors.white, - //设置当前的索引 - currentIndex: _pageController._pageIndexState.pageIndex.value, - //tabBottom的点击监听 - onTap: (index) { - _pageController._pageIndexState.pageController.jumpToPage(index); + bottomNavigationBar: Obx(() { + return BottomNavigationBar( + backgroundColor: Colors.white, + items: [ + BottomNavigationBarItem( + label: '作业', + icon: getItemIcon('assets/images/ic_home_normal.png'), + activeIcon: getItemIcon('assets/images/ic_home_active.png'), + ), + // BottomNavigationBarItem( + // label: '考试', + // icon: getItemIcon('assets/images/ic_work_normal.png'), + // activeIcon: getItemIcon('assets/images/ic_work_active.png'), + // ), + BottomNavigationBarItem( + label: '我的', + icon: getItemIcon('assets/images/ic_mine_normal.png'), + activeIcon: getItemIcon('assets/images/ic_mine_active.png'), + ), + ], + //设置显示的模式 + type: BottomNavigationBarType.fixed, + fixedColor: Theme.of(context).primaryColor, + unselectedItemColor: Colors.grey, + // unselectedItemColor: const Color.fromRGBO(80, 87, 103, 1), + // backgroundColor: Colors.white, + //设置当前的索引 + currentIndex: _pageController._pageIndexState.pageIndex.value, + //tabBottom的点击监听 + onTap: (index) { + _pageController._pageIndexState.pageController.jumpToPage(index); + }, + ); + }), + ), + onPopInvokedWithResult: (bool didPop, dynamic result) async { + if (lastPopTime == null || DateTime.now().difference(lastPopTime!) > const Duration(seconds: 1)) { + lastPopTime = DateTime.now(); + ToastUtils.getFluttertoast( + context: context, + msg: '连续两次返回就退出', + gravity: ToastGravity.CENTER, + fontSize: 18, + ); + } else { + lastPopTime = DateTime.now(); + // 退出app + SystemNavigator.pop(); + } }, ); - }), - ), - onPopInvokedWithResult: (bool didPop, dynamic result) async { - if (lastPopTime == null || DateTime.now().difference(lastPopTime!) > const Duration(seconds: 1)) { - lastPopTime = DateTime.now(); - ToastUtils.getFluttertoast( - context: context, - msg: '连续两次返回就退出', - gravity: ToastGravity.CENTER, - fontSize: 18, - ); - } else { - lastPopTime = DateTime.now(); - // 退出app - SystemNavigator.pop(); - } - }, - ); } } diff --git a/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_desktop_view.dart b/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_desktop_view.dart new file mode 100644 index 0000000..fd8227c --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_desktop_view.dart @@ -0,0 +1,183 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/student_item.dart'; +import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'class_student_logic.dart'; + +class ClassStudentDesktopPage extends StatefulWidget { + const ClassStudentDesktopPage({super.key}); + + @override + State createState() => _ClassStudentDesktopPageState(); +} + +class _ClassStudentDesktopPageState extends State { + final logic = Get.find(); + final state = Get.find().state; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color(0xFFF0F2F5), + body: Column( + children: [ + _buildHeader(), + Expanded( + child: Container( + padding: EdgeInsets.all(24.r), + child: Card( + elevation: 2, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)), + child: Obx(() { + return EasyRefresh( + controller: logic.refreshController, + header: MaterialHeader(), + onRefresh: () async { + logic.getList(); + }, + child: state.studentList.isNotEmpty ? _buildStudentGrid() : const MyEmptyWidget(), + ); + }), + ), + ), + ), + ], + ), + ); + } + + Widget _buildHeader() { + return Container( + padding: EdgeInsets.all(24.r), + color: Colors.white, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Obx(() => Text( + state.title.value, + style: TextStyle(fontSize: 24.sp, fontWeight: FontWeight.bold, color: const Color(0xFF333333)), + )), + IconButton( + onPressed: () => Get.back(), + icon: Icon(Icons.close, size: 24.sp, color: Colors.grey[600]), + tooltip: '关闭', + ), + ], + ), + ); + } + + Widget _buildStudentGrid() { + return GridView.builder( + padding: EdgeInsets.all(16.r), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + crossAxisSpacing: 16.r, + mainAxisSpacing: 16.r, + childAspectRatio: 2.5, + ), + itemCount: state.studentList.length, + itemBuilder: (context, index) { + StudentItem item = state.studentList[index]; + return _buildStudentCard(item); + }, + ); + } + + Widget _buildStudentCard(StudentItem item) { + return Card( + elevation: 2, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.r)), + child: InkWell( + onTap: () { + Get.toNamed(Routes.studentWorkDetailPage, arguments: { + 'studentName': item.name, + 'studentId': item.id, + 'subject': state.subject, + }); + }, + borderRadius: BorderRadius.circular(8.r), + child: Container( + padding: EdgeInsets.all(16.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + item.name, + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF333333), fontWeight: FontWeight.w500), + ), + ), + _buildActionButton(item), + ], + ), + ), + ), + ); + } + + Widget _buildActionButton(StudentItem item) { + if (state.page == 'answerTrajectory') { + return Container( + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h), + decoration: BoxDecoration( + border: Border.all(color: const Color(0xFFB2DA93)), + borderRadius: BorderRadius.circular(16.r), + ), + child: Text('详情', style: TextStyle(fontSize: 12.sp, color: const Color(0xFFB2DA93))), + ); + } else if (state.page == 'history') { + return Container( + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h), + decoration: BoxDecoration( + color: Theme.of(context).primaryColor, + borderRadius: BorderRadius.circular(16.r), + ), + child: Text('历史作业', style: TextStyle(fontSize: 12.sp, color: Colors.white)), + ); + } else { + return InkWell( + onTap: () { + logic.setJobReadLevel(item.id, !item.priorityAnnotate); + EasyLoading.show(status: 'loading...'); + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h), + decoration: BoxDecoration( + color: item.priorityAnnotate ? const Color(0xFFEBE4FF) : const Color(0xFFE1E1E1), + borderRadius: BorderRadius.circular(16.r), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + item.priorityAnnotate ? Icons.star : Icons.star_border, + size: 14.r, + color: item.priorityAnnotate ? Theme.of(context).primaryColor : Colors.grey, + ), + SizedBox(width: 4.w), + Text( + '优先批阅', + style: TextStyle( + fontSize: 12.sp, + color: item.priorityAnnotate ? Theme.of(context).primaryColor : Colors.grey, + ), + ), + ], + ), + ), + ); + } + } + + @override + void dispose() { + Get.delete(); + super.dispose(); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_mobile_view.dart b/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_mobile_view.dart new file mode 100644 index 0000000..b03295c --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_mobile_view.dart @@ -0,0 +1,341 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/student_item.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.dart'; +import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'class_student_logic.dart'; + +class ClassStudentMobilePage extends StatefulWidget { + const ClassStudentMobilePage({super.key}); + + @override + State createState() => _ClassStudentMobilePageState(); +} + +class _ClassStudentMobilePageState extends State { + final logic = Get.find(); + final state = Get.find().state; + + @override + Widget build(BuildContext context) { + return OrientationBuilder(builder: (BuildContext context, Orientation orientation) { + return Scaffold( + backgroundColor: const Color.fromRGBO(245, 245, 245, 1), + appBar: AppBar( + backgroundColor: Colors.white, + title: Obx(() { + return Text( + state.title.value, + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF333333)), + ); + }), + centerTitle: true, + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios, color: Colors.black), + onPressed: () => Get.back(), + ), + actions: const [ + ReturnToHomepage(), + ], + elevation: 0, + ), + body: Obx(() { + return EasyRefresh( + firstRefresh: false, + taskIndependence: true, + controller: logic.refreshController, + header: MaterialHeader(), + footer: TaurusFooter(), + onRefresh: () async { + logic.getList(); + }, + child: state.studentList.isNotEmpty + ? Utils.isPad() + ? GridView( + shrinkWrap: true, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + mainAxisSpacing: 0.r, + crossAxisSpacing: 0.r, + childAspectRatio: 556 / 90, + ), + children: List.generate(state.studentList.length, (index) { + StudentItem item = state.studentList[index]; + return InkWell( + onTap: () { + Get.toNamed(Routes.studentWorkDetailPage, arguments: { + 'studentName': item.name, + 'studentId': item.id, + 'subject': state.subject, + }); + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(0.r)), + color: Colors.transparent, + border: Border( + left: BorderSide( + width: (index + 1) % 2 == 0 ? 1.r : 0, color: const Color(0xFFA5A5A5)), + bottom: BorderSide(width: 1.r, color: const Color(0xFFA5A5A5)))), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + item.name, + style: TextStyle(fontSize: 12.sp, color: Theme.of(context).primaryColor), + )), + state.page == 'answerTrajectory' + ? Container( + height: 20.r, + width: 70.r, + decoration: BoxDecoration( + border: Border.all(width: 1.r, color: const Color(0xFFB2DA93)), + borderRadius: BorderRadius.all(Radius.circular(20.r)), + ), + child: Center( + child: Text('详情', + style: TextStyle(fontSize: 10.r, color: const Color(0xFFB2DA93))), + )) + : state.page == 'history' + ? Container( + height: 20.r, + width: 70.r, + decoration: BoxDecoration( + color: Theme.of(context).primaryColor, + borderRadius: BorderRadius.all(Radius.circular(20.r))), + child: Center( + child: Text( + '历史作业', + style: TextStyle(fontSize: 10.r, color: Colors.white), + )), + ) + : item.priorityAnnotate + ? InkWell( + onTap: () { + logic.setJobReadLevel(item.id, false); + EasyLoading.show(status: 'loading...'); + }, + child: Container( + height: 20.r, + width: 80.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(4.r)), + color: const Color(0xFFEBE4FF), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(left: 3.r), + child: Image.asset( + 'assets/images/youx_icon_active.png', + width: 14.r, + height: 14.r, + ), + ), + Padding( + padding: EdgeInsets.only(top: 2.r, left: 4.r), + child: Text( + '优先批阅', + style: TextStyle( + fontSize: 10.sp, color: Theme.of(context).primaryColor), + ), + ), + ], + ), + ), + ) + : InkWell( + onTap: () { + logic.setJobReadLevel(item.id, true); + EasyLoading.show(status: 'loading...'); + }, + child: Container( + height: 20.r, + width: 80.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(4.r)), + color: const Color(0xFFE1E1E1), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(left: 3.r), + child: Image.asset( + 'assets/images/youx_icon_default.png', + width: 14.r, + height: 14.r, + ), + ), + Padding( + padding: EdgeInsets.only(top: 2.r, left: 4.r), + child: Text( + '优先批阅', + style: TextStyle( + fontSize: 10.sp, color: const Color(0xFF8A9691)), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ); + }), + ) + : Padding( + padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 14.r), + child: ListView.builder( + itemBuilder: (context, index) { + StudentItem item = state.studentList[index]; + return InkWell( + onTap: () { + Get.toNamed(Routes.studentWorkDetailPage, arguments: { + 'studentName': item.name, + 'studentId': item.id, + 'subject': state.subject, + }); + }, + child: Container( + padding: EdgeInsets.symmetric(vertical: 20.r, horizontal: 15.r), + margin: EdgeInsets.only(bottom: 15.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(10.r)), + color: Colors.white, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + item.name, + style: TextStyle(fontSize: 12.sp, color: const Color(0xFF4CC793)), + )), + state.page == 'answerTrajectory' + ? Container( + height: 24.r, + width: 72.r, + decoration: BoxDecoration( + border: Border.all(width: 1.r, color: const Color(0xFFB2DA93)), + borderRadius: BorderRadius.all(Radius.circular(20.r)), + ), + child: Center( + child: Text('详情', + style: TextStyle(fontSize: 10.r, color: const Color(0xFFB2DA93))), + )) + : state.page == 'history' + ? Container( + height: 24.r, + width: 82.r, + decoration: BoxDecoration( + color: const Color(0xFF4CC793), + borderRadius: BorderRadius.all(Radius.circular(20.r))), + child: Center( + child: Text( + '历史作业', + style: TextStyle(fontSize: 10.r, color: Colors.white), + )), + ) + : item.priorityAnnotate + ? InkWell( + onTap: () { + logic.setJobReadLevel(item.id, false); + EasyLoading.show(status: 'loading...'); + }, + child: Container( + height: 24.r, + width: 82.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(4.r)), + color: const Color(0xFFB7FFE0), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(left: 3.r), + child: Image.asset( + 'assets/images/youx_icon_active.png', + width: 14.r, + height: 14.r, + ), + ), + Padding( + padding: EdgeInsets.only(top: 5.r, left: 4.r), + child: Text( + '优先批阅', + style: TextStyle( + fontSize: 10.sp, color: const Color(0xFF4CC793)), + ), + ), + ], + ), + ), + ) + : InkWell( + onTap: () { + logic.setJobReadLevel(item.id, true); + EasyLoading.show(status: 'loading...'); + }, + child: Container( + height: 24.r, + width: 82.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(4.r)), + color: const Color(0xFFE1E1E1), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(left: 3.r), + child: Image.asset( + 'assets/images/youx_icon_default.png', + width: 14.r, + height: 14.r, + ), + ), + Padding( + padding: EdgeInsets.only(top: 5.r, left: 4.r), + child: Text( + '优先批阅', + style: TextStyle( + fontSize: 10.sp, color: const Color(0xFF8A9691)), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ); + }, + itemCount: state.studentList.length, + ), + ) + : const MyEmptyWidget(), + ); + }), + ); + }); + } + + @override + void dispose() { + Get.delete(); + super.dispose(); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_view.dart b/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_view.dart index 88af4f0..e8b0574 100644 --- a/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_view.dart +++ b/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_view.dart @@ -1,437 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:flutter_easyloading/flutter_easyloading.dart'; -import 'package:flutter_easyrefresh/easy_refresh.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:making_school_asignment_app/common/job/student_item.dart'; -import 'package:making_school_asignment_app/common/utils/utils.dart'; -import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.dart'; -import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart'; -import 'package:making_school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/common/utils/platform_utils.dart'; +import 'package:making_school_asignment_app/page/home_page/children/class_student/class_student_desktop_view.dart'; +import 'package:making_school_asignment_app/page/home_page/children/class_student/class_student_mobile_view.dart'; -import 'class_student_logic.dart'; - -class ClassStudentPage extends StatefulWidget { - const ClassStudentPage({Key? key}) : super(key: key); - - @override - State createState() => _ClassStudentPageState(); -} - -class _ClassStudentPageState extends State { - final logic = Get.find(); - final state = Get.find().state; +class ClassStudentPage extends StatelessWidget { + const ClassStudentPage({super.key}); @override Widget build(BuildContext context) { - return OrientationBuilder( - builder: (BuildContext context, Orientation orientation){ - return Scaffold( - backgroundColor: const Color.fromRGBO(245, 245, 245, 1), - appBar: AppBar( - backgroundColor: Colors.white, - title: Obx(() { - return Text( - state.title.value, - style: TextStyle(fontSize: 14.sp, color: const Color(0xFF333333)), - ); - }), - centerTitle: true, - leading: IconButton( - icon: const Icon(Icons.arrow_back_ios, color: Colors.black), - onPressed: () => Get.back(), - ), - actions: const [ - ReturnToHomepage(), - ], - elevation: 0, - ), - body: Obx(() { - return EasyRefresh( - firstRefresh: false, - taskIndependence: true, - controller: logic.refreshController, - header: MaterialHeader(), - footer: TaurusFooter(), - onRefresh: () async { - logic.getList(); - }, - child: state.studentList.isNotEmpty - ? Utils.isPad() - ? GridView( - shrinkWrap: true, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - mainAxisSpacing: 0.r, - crossAxisSpacing: 0.r, - childAspectRatio: 556 / 90, - ), - children: - List.generate(state.studentList.length, (index) { - StudentItem item = state.studentList[index]; - return InkWell( - onTap: () { - // RouterManager.router.navigateTo(context, - // '${RouterManager.jobPersonalDetailPath}?studentId=${item.studentId}&studentName=${Uri.encodeComponent(item.studentName)}'); - Get.toNamed(Routes.studentWorkDetailPage, - arguments: { - 'studentName': item.name, - 'studentId': item.id, - 'subject':state.subject, - }); - }, - child: Container( - padding: EdgeInsets.symmetric(horizontal: 10.r), - decoration: BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(0.r)), - color: Colors.transparent, - border: Border(left: BorderSide(width: - (index + 1)%2 == 0? 1.r:0,color: const Color(0xFFA5A5A5)),bottom: BorderSide(width: 1.r,color: const Color(0xFFA5A5A5))) - ), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - item.name, - style: TextStyle( - fontSize: 12.sp, - color: Theme.of(context).primaryColor), - )), - state.page == 'answerTrajectory' - ? Container( - height: 20.r, - width: 70.r, - decoration: BoxDecoration( - border: Border.all( - width: 1.r, - color: const Color(0xFFB2DA93)), - borderRadius: BorderRadius.all( - Radius.circular(20.r)), - ), - child: Center( - child: Text('详情', - style: TextStyle( - fontSize: 10.r, - color: Color(0xFFB2DA93))), - )) - : state.page == 'history' - ? Container( - height: 20.r, - width: 70.r, - decoration: BoxDecoration( - color: - Theme.of(context).primaryColor, - borderRadius: - BorderRadius.all( - Radius.circular( - 20.r))), - child: Center( - child: Text( - '历史作业', - style: TextStyle( - fontSize: 10.r, - color: Colors.white), - )), - ) - : item.priorityAnnotate - ? InkWell( - onTap: () { - logic.setJobReadLevel( - item.id, false); - EasyLoading.show( - status: 'loading...'); - }, - child: Container( - height: 20.r, - width: 80.r, - decoration: BoxDecoration( - borderRadius: - BorderRadius.all( - Radius.circular( - 4.r)), - color: const Color( - 0xFFEBE4FF), - ), - child: Row( - crossAxisAlignment: - CrossAxisAlignment - .start, - children: [ - Padding( - padding: - EdgeInsets.only( - left: 3.r), - child: Image.asset( - 'assets/images/youx_icon_active.png', - width: 14.r, - height: 14.r, - ), - ), - Padding( - padding: - EdgeInsets.only( - top: 2.r, - left: 4.r), - child: Text( - '优先批阅', - style: TextStyle( - fontSize: 10.sp, - color: Theme.of(context).primaryColor), - ), - ), - ], - ), - ), - ) - : InkWell( - onTap: () { - logic.setJobReadLevel( - item.id, true); - EasyLoading.show( - status: 'loading...'); - }, - child: Container( - height: 20.r, - width: 80.r, - decoration: BoxDecoration( - borderRadius: - BorderRadius.all( - Radius.circular( - 4.r)), - color: const Color( - 0xFFE1E1E1), - ), - child: Row( - crossAxisAlignment: - CrossAxisAlignment - .start, - children: [ - Padding( - padding: - EdgeInsets.only( - left: 3.r), - child: Image.asset( - 'assets/images/youx_icon_default.png', - width: 14.r, - height: 14.r, - ), - ), - Padding( - padding: - EdgeInsets.only( - top: 2.r, - left: 4.r), - child: Text( - '优先批阅', - style: TextStyle( - fontSize: 10.sp, - color: const Color( - 0xFF8A9691)), - ), - ), - ], - ), - ), - ), - ], - ), - ), - ); - }), - ) - : Padding( - padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 14.r), - child: ListView.builder( - itemBuilder: (context, index) { - StudentItem item = state.studentList[index]; - return InkWell( - onTap: () { - // RouterManager.router.navigateTo(context, - // '${RouterManager.jobPersonalDetailPath}?studentId=${item.studentId}&studentName=${Uri.encodeComponent(item.studentName)}'); - Get.toNamed(Routes.studentWorkDetailPage, - arguments: { - 'studentName': item.name, - 'studentId': item.id, - 'subject':state.subject, - }); - }, - child: Container( - padding: EdgeInsets.symmetric( - vertical: 20.r, horizontal: 15.r), - margin: EdgeInsets.only(bottom: 15.r), - decoration: BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(10.r)), - color: Colors.white, - ), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - item.name, - style: TextStyle( - fontSize: 12.sp, - color: const Color(0xFF4CC793)), - )), - state.page == 'answerTrajectory' - ? Container( - height: 24.r, - width: 72.r, - decoration: BoxDecoration( - border: Border.all( - width: 1.r, - color: const Color(0xFFB2DA93)), - borderRadius: BorderRadius.all( - Radius.circular(20.r)), - ), - child: Center( - child: Text('详情', - style: TextStyle( - fontSize: 10.r, - color: Color(0xFFB2DA93))), - )) - : state.page == 'history' - ? Container( - height: 24.r, - width: 82.r, - decoration: BoxDecoration( - color: Color(0xFF4CC793), - borderRadius: - BorderRadius.all( - Radius.circular( - 20.r))), - child: Center( - child: Text( - '历史作业', - style: TextStyle( - fontSize: 10.r, - color: Colors.white), - )), - ) - : item.priorityAnnotate - ? InkWell( - onTap: () { - logic.setJobReadLevel( - item.id, false); - EasyLoading.show( - status: 'loading...'); - }, - child: Container( - height: 24.r, - width: 82.r, - decoration: BoxDecoration( - borderRadius: - BorderRadius.all( - Radius.circular( - 4.r)), - color: Color(0xFFB7FFE0), - ), - child: Row( - crossAxisAlignment: - CrossAxisAlignment - .start, - children: [ - Padding( - padding: - EdgeInsets.only( - left: 3.r), - child: Image.asset( - 'assets/images/youx_icon_active.png', - width: 14.r, - height: 14.r, - ), - ), - Padding( - padding: - EdgeInsets.only( - top: 5.r, - left: 4.r), - child: Text( - '优先批阅', - style: TextStyle( - fontSize: 10.sp, - color: const Color( - 0xFF4CC793)), - ), - ), - ], - ), - ), - ) - : InkWell( - onTap: () { - logic.setJobReadLevel( - item.id, true); - EasyLoading.show( - status: 'loading...'); - }, - child: Container( - height: 24.r, - width: 82.r, - decoration: BoxDecoration( - borderRadius: - BorderRadius.all( - Radius.circular( - 4.r)), - color: const Color( - 0xFFE1E1E1), - ), - child: Row( - crossAxisAlignment: - CrossAxisAlignment - .start, - children: [ - Padding( - padding: - EdgeInsets.only( - left: 3.r), - child: Image.asset( - 'assets/images/youx_icon_default.png', - width: 14.r, - height: 14.r, - ), - ), - Padding( - padding: - EdgeInsets.only( - top: 5.r, - left: 4.r), - child: Text( - '优先批阅', - style: TextStyle( - fontSize: 10.sp, - color: const Color( - 0xFF8A9691)), - ), - ), - ], - ), - ), - ), - ], - ), - ), - ); - }, - itemCount: state.studentList.length, - ), - ) - : const MyEmptyWidget(), - ); - }), - ); - } - ); - } - - @override - void dispose() { - Get.delete(); - super.dispose(); + return PlatformUtils.isDesktop ? const ClassStudentDesktopPage() : const ClassStudentMobilePage(); } } diff --git a/making_school_asignment_app/lib/page/home_page/children/my_info.dart b/making_school_asignment_app/lib/page/home_page/children/my_info.dart index 9d34145..e274eee 100644 --- a/making_school_asignment_app/lib/page/home_page/children/my_info.dart +++ b/making_school_asignment_app/lib/page/home_page/children/my_info.dart @@ -1,247 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:making_school_asignment_app/common/job/user_info_detail.dart'; -import 'package:making_school_asignment_app/common/store/app_storage_key.dart'; -import 'package:making_school_asignment_app/common/store/user_store.dart'; -import 'package:making_school_asignment_app/common/utils/storage.dart'; -import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; -import 'package:making_school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/common/utils/platform_utils.dart'; +import 'package:making_school_asignment_app/page/home_page/children/my_info_desktop.dart'; +import 'package:making_school_asignment_app/page/home_page/children/my_info_mobile.dart'; -class MyInfo extends StatefulWidget { +class MyInfo extends StatelessWidget { const MyInfo({super.key}); - @override - State createState() => _MyInfoState(); -} - -class _MyInfoState extends State with AutomaticKeepAliveClientMixin { - late Rx userInfo = UserStore.to.userDetailInfo; - - @override - void initState() { - SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( - statusBarIconBrightness: Brightness.light, - statusBarColor: Colors.transparent, //状态栏背景颜色 - // systemStatusBarContrastEnforced: false, - )); - super.initState(); - } - - // 确认对话框 - _showAlertDialog(context1) async { - await showDialog( - // 表示点击灰色背景的时候是否消失弹出框 - barrierDismissible: false, - context: context1, - builder: (context) { - return AlertDialog(title: quickText("提示信息"), content: quickText("您确定要退出登录吗?"), actions: [ - TextButton( - child: quickText("取消"), - onPressed: () { - Navigator.pop(context, 'Cancle'); - }, - ), - TextButton( - child: quickText("确定"), - onPressed: () async { - try { - var pwd = StorageService.to.read(AppStorageKey.pwd.value); - var account = StorageService.to.read(AppStorageKey.account.value); - - UserStore.to.erase(); - await StorageService.to.erase(); - StorageService.to.write(AppStorageKey.privacyAgreement.value, true); - StorageService.to.write(AppStorageKey.account.value, account); - StorageService.to.write(AppStorageKey.pwd.value, pwd); - Navigator.pop(context, "Ok"); - Get.offAllNamed(Routes.login); - } catch (e) { - print(e); - } - }) - ]); - }); - } - - @override - bool get wantKeepAlive => true; - @override Widget build(BuildContext context) { - super.build(context); - - final personalInfoTitleStly = TextStyle( - color: const Color.fromRGBO(80, 87, 103, 1), - fontSize: 13.sp, - ); - final personalInfoValStly = TextStyle( - color: const Color.fromRGBO(148, 163, 182, 1), - fontSize: 13.sp, - ); - - return Stack( - children: [ - SizedBox( - height: double.infinity, - child: Column( - children: [ - Container( - height: 220.h, - width: double.infinity, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/images/personal_bg.png'), - fit: BoxFit.cover, - ), - ), - ), - Expanded( - child: Container( - color: const Color.fromRGBO(248, 248, 248, 1), - )) - ], - ), - ), - SafeArea( - child: Scaffold( - backgroundColor: Colors.transparent, - body: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - height: 150.h, - padding: EdgeInsets.only(left: 20.r, right: 20.r), - // alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Image.asset( - 'assets/images/default_user_dead.png', - ), - SizedBox( - width: 5.w, - ), - InkWell( - onTap: () { - /*if (tokenState == '' || userState.id == '') { - toLoginPage(context); - }*/ - }, - child: Container( - margin: EdgeInsets.only(top: 0.h), - child: Text( - userInfo.value?.name ?? '请前往登录', - style: - TextStyle(fontSize: 16.sp, color: const Color(0xFF332A2A), fontWeight: FontWeight.w500), - ), - ), - ), - const Spacer(), - InkWell( - onTap: () { - _showAlertDialog(context); - }, - child: Container( - padding: EdgeInsets.all(2.r), - decoration: BoxDecoration( - color: const Color.fromRGBO(255, 255, 255, 1), - borderRadius: BorderRadius.circular(50.r), - ), - child: Image.asset('assets/images/out_icon.png', fit: BoxFit.cover), - ), - ) - ], - ), - ), - SizedBox(height: 14.h), - Container( - margin: EdgeInsets.symmetric(vertical: 5.h, horizontal: 16.w), - padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 16.w), - alignment: Alignment.center, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(6.w)), - color: Colors.white, - boxShadow: const [ - BoxShadow( - color: Color.fromRGBO(46, 91, 255, 0.1), - offset: Offset.zero, //阴影y轴偏移量 - blurRadius: 20, //阴影模糊程度 - spreadRadius: 10, //阴影扩散程度 - ) - ], - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('账号', style: personalInfoTitleStly), - Text(userInfo.value?.name ?? '请前往登录', style: personalInfoValStly) - ], - ), - ), - Container( - margin: EdgeInsets.symmetric(vertical: 5.h, horizontal: 16.w), - padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 16.w), - alignment: Alignment.center, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(6.w)), - color: Colors.white, - boxShadow: const [ - BoxShadow( - color: Color.fromRGBO(46, 91, 255, 0.1), - offset: Offset.zero, //阴影y轴偏移量 - blurRadius: 20, //阴影模糊程度 - spreadRadius: 10, //阴影扩散程度 - ) - ], - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('所在学校', style: personalInfoTitleStly), - Text(userInfo.value?.schoolName ?? '', style: personalInfoValStly) - ], - ), - ), - Container( - margin: EdgeInsets.symmetric(vertical: 5.h, horizontal: 16.w), - padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 16.w), - alignment: Alignment.center, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(6.w)), - color: Colors.white, - boxShadow: const [ - BoxShadow( - color: Color.fromRGBO(46, 91, 255, 0.1), - offset: Offset.zero, //阴影y轴偏移量 - blurRadius: 20, //阴影模糊程度 - spreadRadius: 10, //阴影扩散程度 - ) - ], - ), - child: InkWell( - onTap: () { - Get.toNamed(Routes.otherPage); - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('其他', style: personalInfoTitleStly), - Icon( - Icons.arrow_forward_ios, - color: const Color.fromRGBO(80, 87, 103, 1), - size: 13.sp, - ) - ], - ), - ), - ), - ], - ), - ), - ), - ], - ); + return PlatformUtils.isDesktop ? const MyInfoDesktop() : const MyInfoMobile(); } } diff --git a/making_school_asignment_app/lib/page/home_page/children/my_info_desktop.dart b/making_school_asignment_app/lib/page/home_page/children/my_info_desktop.dart new file mode 100644 index 0000000..d7cd224 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/my_info_desktop.dart @@ -0,0 +1,229 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/user_info_detail.dart'; +import 'package:making_school_asignment_app/common/store/app_storage_key.dart'; +import 'package:making_school_asignment_app/common/store/user_store.dart'; +import 'package:making_school_asignment_app/common/utils/storage.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +class MyInfoDesktop extends StatefulWidget { + const MyInfoDesktop({super.key}); + + @override + State createState() => _MyInfoDesktopState(); +} + +class _MyInfoDesktopState extends State with AutomaticKeepAliveClientMixin { + late Rx userInfo = UserStore.to.userDetailInfo; + + @override + bool get wantKeepAlive => true; + + // 确认对话框 + _showLogoutDialog(BuildContext context) async { + return showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('退出登录'), + content: const Text('您确定要退出登录吗?'), + actions: [ + TextButton( + child: const Text('取消'), + onPressed: () => Navigator.of(context).pop(false), + ), + TextButton( + child: const Text('确定'), + onPressed: () async { + try { + var pwd = StorageService.to.read(AppStorageKey.pwd.value); + var account = StorageService.to.read(AppStorageKey.account.value); + + UserStore.to.erase(); + await StorageService.to.erase(); + StorageService.to.write(AppStorageKey.privacyAgreement.value, true); + StorageService.to.write(AppStorageKey.account.value, account); + StorageService.to.write(AppStorageKey.pwd.value, pwd); + Navigator.of(context).pop(true); + Get.offAllNamed(Routes.login); + } catch (e) { + print(e); + } + }, + ), + ], + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + super.build(context); + + return Scaffold( + backgroundColor: const Color(0xFFF0F2F5), + body: SingleChildScrollView( + padding: EdgeInsets.all(24.r), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildHeader(), + SizedBox(height: 24.h), + _buildUserCard(), + SizedBox(height: 16.h), + _buildInfoCards(), + ], + ), + ), + ); + } + + Widget _buildHeader() { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '个人信息', + style: TextStyle(fontSize: 24.sp, fontWeight: FontWeight.bold, color: const Color(0xFF333333)), + ), + ElevatedButton.icon( + onPressed: () => _showLogoutDialog(context), + icon: const Icon(Icons.logout, size: 18), + label: const Text('退出登录'), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.red[50], + foregroundColor: Colors.red[700], + elevation: 0, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.r)), + ), + ), + ], + ); + } + + Widget _buildUserCard() { + return Card( + elevation: 2, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)), + child: Container( + padding: EdgeInsets.all(24.r), + child: Row( + children: [ + Container( + width: 80.r, + height: 80.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(40.r), + color: Colors.grey[200], + ), + child: Icon(Icons.person, size: 40.r, color: Colors.grey[600]), + ), + SizedBox(width: 24.w), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + userInfo.value?.name ?? '未登录用户', + style: TextStyle(fontSize: 20.sp, fontWeight: FontWeight.bold, color: const Color(0xFF333333)), + ), + SizedBox(height: 8.h), + Text( + userInfo.value?.schoolName ?? '暂无学校信息', + style: TextStyle(fontSize: 14.sp, color: Colors.grey[600]), + ), + ], + ), + ), + ], + ), + ), + ); + } + + Widget _buildInfoCards() { + return Column( + children: [ + _buildInfoCard('账号信息', userInfo.value?.name ?? '请前往登录', Icons.account_circle), + SizedBox(height: 12.h), + _buildInfoCard('所在学校', userInfo.value?.schoolName ?? '暂无', Icons.school), + SizedBox(height: 12.h), + _buildClickableInfoCard('其他设置', '点击查看更多选项', Icons.settings, () { + Get.toNamed(Routes.otherPage); + }), + ], + ); + } + + Widget _buildInfoCard(String title, String value, IconData icon) { + return Card( + elevation: 1, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.r)), + child: Container( + padding: EdgeInsets.all(16.r), + child: Row( + children: [ + Icon(icon, size: 24.r, color: Colors.grey[600]), + SizedBox(width: 16.w), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: TextStyle(fontSize: 14.sp, fontWeight: FontWeight.w500, color: const Color(0xFF333333)), + ), + SizedBox(height: 4.h), + Text( + value, + style: TextStyle(fontSize: 13.sp, color: Colors.grey[600]), + ), + ], + ), + ), + ], + ), + ), + ); + } + + Widget _buildClickableInfoCard(String title, String subtitle, IconData icon, VoidCallback onTap) { + return Card( + elevation: 1, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.r)), + child: InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(8.r), + child: Container( + padding: EdgeInsets.all(16.r), + child: Row( + children: [ + Icon(icon, size: 24.r, color: Colors.grey[600]), + SizedBox(width: 16.w), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: TextStyle(fontSize: 14.sp, fontWeight: FontWeight.w500, color: const Color(0xFF333333)), + ), + SizedBox(height: 4.h), + Text( + subtitle, + style: TextStyle(fontSize: 13.sp, color: Colors.grey[600]), + ), + ], + ), + ), + Icon(Icons.arrow_forward_ios, size: 16.r, color: Colors.grey[400]), + ], + ), + ), + ), + ); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/my_info_mobile.dart b/making_school_asignment_app/lib/page/home_page/children/my_info_mobile.dart new file mode 100644 index 0000000..9988cca --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/my_info_mobile.dart @@ -0,0 +1,247 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/user_info_detail.dart'; +import 'package:making_school_asignment_app/common/store/app_storage_key.dart'; +import 'package:making_school_asignment_app/common/store/user_store.dart'; +import 'package:making_school_asignment_app/common/utils/storage.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +class MyInfoMobile extends StatefulWidget { + const MyInfoMobile({super.key}); + + @override + State createState() => _MyInfoMobileState(); +} + +class _MyInfoMobileState extends State with AutomaticKeepAliveClientMixin { + late Rx userInfo = UserStore.to.userDetailInfo; + + @override + void initState() { + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarIconBrightness: Brightness.light, + statusBarColor: Colors.transparent, //状态栏背景颜色 + // systemStatusBarContrastEnforced: false, + )); + super.initState(); + } + + // 确认对话框 + _showAlertDialog(context1) async { + await showDialog( + // 表示点击灰色背景的时候是否消失弹出框 + barrierDismissible: false, + context: context1, + builder: (context) { + return AlertDialog(title: quickText("提示信息"), content: quickText("您确定要退出登录吗?"), actions: [ + TextButton( + child: quickText("取消"), + onPressed: () { + Navigator.pop(context, 'Cancle'); + }, + ), + TextButton( + child: quickText("确定"), + onPressed: () async { + try { + var pwd = StorageService.to.read(AppStorageKey.pwd.value); + var account = StorageService.to.read(AppStorageKey.account.value); + + UserStore.to.erase(); + await StorageService.to.erase(); + StorageService.to.write(AppStorageKey.privacyAgreement.value, true); + StorageService.to.write(AppStorageKey.account.value, account); + StorageService.to.write(AppStorageKey.pwd.value, pwd); + Navigator.pop(context, "Ok"); + Get.offAllNamed(Routes.login); + } catch (e) { + print(e); + } + }) + ]); + }); + } + + @override + bool get wantKeepAlive => true; + + @override + Widget build(BuildContext context) { + super.build(context); + + final personalInfoTitleStly = TextStyle( + color: const Color.fromRGBO(80, 87, 103, 1), + fontSize: 13.sp, + ); + final personalInfoValStly = TextStyle( + color: const Color.fromRGBO(148, 163, 182, 1), + fontSize: 13.sp, + ); + + return Stack( + children: [ + SizedBox( + height: double.infinity, + child: Column( + children: [ + Container( + height: 220.h, + width: double.infinity, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/personal_bg.png'), + fit: BoxFit.cover, + ), + ), + ), + Expanded( + child: Container( + color: const Color.fromRGBO(248, 248, 248, 1), + )) + ], + ), + ), + SafeArea( + child: Scaffold( + backgroundColor: Colors.transparent, + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + height: 150.h, + padding: EdgeInsets.only(left: 20.r, right: 20.r), + // alignment: Alignment.center, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Image.asset( + 'assets/images/default_user_dead.png', + ), + SizedBox( + width: 5.w, + ), + InkWell( + onTap: () { + /*if (tokenState == '' || userState.id == '') { + toLoginPage(context); + }*/ + }, + child: Container( + margin: EdgeInsets.only(top: 0.h), + child: Text( + userInfo.value?.name ?? '请前往登录', + style: + TextStyle(fontSize: 16.sp, color: const Color(0xFF332A2A), fontWeight: FontWeight.w500), + ), + ), + ), + const Spacer(), + InkWell( + onTap: () { + _showAlertDialog(context); + }, + child: Container( + padding: EdgeInsets.all(2.r), + decoration: BoxDecoration( + color: const Color.fromRGBO(255, 255, 255, 1), + borderRadius: BorderRadius.circular(50.r), + ), + child: Image.asset('assets/images/out_icon.png', fit: BoxFit.cover), + ), + ) + ], + ), + ), + SizedBox(height: 14.h), + Container( + margin: EdgeInsets.symmetric(vertical: 5.h, horizontal: 16.w), + padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 16.w), + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(6.w)), + color: Colors.white, + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(46, 91, 255, 0.1), + offset: Offset.zero, //阴影y轴偏移量 + blurRadius: 20, //阴影模糊程度 + spreadRadius: 10, //阴影扩散程度 + ) + ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('账号', style: personalInfoTitleStly), + Text(userInfo.value?.name ?? '请前往登录', style: personalInfoValStly) + ], + ), + ), + Container( + margin: EdgeInsets.symmetric(vertical: 5.h, horizontal: 16.w), + padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 16.w), + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(6.w)), + color: Colors.white, + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(46, 91, 255, 0.1), + offset: Offset.zero, //阴影y轴偏移量 + blurRadius: 20, //阴影模糊程度 + spreadRadius: 10, //阴影扩散程度 + ) + ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('所在学校', style: personalInfoTitleStly), + Text(userInfo.value?.schoolName ?? '', style: personalInfoValStly) + ], + ), + ), + Container( + margin: EdgeInsets.symmetric(vertical: 5.h, horizontal: 16.w), + padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 16.w), + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(6.w)), + color: Colors.white, + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(46, 91, 255, 0.1), + offset: Offset.zero, //阴影y轴偏移量 + blurRadius: 20, //阴影模糊程度 + spreadRadius: 10, //阴影扩散程度 + ) + ], + ), + child: InkWell( + onTap: () { + Get.toNamed(Routes.otherPage); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('其他', style: personalInfoTitleStly), + Icon( + Icons.arrow_forward_ios, + color: const Color.fromRGBO(80, 87, 103, 1), + size: 13.sp, + ) + ], + ), + ), + ), + ], + ), + ), + ), + ], + ); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_desktop_view.dart b/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_desktop_view.dart new file mode 100644 index 0000000..78a5ec9 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_desktop_view.dart @@ -0,0 +1,175 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/mixins/getx_keepalive_widget.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/page/home_page/children/read_over/widget/annotate_list.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'read_over_logic.dart'; + +class ReadOverDesktopPage extends GetxKeepAliveWidget { + const ReadOverDesktopPage({super.key}); + + @override + Widget buildContent(BuildContext context, ReadOverLogic controller) { + final state = controller.state; + return Scaffold( + backgroundColor: const Color(0xFFF0F2F5), + body: Column( + children: [ + _buildHeader(context, controller, state), + Expanded( + child: Container( + padding: EdgeInsets.all(24.r), + child: Card( + elevation: 2, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)), + child: Column( + children: [ + _buildTabBar(context, controller, state), + Expanded( + child: Obx(() { + return AnnotateList( + tabIndex: state.tabIndex.value, + assessType: 0, + ); + }), + ), + ], + ), + ), + ), + ), + ], + ), + ); + } + + Widget _buildHeader(BuildContext context, ReadOverLogic controller, dynamic state) { + return Container( + padding: EdgeInsets.all(24.r), + color: Colors.white, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '作业批阅', + style: TextStyle( + fontSize: 24.sp, + fontWeight: FontWeight.bold, + color: const Color(0xFF333333), + ), + ), + Row( + children: [ + IconButton( + onPressed: () { + Get.toNamed(Routes.studentHistoryWorkPage, arguments: {'page': 'set'}); + }, + icon: Icon( + const IconData(0xe63e, fontFamily: "AlibabaIcon"), + color: const Color.fromRGBO(44, 48, 63, 1), + size: 24.sp, + ), + tooltip: '设置', + ), + IconButton( + onPressed: () => Get.back(), + icon: Icon(Icons.close, size: 24.sp, color: Colors.grey[600]), + tooltip: '关闭', + ), + ], + ), + ], + ), + ); + } + + Widget _buildTabBar(BuildContext context, ReadOverLogic controller, dynamic state) { + return Container( + padding: EdgeInsets.all(16.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + decoration: BoxDecoration( + color: const Color.fromRGBO(243, 243, 243, 1), + borderRadius: BorderRadius.circular(8.r), + ), + child: TabBar( + padding: EdgeInsets.zero, + indicatorPadding: EdgeInsets.zero, + indicatorWeight: 0, + labelPadding: EdgeInsets.symmetric(horizontal: 2.w), + controller: controller.tabController, + unselectedLabelStyle: TextStyle( + fontSize: 14.sp, + color: const Color.fromRGBO(69, 83, 100, 1), + ), + labelStyle: TextStyle( + fontSize: 14.sp, + color: const Color(0xFF8C68FF), + ), + indicator: const UnderlineTabIndicator( + borderSide: BorderSide(width: 0, color: Colors.transparent), + ), + onTap: (index) { + state.tabIndex.value = index; + if (index == 1 && state.completedToRefresh) { + state.completedToRefresh = false; + } + }, + tabs: [ + Tab( + iconMargin: EdgeInsets.zero, + height: 34.h, + child: Obx(() { + return Container( + width: 140.w, + alignment: Alignment.center, + decoration: BoxDecoration( + color: state.tabIndex.value == 0 ? const Color.fromRGBO(255, 255, 255, 1) : null, + borderRadius: BorderRadius.all(Radius.circular(8.r)), + ), + child: quickText( + '待批阅', + size: 14.sp, + color: state.tabIndex.value == 0 + ? Theme.of(context).primaryColor + : const Color.fromRGBO(80, 94, 110, 1), + fontWeight: state.tabIndex.value == 0 ? FontWeight.bold : null, + ), + ); + }), + ), + Tab( + iconMargin: EdgeInsets.zero, + height: 34.h, + child: Obx(() { + return Container( + width: 140.w, + alignment: Alignment.center, + decoration: BoxDecoration( + color: state.tabIndex.value == 1 ? const Color.fromRGBO(255, 255, 255, 1) : null, + borderRadius: BorderRadius.all(Radius.circular(8.r)), + ), + child: quickText( + '已批阅', + size: 14.sp, + color: state.tabIndex.value == 1 + ? Theme.of(context).primaryColor + : const Color.fromRGBO(80, 94, 110, 1), + fontWeight: state.tabIndex.value == 1 ? FontWeight.bold : null, + ), + ); + }), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_mobile_view.dart b/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_mobile_view.dart new file mode 100644 index 0000000..95efa5b --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_mobile_view.dart @@ -0,0 +1,174 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/mixins/getx_keepalive_widget.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/page/home_page/children/read_over/widget/annotate_list.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'read_over_logic.dart'; + +class ReadOverMobilePage extends GetxKeepAliveWidget { + const ReadOverMobilePage({super.key}); + + @override + void initState() { + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + statusBarIconBrightness: Brightness.dark, + systemStatusBarContrastEnforced: false, + )); + super.initState(); + } + + @override + Widget buildContent(BuildContext context, ReadOverLogic controller) { + final state = controller.state; + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + Container( + height: 60.h, + padding: EdgeInsets.symmetric(horizontal: 10.w), + child: Row( + children: [ + Expanded( + flex: 1, + child: InkWell( + onTap: () => Get.back(), + child: Container( + height: 30.h, + alignment: Alignment.centerLeft, + padding: EdgeInsets.only(left: 10.w), + child: Icon(Icons.arrow_back_ios_sharp, size: 16.sp), + ), + ), + ), + Expanded( + flex: 4, + child: Container( + padding: EdgeInsets.symmetric(vertical: 2.h), + alignment: Alignment.center, + decoration: BoxDecoration( + color: const Color.fromRGBO(243, 243, 243, 1), + borderRadius: BorderRadius.circular(8.r), + ), + child: TabBar( + padding: EdgeInsets.zero, + indicatorPadding: EdgeInsets.zero, + indicatorWeight: 0, + labelPadding: EdgeInsets.symmetric(horizontal: 2.w), + controller: controller.tabController, + unselectedLabelStyle: TextStyle( + fontSize: 14.sp, + color: const Color.fromRGBO(69, 83, 100, 1), + ), + labelStyle: TextStyle( + fontSize: 14.sp, + color: const Color(0xFF8C68FF), + ), + indicator: const UnderlineTabIndicator( + borderSide: BorderSide(width: 0, color: Colors.transparent), + ), + onTap: (index) { + state.tabIndex.value = index; + if (index == 1 && state.completedToRefresh) { + state.completedToRefresh = false; + } + }, + tabs: [ + Tab( + iconMargin: EdgeInsets.zero, + height: 34.h, + child: Obx(() { + return Container( + width: 140.w, + alignment: Alignment.center, + decoration: BoxDecoration( + color: state.tabIndex.value == 0 ? const Color.fromRGBO(255, 255, 255, 1) : null, + borderRadius: BorderRadius.all(Radius.circular(8.r)), + ), + child: quickText( + '待批阅', + size: 14.sp, + color: state.tabIndex.value == 0 + ? Theme.of(context).primaryColor + : const Color.fromRGBO(80, 94, 110, 1), + fontWeight: state.tabIndex.value == 0 ? FontWeight.bold : null, + ), + ); + }), + ), + Tab( + iconMargin: EdgeInsets.zero, + height: 34.h, + child: Obx(() { + return Container( + width: 140.w, + alignment: Alignment.center, + decoration: BoxDecoration( + color: state.tabIndex.value == 1 ? const Color.fromRGBO(255, 255, 255, 1) : null, + borderRadius: BorderRadius.all(Radius.circular(8.r)), + ), + child: quickText( + '已批阅', + size: 14.sp, + color: state.tabIndex.value == 1 + ? Theme.of(context).primaryColor + : const Color.fromRGBO(80, 94, 110, 1), + fontWeight: state.tabIndex.value == 1 ? FontWeight.bold : null, + ), + ); + }), + ), + ], + ), + ), + ), + Expanded( + flex: 1, + child: InkWell( + onTap: () { + Get.toNamed(Routes.studentHistoryWorkPage, arguments: {'page': 'set'}); + }, + child: Icon( + const IconData(0xe63e, fontFamily: "AlibabaIcon"), + color: const Color.fromRGBO(44, 48, 63, 1), + size: 24.sp, + ), + ), + ), + ], + ), + ), + Expanded( + child: Container( + color: const Color.fromRGBO(245, 245, 245, 1), + child: Obx(() { + return AnnotateList( + tabIndex: state.tabIndex.value, + assessType: 0, + ); + }), + ), + ), + ], + ), + ), + ); + } + + @override + void dispose() { + Get.delete(); + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + statusBarIconBrightness: Brightness.light, + systemStatusBarContrastEnforced: false, + )); + super.dispose(); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_view.dart b/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_view.dart index fdb745c..38d2502 100644 --- a/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_view.dart +++ b/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_view.dart @@ -1,197 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; -import 'package:making_school_asignment_app/page/home_page/children/read_over/widget/annotate_list.dart'; -import 'package:making_school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/common/utils/platform_utils.dart'; +import 'package:making_school_asignment_app/page/home_page/children/read_over/read_over_desktop_view.dart'; +import 'package:making_school_asignment_app/page/home_page/children/read_over/read_over_mobile_view.dart'; -import 'read_over_logic.dart'; - -class ReadOverPage extends StatefulWidget { +class ReadOverPage extends StatelessWidget { const ReadOverPage({super.key}); - @override - State createState() => _ReadOverPageState(); -} - -class _ReadOverPageState extends State { - final logic = Get.find(); - final state = Get.find().state; - - @override - void initState() { - super.initState(); - } - @override Widget build(BuildContext context) { - return AnnotatedRegion( - value: const SystemUiOverlayStyle( - /* systemNavigationBarColor: Color(0xFF000000), - systemNavigationBarDividerColor: null,*/ - statusBarColor: Colors.white, - systemNavigationBarDividerColor: null, - systemNavigationBarIconBrightness: Brightness.light, - statusBarIconBrightness: Brightness.light, - statusBarBrightness: Brightness.light, - ), - child: Scaffold( - backgroundColor: Colors.white, - body: OrientationBuilder( - builder: (BuildContext context, Orientation orientation) { - return Column( - children: [ - Container( - color: Colors.white, - margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top), - padding: EdgeInsets.only(bottom: 9.h, top: 4.h), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - flex: 1, - child: InkWell( - onTap: () { - Get.back(); - }, - child: Container( - height: 30.h, - alignment: Alignment.centerLeft, - padding: EdgeInsets.only(left: 10.w), - child: Icon( - Icons.arrow_back_ios_sharp, - size: 16.sp, - ), - ), - )), - Expanded( - flex: 4, - child: Container( - padding: EdgeInsets.symmetric(vertical: 2.h), - alignment: Alignment.center, - decoration: BoxDecoration( - color: const Color.fromRGBO(243, 243, 243, 1), - borderRadius: BorderRadius.circular(8.r), - ), - child: TabBar( - padding: EdgeInsets.zero, - indicatorPadding: EdgeInsets.zero, - indicatorWeight: 0, - labelPadding: EdgeInsets.symmetric(horizontal: 2.w), - controller: logic.tabController, - unselectedLabelStyle: TextStyle( - fontSize: 14.sp, - color: const Color.fromRGBO(69, 83, 100, 1), - ), - labelStyle: TextStyle( - fontSize: 14.sp, - color: const Color(0xFF8C68FF), - ), - // labelColor: const Color.fromRGBO(45, 56, 76, 1), - indicator: const UnderlineTabIndicator( - borderSide: BorderSide( - width: 0, // 设置边界宽度为0,从而去除下划线 - color: Colors.transparent), - ), - onTap: (index) { - state.tabIndex.value = index; - if (index == 1 && state.completedToRefresh) { - // 已阅卷 - // _refreshController2.callRefresh(); - state.completedToRefresh = false; - } - }, - tabs: [ - Tab( - iconMargin: EdgeInsets.zero, - height: 34.h, - child: Obx(() { - return Container( - width: 140.w, - alignment: Alignment.center, - decoration: BoxDecoration( - color: state.tabIndex.value == 0 ? const Color.fromRGBO(255, 255, 255, 1) : null, - borderRadius: BorderRadius.all(Radius.circular(8.r)), - ), - child: quickText( - '待批阅', - size: 14.sp, - color: state.tabIndex.value == 0 - ? Theme.of(context).primaryColor - : const Color.fromRGBO(80, 94, 110, 1), - fontWeight: state.tabIndex.value == 0 ? FontWeight.bold : null, - ), - ); - }), - ), - Tab( - iconMargin: EdgeInsets.zero, - height: 34.h, - child: Obx(() { - return Container( - width: 140.w, - alignment: Alignment.center, - decoration: BoxDecoration( - color: state.tabIndex.value == 1 ? const Color.fromRGBO(255, 255, 255, 1) : null, - borderRadius: BorderRadius.all(Radius.circular(8.r)), - ), - child: quickText( - '已批阅', - size: 14.sp, - color: state.tabIndex.value == 1 - ? Theme.of(context).primaryColor - : const Color.fromRGBO(80, 94, 110, 1), - fontWeight: state.tabIndex.value == 1 ? FontWeight.bold : null, - ), - ); - }), - ), - ], - ), - ), - ), - Expanded( - flex: 1, - child: InkWell( - onTap: () { - Get.toNamed(Routes.studentHistoryWorkPage, arguments: {'page': 'set'}); - }, - child: Icon(const IconData(0xe63e, fontFamily: "AlibabaIcon"), - color: const Color.fromRGBO(44, 48, 63, 1), size: 24.sp), - ), - ), - ], - ), - ), - Expanded( - child: Container( - color: const Color.fromRGBO(245, 245, 245, 1), - child: Obx(() { - return AnnotateList( - tabIndex: state.tabIndex.value, - assessType: 0, - ); - }), - ), - ), - ], - ); - }, - ), - ), - ); - } - - @override - void dispose() { - Get.delete(); - logic.homeController.getList(); - SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( - statusBarColor: Colors.transparent, //状态栏背景颜色 - statusBarIconBrightness: Brightness.light, - systemStatusBarContrastEnforced: false, - )); - super.dispose(); + return PlatformUtils.isDesktop ? const ReadOverDesktopPage() : const ReadOverMobilePage(); } } diff --git a/making_school_asignment_app/lib/page/home_page/home_desktop_view.dart b/making_school_asignment_app/lib/page/home_page/home_desktop_view.dart new file mode 100644 index 0000000..8de24e5 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/home_desktop_view.dart @@ -0,0 +1,217 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/mixins/getx_keepalive_widget.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'home_logic.dart'; + +class HomeDesktopPage extends GetxKeepAliveWidget { + const HomeDesktopPage({super.key}); + + @override + Widget buildContent(BuildContext context, HomeLogic controller) { + final state = controller.state; + return Scaffold( + backgroundColor: const Color(0xFFF0F2F5), + body: RefreshIndicator( + onRefresh: () { + state.pageNumber = 1; + return Future.microtask(() => controller.getList()); + }, + child: CustomScrollView( + physics: const AlwaysScrollableScrollPhysics(), + slivers: [ + SliverPadding( + padding: EdgeInsets.all(24.r), + sliver: SliverToBoxAdapter(child: _buildHeader(controller)), + ), + SliverPadding( + padding: EdgeInsets.symmetric(horizontal: 24.r, vertical: 0), + sliver: _buildMenuSliverGrid(state), + ), + ], + ), + ), + ); + } + + Widget _buildHeader(HomeLogic controller) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '我的作业管理', + style: TextStyle(fontSize: 24.sp, fontWeight: FontWeight.bold, color: const Color(0xFF333333)), + ), + IconButton( + onPressed: () => controller.getList(), + icon: Icon(Icons.refresh, size: 24.sp, color: Colors.grey[600]), + tooltip: '刷新数据', + ), + ], + ); + } + + SliverGrid _buildMenuSliverGrid(dynamic state) { + final menuItems = [ + { + 'bgImg': 'assets/images/home_bg_01.png', + 'name': '作业批阅', + 'url': Routes.readOverPage, + 'isPrimary': true, + 'value': state.totalCount + }, + { + 'bgImg': 'assets/images/home_bg_02.png', + 'name': '知识点掌握', + 'url': Routes.studentHistoryWorkPage, + 'page': 'points' + }, + { + 'bgImg': 'assets/images/home_bg_03.png', + 'name': '学生历史作业', + 'url': Routes.studentHistoryWorkPage, + 'page': 'history' + }, + {'bgImg': 'assets/images/home_bg_04.png', 'name': '答题轨迹', 'url': Routes.answerTrajectoryPage}, + {'bgImg': 'assets/images/home_bg_05.png', 'name': '优先批阅设定', 'url': Routes.studentHistoryWorkPage, 'page': 'set'}, + ]; + + int crossAxisCount; + final width = Get.width; + if (width > 1200) { + crossAxisCount = 4; + } else if (width > 800) { + crossAxisCount = 3; + } else { + crossAxisCount = 2; + } + + return SliverGrid( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: crossAxisCount, + crossAxisSpacing: 16.r, + mainAxisSpacing: 16.r, + childAspectRatio: 1.5, + ), + delegate: SliverChildBuilderDelegate( + (context, index) { + final item = menuItems[index]; + if (item['value'] is RxInt) { + return Obx(() => _MenuItem( + bgImg: item['bgImg'] as String, + name: item['name'] as String, + url: item['url'] as String, + page: item['page'] as String?, + isPrimary: item['isPrimary'] as bool? ?? false, + value: (item['value'] as RxInt).value > 0 ? (item['value'] as RxInt).value.toString() : null, + )); + } + return _MenuItem( + bgImg: item['bgImg'] as String, + name: item['name'] as String, + url: item['url'] as String, + page: item['page'] as String?, + isPrimary: item['isPrimary'] as bool? ?? false, + ); + }, + childCount: menuItems.length, + ), + ); + } +} + +class _MenuItem extends StatefulWidget { + final String bgImg; + final String name; + final String? value; + final String url; + final String? page; + final bool isPrimary; + + const _MenuItem({ + required this.bgImg, + required this.name, + this.value, + required this.url, + this.page, + this.isPrimary = false, + }); + + @override + __MenuItemState createState() => __MenuItemState(); +} + +class __MenuItemState extends State<_MenuItem> { + bool _isHovered = false; + + @override + Widget build(BuildContext context) { + return MouseRegion( + onEnter: (_) => setState(() => _isHovered = true), + onExit: (_) => setState(() => _isHovered = false), + cursor: SystemMouseCursors.click, + child: Card( + elevation: _isHovered ? 8.0 : 2.0, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)), + shadowColor: Colors.black.withOpacity(0.1), + child: InkWell( + onTap: () => Get.toNamed(widget.url, arguments: {'page': widget.page ?? ''}), + borderRadius: BorderRadius.circular(12.r), + child: Container( + padding: EdgeInsets.all(16.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12.r), + gradient: widget.isPrimary ? const LinearGradient(colors: [Color(0xFF667eea), Color(0xFF764ba2)]) : null, + color: widget.isPrimary ? null : Colors.white, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Text( + widget.name, + style: TextStyle( + fontSize: 14.sp, + color: widget.isPrimary ? Colors.white : const Color(0xFF2C2C2C), + fontWeight: FontWeight.w600, + ), + ), + ), + if (widget.value != null && widget.value!.isNotEmpty) + Container( + padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h), + decoration: BoxDecoration( + color: widget.isPrimary ? Colors.white : const Color(0xFFFF6969), + borderRadius: BorderRadius.circular(12.r), + ), + child: Text( + widget.value!, + style: TextStyle( + fontSize: 12.sp, + color: widget.isPrimary ? const Color(0xFFFF6969) : Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + Icon( + Icons.arrow_forward, + size: 16.sp, + color: widget.isPrimary ? Colors.white70 : Colors.grey[400], + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/home_mobile_view.dart b/making_school_asignment_app/lib/page/home_page/home_mobile_view.dart new file mode 100644 index 0000000..e377eaa --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/home_mobile_view.dart @@ -0,0 +1,436 @@ +import 'package:badges/badges.dart' as badges; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:functional_widget_annotation/functional_widget_annotation.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/mixins/getx_keepalive_widget.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'home_logic.dart'; + +part 'home_mobile_view.g.dart'; + +class HomeMobilePage extends GetxKeepAliveWidget { + const HomeMobilePage({super.key}); + + @override + void initState() { + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, //状态栏背景颜色 + statusBarIconBrightness: Brightness.light, + systemStatusBarContrastEnforced: false, + )); + super.initState(); + } + + @override + Widget buildContent(context, controller) { + return Scaffold( + backgroundColor: Colors.white, + body: OrientationBuilder( + builder: (BuildContext context, Orientation orientation) { + final state = controller.state; + return EasyRefresh( + firstRefresh: false, + taskIndependence: true, + enableControlFinishLoad: true, + controller: controller.refreshController, + header: MaterialHeader(), + onRefresh: () async { + state.pageNumber = 1; + return controller.getList(); + }, + child: CustomScrollView( + slivers: [ + // 顶部横幅区域 + SliverAppBar( + expandedHeight: 300.h, + floating: false, + pinned: false, + backgroundColor: Colors.transparent, + flexibleSpace: FlexibleSpaceBar( + background: Image.asset( + 'assets/images/home_banner.png', + width: Get.width, + fit: BoxFit.cover, + ), + ), + ), + // 主要内容区域 + SliverToBoxAdapter( + child: Container( + padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20.r), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only(topLeft: Radius.circular(30.r), topRight: Radius.circular(30.r)), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 20.r), + // 标题区域 + Row( + children: [ + Icon( + Icons.assignment_outlined, + size: 24.sp, + color: const Color(0xFF4F4F4F), + ), + SizedBox(width: 8.r), + Text( + '我的作业管理', + style: TextStyle( + fontSize: 22.sp, color: const Color(0xFF2C2C2C), fontWeight: FontWeight.w700), + ), + const Spacer(), + // 刷新按钮 + IconButton( + onPressed: () => controller.refreshController.callRefresh(), + icon: Icon( + Icons.refresh, + size: 20.sp, + color: const Color(0xFF4F4F4F), + ), + tooltip: '刷新数据', + ) + ], + ), + + SizedBox(height: 24.r), + // 功能菜单网格 + _buildMenuGrid(context, state), + SizedBox(height: 20.r), + ], + ), + ), + ), + ], + ), + ); + }, + ), + ); + } + + Widget _buildMenuGrid(BuildContext context, dynamic state) { + return Column( + children: [ + // 第一行 + Row( + children: [ + Expanded( + child: Obx(() => $MenuItem( + bgImg: 'assets/images/home_bg_01.png', + name: '作业批阅', + value: state.totalCount.value > 0 ? state.totalCount.value.toString() : null, + url: Routes.readOverPage, + isPrimary: true, + )), + ), + SizedBox(width: 16.r), + const Expanded( + child: $MenuItem( + bgImg: 'assets/images/home_bg_02.png', + name: '知识点掌握', + url: Routes.studentHistoryWorkPage, + page: 'points', + ), + ), + ], + ), + SizedBox(height: 16.r), + // 第二行 + Row( + children: [ + const Expanded( + child: $MenuItem( + bgImg: 'assets/images/home_bg_03.png', + name: '学生历史作业', + url: Routes.studentHistoryWorkPage, + page: 'history', + ), + ), + SizedBox(width: 16.r), + const Expanded( + child: $MenuItem(bgImg: 'assets/images/home_bg_04.png', name: '答题轨迹', url: Routes.answerTrajectoryPage), + ), + ], + ), + SizedBox(height: 16.r), + // 第三行 + Row( + children: [ + const Expanded( + child: $MenuItem( + bgImg: 'assets/images/home_bg_05.png', + name: '优先批阅设定', + url: Routes.studentHistoryWorkPage, + page: 'set', + ), + ), + SizedBox(width: 16.r), + // 占位空间 + const Expanded(child: SizedBox()), + ], + ), + ], + ); + } +} + +@swidget +Widget $menuItem({ + required String bgImg, + required String name, + String? value, + required String url, + String? page, + bool isPrimary = false, +}) { + return Material( + color: Colors.transparent, + child: InkWell( + onTap: () { + Get.toNamed(url, arguments: {'page': page ?? ''}); + }, + borderRadius: BorderRadius.circular(12.r), + child: Semantics( + label: '$name${value != null ? ',待处理数量:$value' : ''}', + hint: '点击进入$name页面', + button: true, + child: Container( + width: (Get.width - 60.r) / 2, + height: (Get.width - 60.r) / 2 * 86 / 164, + padding: EdgeInsets.all(16.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12.r), + gradient: isPrimary + ? const LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color(0xFF667eea), + Color(0xFF764ba2), + ], + ) + : null, + color: isPrimary ? null : Colors.white, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.08), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + image: !isPrimary + ? DecorationImage( + image: AssetImage(bgImg), + fit: BoxFit.cover, + colorFilter: ColorFilter.mode( + Colors.white.withOpacity(0.8), + BlendMode.srcATop, + ), + ) + : null, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Text( + name, + style: TextStyle( + fontSize: 14.sp, + color: isPrimary ? Colors.white : const Color(0xFF2C2C2C), + fontWeight: FontWeight.w600, + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ), + if (value != null && value != '') + Semantics( + label: '待处理数量:$value', + child: Container( + width: 20.r, + height: 20.r, + alignment: Alignment.center, + decoration: BoxDecoration( + color: isPrimary ? Colors.white : const Color(0xFFFF6969), + borderRadius: BorderRadius.all(Radius.circular(10.r)), + ), + child: Text( + value, + style: TextStyle( + fontSize: 10.sp, + color: isPrimary ? const Color(0xFFFF6969) : Colors.white, + fontWeight: FontWeight.w600), + ), + ), + ) + ], + ), + const Spacer(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (isPrimary) + Icon( + Icons.arrow_forward_ios, + size: 14.sp, + color: Colors.white, + ) + else + Image.asset( + 'assets/images/home_right_icon.png', + width: 16.r, + height: 16.r, + semanticLabel: '进入图标', + ), + ], + ), + ], + ), + ), + ), + ), + ); +} + +class EntranceModel extends Object { + String title; + String image; + String navigationUrl; + String? page; + + EntranceModel({required this.title, required this.image, required this.navigationUrl, this.page}); +} + +@swidget +Widget $termRow(BuildContext context, List items, int? data) { + var leng = items.length; + Widget childWidget; + switch (leng) { + case 1: + childWidget = Row(children: [Expanded(child: $TermItem(items[0], data!))]); + break; + case 2: + childWidget = Row(children: [ + Expanded(flex: 9, child: $TermItem(items[0], data!)), + // const Expanded(flex: 1, child: SizedBox()), + SizedBox(width: ScreenUtil().screenWidth / 30), + Expanded(flex: 9, child: $TermItem(items[1], data)), + ]); + break; + case 3: + double theHeight = ScreenUtil().screenWidth / 30 + 54.h * 2; + childWidget = Row( + children: [ + Expanded(child: $TermItem(items[0], data!, theHeight: theHeight)), + SizedBox(width: ScreenUtil().screenWidth / 30), + Expanded( + child: SizedBox( + height: theHeight, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + $TermItem(items[1], data), + $TermItem(items[2], data), + ], + ), + ), + ), + ], + ); + break; + default: + childWidget = Container(); + } + + return Container(padding: EdgeInsets.symmetric(horizontal: 14.w), child: childWidget); +} + +@swidget +Widget $termItem(BuildContext context, EntranceModel e, int data, {double? theHeight}) { + bool isJob = e.title == '作业批阅'; + + return Material( + color: Colors.white, + elevation: 3.r, + shadowColor: const Color.fromRGBO(231, 231, 231, 1), + borderRadius: BorderRadius.all(Radius.circular(8.r)), + child: InkWell( + onTap: () { + Get.toNamed(e.navigationUrl, arguments: {'page': e.page ?? ''}); + }, + + // splashColor: splashColor, + borderRadius: BorderRadius.all(Radius.circular(8.r)), + child: badges.Badge( + showBadge: isJob && data > 0, + ignorePointer: false, + badgeContent: quickText(data, color: Colors.white, size: 10.sp), + badgeAnimation: const badges.BadgeAnimation.rotation( + animationDuration: Duration(seconds: 1), + colorChangeAnimationDuration: Duration(seconds: 1), + loopAnimation: false, + curve: Curves.fastOutSlowIn, + colorChangeAnimationCurve: Curves.easeInCubic, + ), + badgeStyle: badges.BadgeStyle( + badgeColor: const Color.fromRGBO(255, 105, 105, 1), + shape: badges.BadgeShape.square, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10.r), topRight: Radius.circular(8.5.r), bottomRight: Radius.circular(8.5.r)), + // borderSide: BorderSide(color: Colors.white, width: 2), + elevation: 1, + padding: EdgeInsets.symmetric(horizontal: Utils.isPad() ? 11.w : 16.w, vertical: 2.h), + ), + position: badges.BadgePosition.topEnd(top: 10.r, end: 10.r), + child: Container( + height: theHeight, + padding: EdgeInsets.symmetric(vertical: 12.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(8.r)), + // boxShadow: [ + // BoxShadow( + // color: const Color.fromRGBO(231, 231, 231, 1), + // offset: Offset(4.w, 6.h), //阴影y轴偏移量 + // blurRadius: 8, //阴影模糊程度 + // spreadRadius: 0.2, //阴影扩散程度 + // ) + // ], + // border: Border.all(width: 0.5.w, color: Color.fromARGB(255, 219, 226, 250)), + ), + alignment: Alignment.center, + child: isJob + ? Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover), + SizedBox(height: 6.r), + quickText(e.title, + size: 12.sp, color: const Color.fromRGBO(79, 79, 79, 1), fontWeight: FontWeight.w500), + ], + ) + : Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover), + SizedBox(width: 6.r), + quickText(e.title, + size: 12.sp, color: const Color.fromRGBO(79, 79, 79, 1), fontWeight: FontWeight.w500), + ], + ), + ), + )), + ); +} diff --git a/making_school_asignment_app/lib/page/home_page/home_view.dart b/making_school_asignment_app/lib/page/home_page/home_view.dart index 856d0ed..7dac3ec 100644 --- a/making_school_asignment_app/lib/page/home_page/home_view.dart +++ b/making_school_asignment_app/lib/page/home_page/home_view.dart @@ -1,474 +1,13 @@ -import 'package:badges/badges.dart' as badges; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_easyrefresh/easy_refresh.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:functional_widget_annotation/functional_widget_annotation.dart'; -import 'package:get/get.dart'; -import 'package:making_school_asignment_app/common/mixins/getx_keepalive_widget.dart'; -import 'package:making_school_asignment_app/common/utils/utils.dart'; -import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; -import 'package:making_school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/common/utils/platform_utils.dart'; +import 'package:making_school_asignment_app/page/home_page/home_desktop_view.dart'; +import 'package:making_school_asignment_app/page/home_page/home_mobile_view.dart'; -import 'home_logic.dart'; - -part 'home_view.g.dart'; - -class HomePage extends GetxKeepAliveWidget { +class HomePage extends StatelessWidget { const HomePage({super.key}); @override - void initState() { - SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( - statusBarColor: Colors.transparent, //状态栏背景颜色 - statusBarIconBrightness: Brightness.light, - systemStatusBarContrastEnforced: false, - )); - super.initState(); - } - - @override - Widget buildContent(context, controller) { - return Scaffold( - backgroundColor: Colors.white, - body: OrientationBuilder( - builder: (BuildContext context, Orientation orientation) { - final state = controller.state; - return EasyRefresh( - firstRefresh: false, - taskIndependence: true, - enableControlFinishLoad: true, - controller: controller.refreshController, - header: MaterialHeader(), - onRefresh: () async { - state.pageNumber = 1; - return controller.getList(); - }, - child: CustomScrollView( - slivers: [ - // 顶部横幅区域 - SliverAppBar( - expandedHeight: 300.h, - floating: false, - pinned: false, - backgroundColor: Colors.transparent, - flexibleSpace: FlexibleSpaceBar( - background: Image.asset( - 'assets/images/home_banner.png', - width: Get.width, - fit: BoxFit.cover, - ), - ), - ), - // 主要内容区域 - SliverToBoxAdapter( - child: Container( - padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20.r), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only(topLeft: Radius.circular(30.r), topRight: Radius.circular(30.r)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox(height: 20.r), - // 标题区域 - Row( - children: [ - Icon( - Icons.assignment_outlined, - size: 24.sp, - color: const Color(0xFF4F4F4F), - ), - SizedBox(width: 8.r), - Text( - '我的作业管理', - style: TextStyle( - fontSize: 22.sp, color: const Color(0xFF2C2C2C), fontWeight: FontWeight.w700), - ), - const Spacer(), - // 刷新按钮 - IconButton( - onPressed: () => controller.refreshController.callRefresh(), - icon: Icon( - Icons.refresh, - size: 20.sp, - color: const Color(0xFF4F4F4F), - ), - tooltip: '刷新数据', - ) - ], - ), - - SizedBox(height: 24.r), - // 功能菜单网格 - _buildMenuGrid(context, state), - SizedBox(height: 20.r), - ], - ), - ), - ), - ], - ), - ); - }, - ), - ); - } - - Widget _buildStatCard(String title, String value, Color color, IconData icon) { - return Container( - padding: EdgeInsets.all(12.r), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8.r), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - children: [ - Icon(icon, color: color, size: 20.sp), - SizedBox(height: 4.r), - Text( - value, - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.bold, - color: color, - ), - ), - Text( - title, - style: TextStyle( - fontSize: 12.sp, - color: const Color(0xFF6C757D), - ), - ), - ], - ), - ); - } - - Widget _buildMenuGrid(BuildContext context, dynamic state) { - return Column( - children: [ - // 第一行 - Row( - children: [ - Expanded( - child: Obx(() => $MenuItem( - bgImg: 'assets/images/home_bg_01.png', - name: '作业批阅', - value: state.totalCount.value > 0 ? state.totalCount.value.toString() : null, - url: Routes.readOverPage, - isPrimary: true, - )), - ), - SizedBox(width: 16.r), - const Expanded( - child: $MenuItem( - bgImg: 'assets/images/home_bg_02.png', - name: '知识点掌握', - url: Routes.studentHistoryWorkPage, - page: 'points', - ), - ), - ], - ), - SizedBox(height: 16.r), - // 第二行 - Row( - children: [ - const Expanded( - child: $MenuItem( - bgImg: 'assets/images/home_bg_03.png', - name: '学生历史作业', - url: Routes.studentHistoryWorkPage, - page: 'history', - ), - ), - SizedBox(width: 16.r), - const Expanded( - child: $MenuItem(bgImg: 'assets/images/home_bg_04.png', name: '答题轨迹', url: Routes.answerTrajectoryPage), - ), - ], - ), - SizedBox(height: 16.r), - // 第三行 - Row( - children: [ - const Expanded( - child: $MenuItem( - bgImg: 'assets/images/home_bg_05.png', - name: '优先批阅设定', - url: Routes.studentHistoryWorkPage, - page: 'set', - ), - ), - SizedBox(width: 16.r), - // 占位空间 - const Expanded(child: SizedBox()), - ], - ), - ], - ); + Widget build(BuildContext context) { + return PlatformUtils.isDesktop ? const HomeDesktopPage() : const HomeMobilePage(); } } - -@swidget -Widget $menuItem({ - required String bgImg, - required String name, - String? value, - required String url, - String? page, - bool isPrimary = false, -}) { - return Material( - color: Colors.transparent, - child: InkWell( - onTap: () { - Get.toNamed(url, arguments: {'page': page ?? ''}); - }, - borderRadius: BorderRadius.circular(12.r), - child: Semantics( - label: '$name${value != null ? ',待处理数量:$value' : ''}', - hint: '点击进入$name页面', - button: true, - child: Container( - width: (Get.width - 60.r) / 2, - height: (Get.width - 60.r) / 2 * 86 / 164, - padding: EdgeInsets.all(16.r), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12.r), - gradient: isPrimary - ? const LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - Color(0xFF667eea), - Color(0xFF764ba2), - ], - ) - : null, - color: isPrimary ? null : Colors.white, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.08), - blurRadius: 8, - offset: const Offset(0, 2), - ), - ], - image: !isPrimary - ? DecorationImage( - image: AssetImage(bgImg), - fit: BoxFit.cover, - colorFilter: ColorFilter.mode( - Colors.white.withOpacity(0.8), - BlendMode.srcATop, - ), - ) - : null, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Text( - name, - style: TextStyle( - fontSize: 14.sp, - color: isPrimary ? Colors.white : const Color(0xFF2C2C2C), - fontWeight: FontWeight.w600, - ), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - ), - if (value != null && value != '') - Semantics( - label: '待处理数量:$value', - child: Container( - width: 20.r, - height: 20.r, - alignment: Alignment.center, - decoration: BoxDecoration( - color: isPrimary ? Colors.white : const Color(0xFFFF6969), - borderRadius: BorderRadius.all(Radius.circular(10.r)), - ), - child: Text( - value, - style: TextStyle( - fontSize: 10.sp, - color: isPrimary ? const Color(0xFFFF6969) : Colors.white, - fontWeight: FontWeight.w600), - ), - ), - ) - ], - ), - const Spacer(), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - if (isPrimary) - Icon( - Icons.arrow_forward_ios, - size: 14.sp, - color: Colors.white, - ) - else - Image.asset( - 'assets/images/home_right_icon.png', - width: 16.r, - height: 16.r, - semanticLabel: '进入图标', - ), - ], - ), - ], - ), - ), - ), - ), - ); -} - -class EntranceModel extends Object { - String title; - String image; - String navigationUrl; - String? page; - - EntranceModel({required this.title, required this.image, required this.navigationUrl, this.page}); -} - -@swidget -Widget $termRow(BuildContext context, List items, int? data) { - var leng = items.length; - Widget childWidget; - switch (leng) { - case 1: - childWidget = Row(children: [Expanded(child: $TermItem(items[0], data!))]); - break; - case 2: - childWidget = Row(children: [ - Expanded(flex: 9, child: $TermItem(items[0], data!)), - // const Expanded(flex: 1, child: SizedBox()), - SizedBox(width: ScreenUtil().screenWidth / 30), - Expanded(flex: 9, child: $TermItem(items[1], data)), - ]); - break; - case 3: - double theHeight = ScreenUtil().screenWidth / 30 + 54.h * 2; - childWidget = Row( - children: [ - Expanded(child: $TermItem(items[0], data!, theHeight: theHeight)), - SizedBox(width: ScreenUtil().screenWidth / 30), - Expanded( - child: SizedBox( - height: theHeight, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - $TermItem(items[1], data), - $TermItem(items[2], data), - ], - ), - ), - ), - ], - ); - break; - default: - childWidget = Container(); - } - - return Container(padding: EdgeInsets.symmetric(horizontal: 14.w), child: childWidget); -} - -@swidget -Widget $termItem(BuildContext context, EntranceModel e, int data, {double? theHeight}) { - bool isJob = e.title == '作业批阅'; - - return Material( - color: Colors.white, - elevation: 3.r, - shadowColor: const Color.fromRGBO(231, 231, 231, 1), - borderRadius: BorderRadius.all(Radius.circular(8.r)), - child: InkWell( - onTap: () { - Get.toNamed(e.navigationUrl, arguments: {'page': e.page ?? ''}); - }, - - // splashColor: splashColor, - borderRadius: BorderRadius.all(Radius.circular(8.r)), - child: badges.Badge( - showBadge: isJob && data > 0, - ignorePointer: false, - badgeContent: quickText(data, color: Colors.white, size: 10.sp), - badgeAnimation: const badges.BadgeAnimation.rotation( - animationDuration: Duration(seconds: 1), - colorChangeAnimationDuration: Duration(seconds: 1), - loopAnimation: false, - curve: Curves.fastOutSlowIn, - colorChangeAnimationCurve: Curves.easeInCubic, - ), - badgeStyle: badges.BadgeStyle( - badgeColor: const Color.fromRGBO(255, 105, 105, 1), - shape: badges.BadgeShape.square, - borderRadius: BorderRadius.only( - topLeft: Radius.circular(10.r), topRight: Radius.circular(8.5.r), bottomRight: Radius.circular(8.5.r)), - // borderSide: BorderSide(color: Colors.white, width: 2), - elevation: 1, - padding: EdgeInsets.symmetric(horizontal: Utils.isPad() ? 11.w : 16.w, vertical: 2.h), - ), - position: badges.BadgePosition.topEnd(top: 10.r, end: 10.r), - child: Container( - height: theHeight, - padding: EdgeInsets.symmetric(vertical: 12.h), - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(8.r)), - // boxShadow: [ - // BoxShadow( - // color: const Color.fromRGBO(231, 231, 231, 1), - // offset: Offset(4.w, 6.h), //阴影y轴偏移量 - // blurRadius: 8, //阴影模糊程度 - // spreadRadius: 0.2, //阴影扩散程度 - // ) - // ], - // border: Border.all(width: 0.5.w, color: Color.fromARGB(255, 219, 226, 250)), - ), - alignment: Alignment.center, - child: isJob - ? Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover), - SizedBox(height: 6.r), - quickText(e.title, - size: 12.sp, color: const Color.fromRGBO(79, 79, 79, 1), fontWeight: FontWeight.w500), - ], - ) - : Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover), - SizedBox(width: 6.r), - quickText(e.title, - size: 12.sp, color: const Color.fromRGBO(79, 79, 79, 1), fontWeight: FontWeight.w500), - ], - ), - ), - )), - ); -} diff --git a/making_school_asignment_app/lib/page/login_page/children/agreement_desktop.dart b/making_school_asignment_app/lib/page/login_page/children/agreement_desktop.dart new file mode 100644 index 0000000..2c80c8a --- /dev/null +++ b/making_school_asignment_app/lib/page/login_page/children/agreement_desktop.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/const_text.dart'; + +class AgreementDesktopPage extends StatelessWidget { + const AgreementDesktopPage({super.key}); + + @override + Widget build(BuildContext context) { + AGREEMENT_KEY type = AGREEMENT_KEY.values.byName(Get.arguments['type']); + AgreementClass agreement = AGREEMENT_MAP[type]!; + return Scaffold( + backgroundColor: const Color(0xFFF0F2F5), + body: Center( + child: Container( + width: 800.w, + height: 600.h, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.r), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 20, + offset: const Offset(0, 10), + ), + ], + ), + child: Column( + children: [ + AppBar( + title: Text(agreement.title), + centerTitle: true, + automaticallyImplyLeading: false, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.vertical( + top: Radius.circular(8.r), + ), + ), + ), + Expanded( + child: SingleChildScrollView( + padding: EdgeInsets.all(24.r), + child: HtmlWidget(agreement.richText), + ), + ), + Padding( + padding: EdgeInsets.all(16.r), + child: ElevatedButton( + onPressed: () => Get.back(), + style: ElevatedButton.styleFrom( + minimumSize: Size(120.w, 50.h), + ), + child: const Text('关闭'), + ), + ) + ], + ), + ), + ), + ); + } +} diff --git a/making_school_asignment_app/lib/page/login_page/children/agreement_mobile.dart b/making_school_asignment_app/lib/page/login_page/children/agreement_mobile.dart new file mode 100644 index 0000000..20b8d18 --- /dev/null +++ b/making_school_asignment_app/lib/page/login_page/children/agreement_mobile.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/const_text.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; + +// 协议富文本 +class AgreementMobilePage extends StatelessWidget { + const AgreementMobilePage({super.key}); + + @override + Widget build(BuildContext context) { + AGREEMENT_KEY type = AGREEMENT_KEY.values.byName(Get.arguments['type']); + AgreementClass agreement = AGREEMENT_MAP[type]!; + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).primaryColor, + title: quickText(agreement.title, color: Colors.white), + ), + body: ListView( + padding: EdgeInsets.symmetric(horizontal: 14.w, vertical: 8.h), + children: [ + HtmlWidget(agreement.richText, textStyle: const TextStyle(color: Colors.black)), + ], + ), + ); + } +} diff --git a/making_school_asignment_app/lib/page/login_page/children/agreement_page.dart b/making_school_asignment_app/lib/page/login_page/children/agreement_page.dart index a741b6f..ace462f 100644 --- a/making_school_asignment_app/lib/page/login_page/children/agreement_page.dart +++ b/making_school_asignment_app/lib/page/login_page/children/agreement_page.dart @@ -1,29 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; -import 'package:get/get.dart'; -import 'package:making_school_asignment_app/common/const_text.dart'; -import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/common/utils/platform_utils.dart'; +import 'package:making_school_asignment_app/page/login_page/children/agreement_desktop.dart'; +import 'package:making_school_asignment_app/page/login_page/children/agreement_mobile.dart'; -// 协议富文本 class AgreementPage extends StatelessWidget { const AgreementPage({super.key}); @override Widget build(BuildContext context) { - AGREEMENT_KEY type = AGREEMENT_KEY.values.byName(Get.arguments['type']); - AgreementClass agreement = AGREEMENT_MAP[type]!; - return Scaffold( - appBar: AppBar( - backgroundColor: Theme.of(context).primaryColor, - title: quickText(agreement.title, color: Colors.white), - ), - body: ListView( - padding: EdgeInsets.symmetric(horizontal: 14.w, vertical: 8.h), - children: [ - HtmlWidget(agreement.richText, textStyle: const TextStyle(color: Colors.black)), - ], - ), - ); + return PlatformUtils.isDesktop ? const AgreementDesktopPage() : const AgreementMobilePage(); } } diff --git a/making_school_asignment_app/lib/page/login_page/children/register.dart b/making_school_asignment_app/lib/page/login_page/children/register.dart index d2fe094..9bb2cca 100644 --- a/making_school_asignment_app/lib/page/login_page/children/register.dart +++ b/making_school_asignment_app/lib/page/login_page/children/register.dart @@ -1,291 +1,13 @@ -import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_easyloading/flutter_easyloading.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:making_school_asignment_app/common/const_text.dart'; -import 'package:making_school_asignment_app/common/job/user_register_params.dart'; -import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; -import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; -import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; -import 'package:making_school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/common/utils/platform_utils.dart'; +import 'package:making_school_asignment_app/page/login_page/children/register_desktop.dart'; +import 'package:making_school_asignment_app/page/login_page/children/register_mobile.dart'; -/// 注册页面 -class Register extends StatefulWidget { +class Register extends StatelessWidget { const Register({super.key}); - @override - State createState() => _RegisterState(); -} - -class _RegisterState extends State with RequestToolMixin { - late final FocusNode _theFocus; - late final FocusNode _pwdFocus; // 密码 - //文本输入框控制器 - late final TextEditingController _userNameController; - late final TextEditingController _passwordController; - - bool readAgreement = false; // 阅读协议 - bool _isShowPwd = true; - bool canLogin = true; - - @override - void initState() { - super.initState(); - _userNameController = TextEditingController(); - _passwordController = TextEditingController(); - _pwdFocus = FocusNode(); - _theFocus = FocusNode(); - } - - @override - void dispose() { - super.dispose(); - _userNameController.dispose(); - _passwordController.dispose(); - _pwdFocus.dispose(); - _theFocus.dispose(); - } - - void toRegister() async { - if (!canLogin) return; - setState(() => canLogin = false); - void toMsg(msg) { - Future.delayed(Duration.zero, () => ToastUtils.showError(msg)); - setState(() => canLogin = true); - } - - FocusScope.of(context).requestFocus(_theFocus); - try { - String userName = _userNameController.text.trim(); - String userPwd = _passwordController.text.trim(); - if (userName == '') return toMsg('请填写用户账号'); - if (userPwd == '') return toMsg('请填写密码'); - if (userPwd.length < 6) return toMsg('密码长度不得少于6位'); - if (!readAgreement) return toMsg('请勾选我已阅读用户协议和隐私协议'); - EasyLoading.show(status: 'loading...'); - var resultData = await getClient().toRegister(UserRegisterParams(account: userName, password: userPwd)); - print(resultData); - // if (resultData.success) return toMsg(resultData.message ?? '注册失败,请重试'); - ToastUtils.showSuccess('注册成功,请登录'); - // 跳转登录页 - Future.delayed(Duration.zero, () => Get.back()); - } catch (e) { - setState(() => canLogin = true); - } finally { - EasyLoading.dismiss(); - } - } - - void _showPassword() { - setState(() { - _isShowPwd = !_isShowPwd; - }); - } - @override Widget build(BuildContext context) { - return GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () { - FocusScope.of(context).requestFocus(_theFocus); - }, - child: AnnotatedRegion( - value: const SystemUiOverlayStyle( - statusBarColor: Colors.transparent, - systemNavigationBarIconBrightness: Brightness.light, - statusBarIconBrightness: Brightness.light, - statusBarBrightness: Brightness.dark, - ), - child: Scaffold( - backgroundColor: Colors.transparent, - resizeToAvoidBottomInset: false, - body: Stack( - children: [ - Container( - width: double.infinity, - height: double.infinity, - alignment: Alignment.center, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/images/register_bg.png'), - fit: BoxFit.fill, // 完全填充 - ), - ), - child: SingleChildScrollView( - child: Column( - children: [ - Container( - width: 86.w, - height: 86.w, - alignment: Alignment.center, - child: SizedBox( - height: 86.w, - width: 86.w, - child: Image.asset('assets/images/login_logo_icon.png', fit: BoxFit.cover), - ), - ), - Container( - margin: EdgeInsets.symmetric(horizontal: 32.w, vertical: 24.h), - padding: EdgeInsets.only(top: 34.h, bottom: 16.h, left: 22.w, right: 22.w), - decoration: BoxDecoration( - color: Colors.white, - border: Border.all(width: 1.w, color: Colors.white), - borderRadius: BorderRadius.all(Radius.circular(10.w)), - boxShadow: const [ - BoxShadow( - color: Color.fromRGBO(46, 91, 255, 0.1), - offset: Offset.zero, //阴影y轴偏移量 - blurRadius: 100, //阴影模糊程度 - spreadRadius: 100, //阴影扩散程度 - ) - ], - ), - child: Column(children: [ - TextField( - controller: _userNameController, - maxLines: 1, - maxLength: 20, - textInputAction: TextInputAction.next, - onEditingComplete: () { - FocusScope.of(context).requestFocus(_pwdFocus); - }, - style: TextStyle( - color: const Color.fromRGBO(80, 87, 103, 1), - fontSize: 15.sp, - ), - decoration: InputDecoration( - hintText: "请输入账号", - hintStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(153, 153, 153, 1)), - labelText: "账号", - labelStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)), - ), - ), - TextField( - focusNode: _pwdFocus, - controller: _passwordController, - keyboardType: TextInputType.number, - maxLines: 1, - obscureText: _isShowPwd, //隐藏密码显示 - textInputAction: TextInputAction.go, - onSubmitted: (_) => toRegister(), - style: TextStyle( - color: const Color.fromRGBO(80, 87, 103, 1), - fontSize: 15.sp, - ), - decoration: InputDecoration( - hintText: "请输入密码", - suffix: GestureDetector( - onTap: _showPassword, - child: Icon( - Icons.remove_red_eye, - color: !_isShowPwd ? Theme.of(context).primaryColor : Colors.grey, - ), - ), - hintStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(153, 153, 153, 1)), - labelText: "密码", - isDense: true, - labelStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)), - ), - ), - SizedBox( - height: 12.h, - ), - InkWell( - onTap: toRegister, - child: Container( - margin: EdgeInsets.symmetric(vertical: 10.h), - decoration: BoxDecoration( - color: canLogin ? Theme.of(context).primaryColor : Colors.grey, - boxShadow: [ - BoxShadow( - color: const Color.fromRGBO(76, 199, 147, 0.5), - offset: Offset(4.w, 6.h), //阴影y轴偏移量 - blurRadius: 10, //阴影模糊程度 - spreadRadius: 0.5, //阴影扩散程度 - ) - ], - borderRadius: BorderRadius.all( - Radius.circular(8.w), - ), - ), - alignment: Alignment.center, - width: double.infinity, - height: 50.h, - child: Text( - '注 册', - style: TextStyle(fontSize: 16.sp, color: Colors.white), - ), - ), - ), - Row( - children: [ - Container( - width: 30.w, - padding: EdgeInsets.only(right: 10.w), - child: Checkbox( - activeColor: Colors.deepOrangeAccent, - checkColor: Colors.white, - value: readAgreement, - onChanged: (value) { - FocusScope.of(context).requestFocus(_pwdFocus); - FocusScope.of(context).requestFocus(_theFocus); - setState(() { - readAgreement = value ?? false; - }); - }, - ), - ), - InkWell( - onTap: () { - // RouterManager.router.navigateTo( - // context, - // '${RouterManager.agreementPath}?type=${AGREEMENT_KEY.USER_AGREEMENT.name}', - // transition: getTransition(), - // ); - }, - child: quickText('我已阅读', size: 11.sp), - ), - InkWell( - onTap: () { - Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.USER_AGREEMENT.name}); - }, - child: quickText( - '《用户协议》', - size: 12.sp, - color: Theme.of(context).primaryColor, - ), - ), - InkWell( - onTap: () { - Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.PRIVACY_GREEMENT.name}); - }, - child: quickText( - '《隐私协议》', - size: 12.sp, - color:Theme.of(context).primaryColor, - ), - ), - ], - ), - ]), - ) - ], - ), - )), - Positioned( - top: MediaQuery.of(context).padding.top + 20.r, - left: 20.r, - child: InkWell( - onTap: () => Navigator.pop(context), - child: Icon(Icons.arrow_back_ios_new_rounded, color: Colors.white, size: 24.sp), - ), - ), - ], - ), - ), - ), - ); + return PlatformUtils.isDesktop ? const RegisterDesktop() : const RegisterMobile(); } } diff --git a/making_school_asignment_app/lib/page/login_page/children/register_desktop.dart b/making_school_asignment_app/lib/page/login_page/children/register_desktop.dart new file mode 100644 index 0000000..d3c9226 --- /dev/null +++ b/making_school_asignment_app/lib/page/login_page/children/register_desktop.dart @@ -0,0 +1,207 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/const_text.dart'; +import 'package:making_school_asignment_app/common/job/user_register_params.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +class RegisterDesktop extends StatefulWidget { + const RegisterDesktop({super.key}); + + @override + State createState() => _RegisterDesktopState(); +} + +class _RegisterDesktopState extends State with RequestToolMixin { + late final TextEditingController _userNameController; + late final TextEditingController _passwordController; + late final TextEditingController _confirmPasswordController; + + bool readAgreement = false; + bool _isShowPwd = true; + bool _isShowConfirmPwd = true; + bool canRegister = true; + + @override + void initState() { + super.initState(); + _userNameController = TextEditingController(); + _passwordController = TextEditingController(); + _confirmPasswordController = TextEditingController(); + } + + @override + void dispose() { + super.dispose(); + _userNameController.dispose(); + _passwordController.dispose(); + _confirmPasswordController.dispose(); + } + + void toRegister() async { + if (!canRegister) return; + setState(() => canRegister = false); + void toMsg(msg) { + Future.delayed(Duration.zero, () => ToastUtils.showError(msg)); + setState(() => canRegister = true); + } + + try { + String userName = _userNameController.text.trim(); + String userPwd = _passwordController.text.trim(); + String confirmPwd = _confirmPasswordController.text.trim(); + + if (userName.isEmpty) return toMsg('请填写用户账号'); + if (userPwd.isEmpty) return toMsg('请填写密码'); + if (userPwd.length < 6) return toMsg('密码长度不得少于6位'); + if (userPwd != confirmPwd) return toMsg('两次输入的密码不一致'); + if (!readAgreement) return toMsg('请勾选我已阅读用户协议和隐私协议'); + + EasyLoading.show(status: '注册中...'); + await getClient().toRegister(UserRegisterParams(account: userName, password: userPwd)); + ToastUtils.showSuccess('注册成功,请登录'); + Get.back(); + } catch (e) { + setState(() => canRegister = true); + } finally { + EasyLoading.dismiss(); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color(0xFFF0F2F5), + body: Center( + child: Container( + width: 400.w, + padding: EdgeInsets.all(32.r), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.r), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 20, + offset: const Offset(0, 10), + ), + ], + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + '创建您的账户', + style: TextStyle(fontSize: 24.sp, fontWeight: FontWeight.bold), + ), + SizedBox(height: 24.h), + _buildTextField(controller: _userNameController, hintText: "请输入账号", prefixIcon: Icons.person_outline), + SizedBox(height: 20.h), + _buildPasswordField( + controller: _passwordController, + hintText: "请输入密码", + prefixIcon: Icons.lock_outline, + obscureText: _isShowPwd, + onToggleVisibility: () => setState(() => _isShowPwd = !_isShowPwd), + ), + SizedBox(height: 20.h), + _buildPasswordField( + controller: _confirmPasswordController, + hintText: "请再次输入密码", + prefixIcon: Icons.lock_outline, + obscureText: _isShowConfirmPwd, + onToggleVisibility: () => setState(() => _isShowConfirmPwd = !_isShowConfirmPwd), + ), + SizedBox(height: 20.h), + InkWell( + onTap: toRegister, + child: Container( + decoration: BoxDecoration( + color: canRegister ? const Color(0xFF8C68FF) : const Color(0xFFdddddd), + borderRadius: BorderRadius.all(Radius.circular(8.r)), + ), + alignment: Alignment.center, + width: double.infinity, + height: 50.h, + child: quickText('注 册', size: 18.sp, color: Colors.white), + ), + ), + SizedBox(height: 20.h), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Checkbox( + value: readAgreement, + onChanged: (value) => setState(() => readAgreement = value ?? false), + ), + const Text('我已阅读并同意'), + InkWell( + onTap: () => + Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.USER_AGREEMENT.name}), + child: Text('《用户协议》', style: TextStyle(color: Theme.of(context).primaryColor)), + ), + const Text('和'), + InkWell( + onTap: () => + Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.PRIVACY_GREEMENT.name}), + child: Text('《隐私协议》', style: TextStyle(color: Theme.of(context).primaryColor)), + ), + ], + ), + SizedBox(height: 20.h), + InkWell( + onTap: () => Get.back(), + child: Text('已有账户?返回登录', style: TextStyle(color: Theme.of(context).primaryColor)), + ), + ], + ), + ), + ), + ); + } + + Widget _buildTextField( + {required TextEditingController controller, required String hintText, required IconData prefixIcon}) { + return TextField( + controller: controller, + decoration: InputDecoration( + hintText: hintText, + prefixIcon: Icon(prefixIcon), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.r), borderSide: const BorderSide(color: Colors.grey)), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.r), borderSide: BorderSide(color: Colors.grey.shade300)), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.r), borderSide: BorderSide(color: Theme.of(context).primaryColor)), + ), + ); + } + + Widget _buildPasswordField( + {required TextEditingController controller, + required String hintText, + required IconData prefixIcon, + required bool obscureText, + required VoidCallback onToggleVisibility}) { + return TextField( + controller: controller, + obscureText: obscureText, + decoration: InputDecoration( + hintText: hintText, + prefixIcon: Icon(prefixIcon), + suffixIcon: IconButton( + icon: Icon(obscureText ? Icons.visibility_off : Icons.visibility), onPressed: onToggleVisibility), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.r), borderSide: const BorderSide(color: Colors.grey)), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.r), borderSide: BorderSide(color: Colors.grey.shade300)), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.r), borderSide: BorderSide(color: Theme.of(context).primaryColor)), + ), + ); + } +} diff --git a/making_school_asignment_app/lib/page/login_page/children/register_mobile.dart b/making_school_asignment_app/lib/page/login_page/children/register_mobile.dart new file mode 100644 index 0000000..49bd004 --- /dev/null +++ b/making_school_asignment_app/lib/page/login_page/children/register_mobile.dart @@ -0,0 +1,292 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/const_text.dart'; +import 'package:making_school_asignment_app/common/job/user_register_params.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +/// 注册页面 +class RegisterMobile extends StatefulWidget { + const RegisterMobile({super.key}); + + @override + State createState() => _RegisterMobileState(); +} + +class _RegisterMobileState extends State with RequestToolMixin { + late final FocusNode _theFocus; + late final FocusNode _pwdFocus; // 密码 + //文本输入框控制器 + late final TextEditingController _userNameController; + late final TextEditingController _passwordController; + + bool readAgreement = false; // 阅读协议 + bool _isShowPwd = true; + bool canLogin = true; + + @override + void initState() { + super.initState(); + _userNameController = TextEditingController(); + _passwordController = TextEditingController(); + _pwdFocus = FocusNode(); + _theFocus = FocusNode(); + } + + @override + void dispose() { + super.dispose(); + _userNameController.dispose(); + _passwordController.dispose(); + _pwdFocus.dispose(); + _theFocus.dispose(); + } + + void toRegister() async { + if (!canLogin) return; + setState(() => canLogin = false); + void toMsg(msg) { + Future.delayed(Duration.zero, () => ToastUtils.showError(msg)); + setState(() => canLogin = true); + } + + FocusScope.of(context).requestFocus(_theFocus); + try { + String userName = _userNameController.text.trim(); + String userPwd = _passwordController.text.trim(); + if (userName == '') return toMsg('请填写用户账号'); + if (userPwd == '') return toMsg('请填写密码'); + if (userPwd.length < 6) return toMsg('密码长度不得少于6位'); + if (!readAgreement) return toMsg('请勾选我已阅读用户协议和隐私协议'); + EasyLoading.show(status: 'loading...'); + var resultData = await getClient().toRegister(UserRegisterParams(account: userName, password: userPwd)); + print(resultData); + // if (resultData.success) return toMsg(resultData.message ?? '注册失败,请重试'); + ToastUtils.showSuccess('注册成功,请登录'); + // 跳转登录页 + Future.delayed(Duration.zero, () => Get.back()); + } catch (e) { + setState(() => canLogin = true); + } finally { + EasyLoading.dismiss(); + } + } + + void _showPassword() { + setState(() { + _isShowPwd = !_isShowPwd; + }); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + FocusScope.of(context).requestFocus(_theFocus); + }, + child: AnnotatedRegion( + value: const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + systemNavigationBarIconBrightness: Brightness.light, + statusBarIconBrightness: Brightness.light, + statusBarBrightness: Brightness.dark, + ), + child: Scaffold( + backgroundColor: Colors.transparent, + resizeToAvoidBottomInset: false, + body: Stack( + children: [ + Container( + width: double.infinity, + height: double.infinity, + alignment: Alignment.center, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/register_bg.png'), + fit: BoxFit.fill, // 完全填充 + ), + ), + child: SingleChildScrollView( + child: Column( + children: [ + Container( + width: 86.w, + height: 86.w, + alignment: Alignment.center, + child: SizedBox( + height: 86.w, + width: 86.w, + child: Image.asset('assets/images/login_logo_icon.png', fit: BoxFit.cover), + ), + ), + Container( + margin: EdgeInsets.symmetric(horizontal: 32.w, vertical: 24.h), + padding: EdgeInsets.only(top: 34.h, bottom: 16.h, left: 22.w, right: 22.w), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 1.w, color: Colors.white), + borderRadius: BorderRadius.all(Radius.circular(10.w)), + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(46, 91, 255, 0.1), + offset: Offset.zero, //阴影y轴偏移量 + blurRadius: 100, //阴影模糊程度 + spreadRadius: 100, //阴影扩散程度 + ) + ], + ), + child: Column(children: [ + TextField( + controller: _userNameController, + maxLines: 1, + maxLength: 20, + textInputAction: TextInputAction.next, + onEditingComplete: () { + FocusScope.of(context).requestFocus(_pwdFocus); + }, + style: TextStyle( + color: const Color.fromRGBO(80, 87, 103, 1), + fontSize: 15.sp, + ), + decoration: InputDecoration( + hintText: "请输入账号", + hintStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(153, 153, 153, 1)), + labelText: "账号", + labelStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)), + ), + ), + TextField( + focusNode: _pwdFocus, + controller: _passwordController, + keyboardType: TextInputType.number, + maxLines: 1, + obscureText: _isShowPwd, //隐藏密码显示 + textInputAction: TextInputAction.go, + onSubmitted: (_) => toRegister(), + style: TextStyle( + color: const Color.fromRGBO(80, 87, 103, 1), + fontSize: 15.sp, + ), + decoration: InputDecoration( + hintText: "请输入密码", + suffix: GestureDetector( + onTap: _showPassword, + child: Icon( + Icons.remove_red_eye, + color: !_isShowPwd ? Theme.of(context).primaryColor : Colors.grey, + ), + ), + hintStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(153, 153, 153, 1)), + labelText: "密码", + isDense: true, + labelStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)), + ), + ), + SizedBox( + height: 12.h, + ), + InkWell( + onTap: toRegister, + child: Container( + margin: EdgeInsets.symmetric(vertical: 10.h), + decoration: BoxDecoration( + color: canLogin ? Theme.of(context).primaryColor : Colors.grey, + boxShadow: [ + BoxShadow( + color: const Color.fromRGBO(76, 199, 147, 0.5), + offset: Offset(4.w, 6.h), //阴影y轴偏移量 + blurRadius: 10, //阴影模糊程度 + spreadRadius: 0.5, //阴影扩散程度 + ) + ], + borderRadius: BorderRadius.all( + Radius.circular(8.w), + ), + ), + alignment: Alignment.center, + width: double.infinity, + height: 50.h, + child: Text( + '注 册', + style: TextStyle(fontSize: 16.sp, color: Colors.white), + ), + ), + ), + Row( + children: [ + Container( + width: 30.w, + padding: EdgeInsets.only(right: 10.w), + child: Checkbox( + activeColor: Colors.deepOrangeAccent, + checkColor: Colors.white, + value: readAgreement, + onChanged: (value) { + FocusScope.of(context).requestFocus(_pwdFocus); + FocusScope.of(context).requestFocus(_theFocus); + setState(() { + readAgreement = value ?? false; + }); + }, + ), + ), + InkWell( + onTap: () { + // RouterManager.router.navigateTo( + // context, + // '${RouterManager.agreementPath}?type=${AGREEMENT_KEY.USER_AGREEMENT.name}', + // transition: getTransition(), + // ); + }, + child: quickText('我已阅读', size: 11.sp), + ), + InkWell( + onTap: () { + Get.toNamed(Routes.agreementPage, + arguments: {"type": AGREEMENT_KEY.USER_AGREEMENT.name}); + }, + child: quickText( + '《用户协议》', + size: 12.sp, + color: Theme.of(context).primaryColor, + ), + ), + InkWell( + onTap: () { + Get.toNamed(Routes.agreementPage, + arguments: {"type": AGREEMENT_KEY.PRIVACY_GREEMENT.name}); + }, + child: quickText( + '《隐私协议》', + size: 12.sp, + color: Theme.of(context).primaryColor, + ), + ), + ], + ), + ]), + ) + ], + ), + )), + Positioned( + top: MediaQuery.of(context).padding.top + 20.r, + left: 20.r, + child: InkWell( + onTap: () => Navigator.pop(context), + child: Icon(Icons.arrow_back_ios_new_rounded, color: Colors.white, size: 24.sp), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/making_school_asignment_app/lib/page/login_page/login_desktop_view.dart b/making_school_asignment_app/lib/page/login_page/login_desktop_view.dart new file mode 100644 index 0000000..f3983c4 --- /dev/null +++ b/making_school_asignment_app/lib/page/login_page/login_desktop_view.dart @@ -0,0 +1,231 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/const_text.dart'; +import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart'; +import 'package:making_school_asignment_app/common/utils/app_upgrade/upgradeLogic.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'children/sys_protocol.dart'; +import 'login_logic.dart'; + +class LoginDesktopPage extends StatefulWidget { + const LoginDesktopPage({super.key}); + + @override + State createState() => _LoginDesktopPageState(); +} + +class _LoginDesktopPageState extends State { + final logic = Get.find(); + final upgradeLogic = Get.find(); + final state = Get.find().state; + + @override + void initState() { + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarIconBrightness: Brightness.dark, + statusBarColor: Colors.transparent, //状态栏背景颜色 + )); + + WidgetsBinding.instance.addPostFrameCallback((_) async { + await sysProtocol(context); + }); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + Utils.hideKeyboard(); + }, + child: Scaffold( + backgroundColor: const Color(0xFFF0F2F5), + body: Center( + child: Container( + width: 400.w, + padding: EdgeInsets.all(32.r), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.r), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 20, + offset: const Offset(0, 10), + ), + ], + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Image.asset('assets/images/login_logo_icon.png', height: 64.r), + SizedBox(height: 24.h), + Text( + '欢迎登录', + style: TextStyle(fontSize: 24.sp, fontWeight: FontWeight.bold), + ), + SizedBox(height: 24.h), + _buildTextField( + controller: state.userNameController, + hintText: "请输入账号", + prefixIcon: Icons.person_outline, + ), + SizedBox(height: 20.h), + Obx( + () => _buildPasswordField( + controller: state.passwordController, + hintText: "请输入密码", + prefixIcon: Icons.lock_outline, + obscureText: state.isShowPwd.value, + onToggleVisibility: () { + state.isShowPwd.value = !state.isShowPwd.value; + }, + ), + ), + SizedBox(height: 20.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Obx(() => Checkbox( + value: state.keepPwd.value, + onChanged: (value) { + state.keepPwd.value = value ?? false; + }, + )), + const Text('记住密码'), + ], + ), + InkWell( + onTap: () => Get.toNamed(Routes.register), + child: Text('账号注册', style: TextStyle(color: Theme.of(context).primaryColor)), + ) + ], + ), + SizedBox(height: 20.h), + InkWell( + onTap: () => easyThrottle('LOGIN_EASYTHROTTLE', () async { + Utils.hideKeyboard(); + await Future.delayed(Duration.zero); + WidgetsBinding.instance.addPostFrameCallback((_) => logic.toLogin(context, upgradeLogic)); + }), + child: Obx(() { + return Container( + decoration: BoxDecoration( + color: state.canLogin.value ? const Color(0xFF8C68FF) : const Color(0xFFdddddd), + borderRadius: BorderRadius.all( + Radius.circular(8.r), + ), + ), + alignment: Alignment.center, + width: double.infinity, + height: 50.h, + child: quickText('登 录', size: 18.sp, color: Colors.white)); + }), + ), + SizedBox(height: 20.h), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Obx(() => Checkbox( + value: state.readAgreement.value, + onChanged: (value) { + state.readAgreement.value = value ?? false; + }, + )), + const Text('我已阅读并同意'), + InkWell( + onTap: () { + Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.USER_AGREEMENT.name}); + }, + child: Text( + '《用户协议》', + style: TextStyle(color: Theme.of(context).primaryColor), + ), + ), + const Text('和'), + InkWell( + onTap: () { + Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.PRIVACY_GREEMENT.name}); + }, + child: Text( + '《隐私协议》', + style: TextStyle(color: Theme.of(context).primaryColor), + ), + ), + ], + ), + ], + ), + ), + ), + ), + ); + } + + Widget _buildTextField({ + required TextEditingController controller, + required String hintText, + required IconData prefixIcon, + }) { + return TextField( + controller: controller, + decoration: InputDecoration( + hintText: hintText, + prefixIcon: Icon(prefixIcon), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.r), + borderSide: const BorderSide(color: Colors.grey), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.r), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.r), + borderSide: BorderSide(color: Theme.of(context).primaryColor), + ), + ), + ); + } + + Widget _buildPasswordField({ + required TextEditingController controller, + required String hintText, + required IconData prefixIcon, + required bool obscureText, + required VoidCallback onToggleVisibility, + }) { + return TextField( + controller: controller, + obscureText: obscureText, + decoration: InputDecoration( + hintText: hintText, + prefixIcon: Icon(prefixIcon), + suffixIcon: IconButton( + icon: Icon(obscureText ? Icons.visibility_off : Icons.visibility), + onPressed: onToggleVisibility, + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.r), + borderSide: const BorderSide(color: Colors.grey), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.r), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.r), + borderSide: BorderSide(color: Theme.of(context).primaryColor), + ), + ), + ); + } +} diff --git a/making_school_asignment_app/lib/page/login_page/login_mobile_view.dart b/making_school_asignment_app/lib/page/login_page/login_mobile_view.dart new file mode 100644 index 0000000..5fc6f4b --- /dev/null +++ b/making_school_asignment_app/lib/page/login_page/login_mobile_view.dart @@ -0,0 +1,404 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/const_text.dart'; +import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart'; +import 'package:making_school_asignment_app/common/utils/app_upgrade/upgradeLogic.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'children/sys_protocol.dart'; +import 'login_logic.dart'; + +class LoginMobilePage extends StatefulWidget { + const LoginMobilePage({super.key}); + + @override + State createState() => _LoginMobilePageState(); +} + +class _LoginMobilePageState extends State { + final logic = Get.find(); + final upgradeLogic = Get.find(); + final state = Get.find().state; + + @override + void initState() { + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarIconBrightness: Brightness.light, + statusBarColor: Colors.transparent, //状态栏背景颜色 + )); + + WidgetsBinding.instance.addPostFrameCallback((_) async { + await sysProtocol(context); + + /// 为了发布各平台方便审核 不能再登陆页面直接弹出审核 + // await Future.delayed(Duration.zero, () => upgradeLogic.getAppUpgrade(context)); + }); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + Utils.hideKeyboard(); + // FocusScope.of(context).requestFocus(state.theFocus); + }, + child: AnnotatedRegion( + value: const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + systemNavigationBarIconBrightness: Brightness.light, + statusBarIconBrightness: Brightness.light, + statusBarBrightness: Brightness.dark, + ), + child: Scaffold( + backgroundColor: Colors.white, + resizeToAvoidBottomInset: false, + body: Stack( + children: [ + Positioned( + top: 0, + left: 0, + child: Image.asset( + 'assets/images/logo_banner.png', + width: Get.width, + fit: BoxFit.fill, + )), + SingleChildScrollView( + child: Column( + children: [ + SizedBox( + height: 130.r, + ), + Container( + width: 77.w, + height: 77.w, + alignment: Alignment.center, + child: SizedBox( + height: 77.w, + width: 77.w, + child: Image.asset('assets/images/login_logo_icon.png', fit: BoxFit.cover), + ), + ), + Container( + margin: EdgeInsets.only(top: 90.r), + padding: EdgeInsets.only(top: 50.h, bottom: 16.h, left: 40.w, right: 40.w), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: + BorderRadius.only(topLeft: Radius.circular(30.r), topRight: Radius.circular(30.r)), + /*boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(46, 91, 255, 0.1), + offset: Offset.zero, //阴影y轴偏移量 + blurRadius: 100, //阴影模糊程度 + spreadRadius: 100, //阴影扩散程度 + ) + ],*/ + ), + child: Column(children: [ + Container( + padding: EdgeInsets.symmetric( + horizontal: 15.w, + ), + decoration: BoxDecoration( + color: Colors.transparent, + border: Border.all(width: 1.w, color: const Color(0xFF434343)), + borderRadius: BorderRadius.all(Radius.circular(17.w)), + ), + child: TextField( + controller: state.userNameController, + /* maxLines: 1, + maxLength: 20,*/ + textInputAction: TextInputAction.next, + onEditingComplete: () { + Get.focusScope?.nextFocus(); + // FocusScope.of(context).requestFocus(_pwdFocus); + }, + style: TextStyle( + color: const Color(0xFF434343), + fontSize: 14.sp, + ), + decoration: InputDecoration( + hintText: "请输入账号", + hintStyle: TextStyle( + fontSize: 14.sp, + color: const Color(0xFF434343), + ), + // labelText: "账号", + labelStyle: TextStyle( + fontSize: 14.sp, + color: const Color(0xFF434343), + ), + border: InputBorder.none, + isDense: true, + prefixIconConstraints: BoxConstraints( + minHeight: 10.w, + minWidth: 10.h, + ), + prefixIcon: Padding( + padding: EdgeInsets.only(right: 5.r), + child: Image.asset( + 'assets/images/login_account.png', + width: 15.r, + height: 15.r, + ), + ), + ), + ), + ), + SizedBox( + height: 20.r, + ), + Obx(() { + return Container( + padding: EdgeInsets.symmetric(horizontal: 15.w), + decoration: BoxDecoration( + color: Colors.transparent, + border: Border.all(width: 1.w, color: const Color(0xFF434343)), + borderRadius: BorderRadius.all(Radius.circular(17.w)), + ), + child: TextField( + focusNode: state.pwdFocus, + controller: state.passwordController, + keyboardType: TextInputType.number, + maxLines: 1, + obscureText: state.isShowPwd.value, + //隐藏密码显示 + // textInputAction: state.isShowPwd.value?TextInputAction.go:TextInputAction.next, + textInputAction: TextInputAction.send, + onSubmitted: (_) => easyThrottle('LOGIN_EASYTHROTTLE', () async { + Utils.hideKeyboard(); + await Future.delayed(const Duration(milliseconds: 300)); + WidgetsBinding.instance + .addPostFrameCallback((_) => logic.toLogin(context, upgradeLogic)); + }), + style: TextStyle( + color: const Color(0xFF434343), + fontSize: 14.sp, + ), + decoration: InputDecoration( + hintText: "请输入密码", + prefixIconConstraints: BoxConstraints( + minHeight: 10.w, + minWidth: 10.h, + ), + prefixIcon: Padding( + padding: EdgeInsets.only(right: 5.r), + child: Image.asset( + 'assets/images/login_pwd.png', + width: 15.r, + height: 15.r, + ), + ), + suffixIconConstraints: BoxConstraints( + minHeight: 10.w, + minWidth: 10.h, + ), + suffixIcon: InkWell( + onTap: () { + state.isShowPwd.value = !state.isShowPwd.value; + }, + child: Padding( + padding: EdgeInsets.only(right: 5.r), + child: Image.asset( + state.isShowPwd.value + ? 'assets/images/eye_default.png' + : 'assets/images/eye_active.png', + width: 15.r, + height: 15.r, + ), + ), + ), + hintStyle: TextStyle( + fontSize: 14.sp, + color: const Color(0xFF434343), + ), + border: InputBorder.none, + // labelText: "密码", + isDense: true, + labelStyle: TextStyle( + fontSize: 14.sp, + color: Colors.white, + ), + ), + ), + ); + }), + SizedBox(height: 10.h), + Row( + children: [ + Expanded( + child: Row( + children: [ + Container( + width: 25.w, + padding: EdgeInsets.only(right: 0.w), + child: Obx(() { + return Transform.scale( + scale: 1.0, + child: Checkbox( + // activeColor: Colors.transparent, //去掉勾选时背景颜色 + + activeColor: Theme.of(context).primaryColor, + // checkColor: Colors.white, + value: state.keepPwd.value, + onChanged: (value) { + // Get.focusScope?.nextFocus(); + FocusScope.of(context).requestFocus(state.pwdFocus); + FocusScope.of(context).requestFocus(state.theFocus); + state.keepPwd.value = value ?? false; + }, + side: WidgetStateBorderSide.resolveWith( + (Set states) { + if (states.contains(WidgetState.selected)) { + //修改勾选时边框颜色为红色 + return BorderSide( + width: 1.5.r, color: Theme.of(context).primaryColor); + } + //修改默认时边框颜色为绿色 + return BorderSide(width: 1.r, color: const Color(0xFF434343)); + }, + )), + ); + }), + ), + InkWell( + onTap: () { + Utils.hideKeyboard(); + Get.focusScope?.nextFocus(); + Get.focusScope?.nextFocus(); + FocusScope.of(context).requestFocus(state.pwdFocus); + FocusScope.of(context).requestFocus(state.theFocus); + state.keepPwd.value = !state.keepPwd.value; + }, + child: Text( + '记住密码', + style: TextStyle( + fontSize: 12.sp, + color: const Color(0xFF434343), + ), + ), + ), + ], + ), + ), + InkWell( + onTap: () => Get.toNamed(Routes.register), + child: quickText('账号注册', color: const Color(0xFF434343)), + ) + ], + ), + InkWell( + onTap: () => easyThrottle('LOGIN_EASYTHROTTLE', () async { + Utils.hideKeyboard(); + await Future.delayed(Duration.zero); + WidgetsBinding.instance.addPostFrameCallback((_) => logic.toLogin(context, upgradeLogic)); + }), + child: Obx(() { + return Container( + margin: EdgeInsets.symmetric(vertical: 10.h), + decoration: BoxDecoration( + color: state.canLogin.value ? const Color(0xFF8C68FF) : const Color(0xFFdddddd), + /*boxShadow: [ + BoxShadow( + color: + const Color.fromRGBO(76, 199, 147, 0.5), + offset: Offset(6.w, 10.h), //阴影y轴偏移量 + blurRadius: 14, //阴影模糊程度 + spreadRadius: 0.5, //阴影扩散程度 + ) + ],*/ + borderRadius: BorderRadius.all( + Radius.circular(17.w), + ), + ), + alignment: Alignment.center, + width: double.infinity, + height: 50.h, + child: quickText('登 录', size: 18.sp, color: Colors.white)); + }), + ), + Row( + children: [ + Container( + width: 25.w, + padding: EdgeInsets.only(right: 0.w), + child: Obx(() { + return Transform.scale( + scale: 1.0, + child: Checkbox( + activeColor: Theme.of(context).primaryColor, + checkColor: Colors.white, + value: state.readAgreement.value, + onChanged: (value) { + Utils.hideKeyboard(); + /* FocusScope.of(context).requestFocus( + state.pwdFocus); + FocusScope.of(context).requestFocus( + state.theFocus);*/ + state.readAgreement.value = value ?? false; + }, + side: WidgetStateBorderSide.resolveWith( + (Set states) { + if (states.contains(WidgetState.selected)) { + //修改勾选时边框颜色为红色 + return BorderSide(width: 1.5.r, color: Theme.of(context).primaryColor); + } + //修改默认时边框颜色为绿色 + return BorderSide(width: 1.r, color: const Color(0xFF434343)); + }, + ), + ), + ); + }), + ), + InkWell( + onTap: () { + Get.toNamed(Routes.agreementPage, + arguments: {"type": AGREEMENT_KEY.USER_AGREEMENT.name}); + }, + child: quickText( + '请仔细阅读', + size: 11.sp, + ), + ), + InkWell( + onTap: () { + Get.toNamed(Routes.agreementPage, + arguments: {"type": AGREEMENT_KEY.USER_AGREEMENT.name}); + }, + child: Text( + '《用户协议》', + style: TextStyle(fontSize: 12.r, color: Theme.of(context).primaryColor), + ), + ), + InkWell( + onTap: () { + Get.toNamed(Routes.agreementPage, + arguments: {"type": AGREEMENT_KEY.PRIVACY_GREEMENT.name}); + }, + child: quickText( + '《隐私协议》', + size: 12.sp, + color: Theme.of(context).primaryColor, + ), + ), + ], + ), + ]), + ) + ], + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/making_school_asignment_app/lib/page/login_page/login_view.dart b/making_school_asignment_app/lib/page/login_page/login_view.dart index 964aa0a..08b3444 100644 --- a/making_school_asignment_app/lib/page/login_page/login_view.dart +++ b/making_school_asignment_app/lib/page/login_page/login_view.dart @@ -1,395 +1,13 @@ -import 'package:get/get.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:making_school_asignment_app/common/const_text.dart'; -import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart'; -import 'package:making_school_asignment_app/common/utils/app_upgrade/upgradeLogic.dart'; -import 'package:making_school_asignment_app/common/utils/utils.dart'; -import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; -import 'package:making_school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/common/utils/platform_utils.dart'; +import 'package:making_school_asignment_app/page/login_page/login_desktop_view.dart'; +import 'package:making_school_asignment_app/page/login_page/login_mobile_view.dart'; -import 'children/sys_protocol.dart'; -import 'login_logic.dart'; - -class LoginPage extends StatefulWidget { +class LoginPage extends StatelessWidget { const LoginPage({super.key}); - @override - State createState() => _LoginPageState(); -} - -class _LoginPageState extends State { - final logic = Get.find(); - final upgradeLogic = Get.find(); - final state = Get.find().state; - - @override - void initState() { - SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( - statusBarIconBrightness: Brightness.light, - statusBarColor: Colors.transparent, //状态栏背景颜色 - )); - - WidgetsBinding.instance.addPostFrameCallback((_) async { - await sysProtocol(context); - /// 为了发布各平台方便审核 不能再登陆页面直接弹出审核 - // await Future.delayed(Duration.zero, () => upgradeLogic.getAppUpgrade(context)); - }); - super.initState(); - } - @override Widget build(BuildContext context) { - return GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () { - Utils.hideKeyboard(); - // FocusScope.of(context).requestFocus(state.theFocus); - }, - child: AnnotatedRegion( - value: const SystemUiOverlayStyle( - statusBarColor: Colors.transparent, - systemNavigationBarIconBrightness: Brightness.light, - statusBarIconBrightness: Brightness.light, - statusBarBrightness: Brightness.dark, - ), - child: Scaffold( - backgroundColor: Colors.white, - resizeToAvoidBottomInset: false, - body: Stack( - children: [ - Positioned( - top: 0, - left: 0, - child: Image.asset( - 'assets/images/logo_banner.png', - width: Get.width, - fit: BoxFit.fill, - )), - SingleChildScrollView( - child: Column( - children: [ - SizedBox( - height: 130.r, - ), - Container( - width: 77.w, - height: 77.w, - alignment: Alignment.center, - child: SizedBox( - height: 77.w, - width: 77.w, - child: Image.asset('assets/images/login_logo_icon.png', fit: BoxFit.cover), - ), - ), - Container( - margin: EdgeInsets.only(top: 90.r), - padding: EdgeInsets.only(top: 50.h, bottom: 16.h, left: 40.w, right: 40.w), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only(topLeft: Radius.circular(30.r), topRight: Radius.circular(30.r)), - /*boxShadow: const [ - BoxShadow( - color: Color.fromRGBO(46, 91, 255, 0.1), - offset: Offset.zero, //阴影y轴偏移量 - blurRadius: 100, //阴影模糊程度 - spreadRadius: 100, //阴影扩散程度 - ) - ],*/ - ), - child: Column(children: [ - Container( - padding: EdgeInsets.symmetric( - horizontal: 15.w, - ), - decoration: BoxDecoration( - color: Colors.transparent, - border: Border.all(width: 1.w, color: const Color(0xFF434343)), - borderRadius: BorderRadius.all(Radius.circular(17.w)), - ), - child: TextField( - controller: state.userNameController, - /* maxLines: 1, - maxLength: 20,*/ - textInputAction: TextInputAction.next, - onEditingComplete: () { - Get.focusScope?.nextFocus(); - // FocusScope.of(context).requestFocus(_pwdFocus); - }, - style: TextStyle( - color: const Color(0xFF434343), - fontSize: 14.sp, - ), - decoration: InputDecoration( - hintText: "请输入账号", - hintStyle: TextStyle( - fontSize: 14.sp, - color: const Color(0xFF434343), - ), - // labelText: "账号", - labelStyle: TextStyle( - fontSize: 14.sp, - color: const Color(0xFF434343), - ), - border: InputBorder.none, - isDense: true, - prefixIconConstraints: BoxConstraints( - minHeight: 10.w, - minWidth: 10.h, - ), - prefixIcon: Padding( - padding: EdgeInsets.only(right: 5.r), - child: Image.asset( - 'assets/images/login_account.png', - width: 15.r, - height: 15.r, - ), - ), - ), - ), - ), - SizedBox( - height: 20.r, - ), - Obx(() { - return Container( - padding: EdgeInsets.symmetric(horizontal: 15.w), - decoration: BoxDecoration( - color: Colors.transparent, - border: Border.all(width: 1.w, color: const Color(0xFF434343)), - borderRadius: BorderRadius.all(Radius.circular(17.w)), - ), - child: TextField( - focusNode: state.pwdFocus, - controller: state.passwordController, - keyboardType: TextInputType.number, - maxLines: 1, - obscureText: state.isShowPwd.value, - //隐藏密码显示 - // textInputAction: state.isShowPwd.value?TextInputAction.go:TextInputAction.next, - textInputAction: TextInputAction.send, - onSubmitted: (_) => easyThrottle('LOGIN_EASYTHROTTLE', () async{ - Utils.hideKeyboard(); - await Future.delayed(const Duration(milliseconds: 300)); - WidgetsBinding.instance.addPostFrameCallback((_) => logic.toLogin(context,upgradeLogic)); - }), - style: TextStyle( - color: const Color(0xFF434343), - fontSize: 14.sp, - ), - decoration: InputDecoration( - hintText: "请输入密码", - prefixIconConstraints: BoxConstraints( - minHeight: 10.w, - minWidth: 10.h, - ), - prefixIcon: Padding( - padding: EdgeInsets.only(right: 5.r), - child: Image.asset( - 'assets/images/login_pwd.png', - width: 15.r, - height: 15.r, - ), - ), - suffixIconConstraints: BoxConstraints( - minHeight: 10.w, - minWidth: 10.h, - ), - suffixIcon: InkWell( - onTap: () { - state.isShowPwd.value = !state.isShowPwd.value; - }, - child: Padding( - padding: EdgeInsets.only(right: 5.r), - child: Image.asset( - state.isShowPwd.value ? 'assets/images/eye_default.png' : 'assets/images/eye_active.png', - width: 15.r, - height: 15.r, - ), - ), - ), - hintStyle: TextStyle( - fontSize: 14.sp, - color: const Color(0xFF434343), - ), - border: InputBorder.none, - // labelText: "密码", - isDense: true, - labelStyle: TextStyle( - fontSize: 14.sp, - color: Colors.white, - ), - ), - ), - ); - }), - SizedBox(height: 10.h), - Row( - children: [ - Expanded( - child: Row( - children: [ - Container( - width: 25.w, - padding: EdgeInsets.only(right: 0.w), - child: Obx(() { - return Transform.scale( - scale: 1.0, - child: Checkbox( - // activeColor: Colors.transparent, //去掉勾选时背景颜色 - - activeColor: Theme.of(context).primaryColor, - // checkColor: Colors.white, - value: state.keepPwd.value, - onChanged: (value) { - // Get.focusScope?.nextFocus(); - FocusScope.of(context).requestFocus(state.pwdFocus); - FocusScope.of(context).requestFocus(state.theFocus); - state.keepPwd.value = value ?? false; - }, - side: WidgetStateBorderSide.resolveWith( - (Set states) { - if (states.contains(WidgetState.selected)) { - //修改勾选时边框颜色为红色 - return BorderSide(width: 1.5.r, color: Theme.of(context).primaryColor); - } - //修改默认时边框颜色为绿色 - return BorderSide(width: 1.r, color: const Color(0xFF434343)); - }, - )), - ); - }), - ), - InkWell( - onTap: () { - Utils.hideKeyboard(); - Get.focusScope?.nextFocus(); - Get.focusScope?.nextFocus(); - FocusScope.of(context).requestFocus(state.pwdFocus); - FocusScope.of(context).requestFocus(state.theFocus); - state.keepPwd.value = !state.keepPwd.value; - }, - child: Text( - '记住密码', - style: TextStyle( - fontSize: 12.sp, - color: const Color(0xFF434343), - ), - ), - ), - ], - ), - ), - InkWell( - onTap: () => Get.toNamed(Routes.register), - child: quickText('账号注册', color: const Color(0xFF434343)), - ) - ], - ), - InkWell( - onTap: () => easyThrottle('LOGIN_EASYTHROTTLE', () async{ - Utils.hideKeyboard(); - await Future.delayed(Duration.zero); - WidgetsBinding.instance.addPostFrameCallback((_) => logic.toLogin(context,upgradeLogic)); - }), - child: Obx(() { - return Container( - margin: EdgeInsets.symmetric(vertical: 10.h), - decoration: BoxDecoration( - color: state.canLogin.value ? const Color(0xFF8C68FF) : const Color(0xFFdddddd), - /*boxShadow: [ - BoxShadow( - color: - const Color.fromRGBO(76, 199, 147, 0.5), - offset: Offset(6.w, 10.h), //阴影y轴偏移量 - blurRadius: 14, //阴影模糊程度 - spreadRadius: 0.5, //阴影扩散程度 - ) - ],*/ - borderRadius: BorderRadius.all( - Radius.circular(17.w), - ), - ), - alignment: Alignment.center, - width: double.infinity, - height: 50.h, - child: quickText('登 录', size: 18.sp, color: Colors.white)); - }), - ), - Row( - children: [ - Container( - width: 25.w, - padding: EdgeInsets.only(right: 0.w), - child: Obx(() { - return Transform.scale( - scale: 1.0, - child: Checkbox( - activeColor: Theme.of(context).primaryColor, - checkColor: Colors.white, - value: state.readAgreement.value, - onChanged: (value) { - Utils.hideKeyboard(); - /* FocusScope.of(context).requestFocus( - state.pwdFocus); - FocusScope.of(context).requestFocus( - state.theFocus);*/ - state.readAgreement.value = value ?? false; - }, - side: WidgetStateBorderSide.resolveWith( - (Set states) { - if (states.contains(WidgetState.selected)) { - //修改勾选时边框颜色为红色 - return BorderSide(width: 1.5.r, color: Theme.of(context).primaryColor); - } - //修改默认时边框颜色为绿色 - return BorderSide(width: 1.r, color: const Color(0xFF434343)); - }, - ), - ), - ); - }), - ), - InkWell( - onTap: () { - Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.USER_AGREEMENT.name}); - }, - child: quickText( - '请仔细阅读', - size: 11.sp, - ), - ), - InkWell( - onTap: () { - Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.USER_AGREEMENT.name}); - }, - child: Text( - '《用户协议》', - style: TextStyle(fontSize: 12.r, color: Theme.of(context).primaryColor), - ), - ), - InkWell( - onTap: () { - Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.PRIVACY_GREEMENT.name}); - }, - child: quickText( - '《隐私协议》', - size: 12.sp, - color: Theme.of(context).primaryColor, - ), - ), - ], - ), - ]), - ) - ], - ), - ), - ], - ), - ), - ), - ); + return PlatformUtils.isDesktop ? const LoginDesktopPage() : const LoginMobilePage(); } } diff --git a/making_school_asignment_app/lib/page/work_page/work_desktop_view.dart b/making_school_asignment_app/lib/page/work_page/work_desktop_view.dart new file mode 100644 index 0000000..cf626db --- /dev/null +++ b/making_school_asignment_app/lib/page/work_page/work_desktop_view.dart @@ -0,0 +1,118 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/mixins/getx_keepalive_widget.dart'; +import 'package:making_school_asignment_app/page/home_page/children/read_over/widget/annotate_list.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'work_logic.dart'; + +class WorkDesktopPage extends GetxKeepAliveWidget { + const WorkDesktopPage({super.key}); + + @override + Widget buildContent(BuildContext context, WorkLogic controller) { + final state = controller.state; + return Scaffold( + backgroundColor: const Color(0xFFF0F2F5), + body: Column( + children: [ + _buildHeader(context, controller, state), + Expanded( + child: Container( + padding: EdgeInsets.all(24.r), + child: Card( + elevation: 2, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)), + child: Column( + children: [ + _buildTabBar(context, controller, state), + Expanded( + child: Obx(() { + return AnnotateList( + tabIndex: state.tabIndex.value, + assessType: 1, + ); + }), + ), + ], + ), + ), + ), + ), + ], + ), + ); + } + + Widget _buildHeader(BuildContext context, WorkLogic controller, dynamic state) { + return Container( + padding: EdgeInsets.all(24.r), + color: Colors.white, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '作业批阅', + style: TextStyle(fontSize: 24.sp, fontWeight: FontWeight.bold, color: const Color(0xFF333333)), + ), + IconButton( + onPressed: () { + Get.toNamed(Routes.studentHistoryWorkPage, arguments: {'page': 'set'}); + }, + icon: Icon(Icons.settings, size: 24.sp, color: Colors.grey[600]), + tooltip: '设置', + ), + ], + ), + ); + } + + Widget _buildTabBar(BuildContext context, WorkLogic controller, dynamic state) { + return Container( + padding: EdgeInsets.all(16.r), + child: Row( + children: [ + Expanded( + child: Container( + height: 48.h, + decoration: BoxDecoration( + color: Colors.grey[100], + borderRadius: BorderRadius.circular(8.r), + ), + child: TabBar( + controller: controller.tabController, + indicator: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(6.r), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + indicatorPadding: EdgeInsets.all(4.r), + labelColor: Theme.of(context).primaryColor, + unselectedLabelColor: Colors.grey[600], + labelStyle: TextStyle(fontSize: 14.sp, fontWeight: FontWeight.w600), + unselectedLabelStyle: TextStyle(fontSize: 14.sp), + onTap: (index) { + state.tabIndex.value = index; + if (index == 1 && state.completedToRefresh) { + state.completedToRefresh = false; + } + }, + tabs: const [ + Tab(text: '待批阅'), + Tab(text: '已批阅'), + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/making_school_asignment_app/lib/page/work_page/work_mobile_view.dart b/making_school_asignment_app/lib/page/work_page/work_mobile_view.dart new file mode 100644 index 0000000..8f5484f --- /dev/null +++ b/making_school_asignment_app/lib/page/work_page/work_mobile_view.dart @@ -0,0 +1,141 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/mixins/getx_keepalive_widget.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/page/home_page/children/read_over/widget/annotate_list.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'work_logic.dart'; + +class WorkMobilePage extends GetxKeepAliveWidget { + const WorkMobilePage({super.key}); + + @override + Widget buildContent(BuildContext context, WorkLogic controller) { + final state = controller.state; + return Scaffold( + backgroundColor: const Color.fromRGBO(244, 244, 244, 1), + body: Column( + children: [ + Container( + color: Colors.white, + margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top), + padding: EdgeInsets.only(bottom: 9.h, top: 4.h), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + flex: 1, + child: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.only(left: 10.w), + )), + Expanded( + flex: 4, + child: Container( + padding: EdgeInsets.symmetric(vertical: 2.h), + alignment: Alignment.center, + decoration: BoxDecoration( + color: const Color.fromRGBO(243, 243, 243, 1), + borderRadius: BorderRadius.circular(8.r), + ), + child: TabBar( + padding: EdgeInsets.zero, + indicatorPadding: EdgeInsets.zero, + indicatorWeight: 0, + labelPadding: EdgeInsets.symmetric(horizontal: 2.w), + controller: controller.tabController, + unselectedLabelStyle: TextStyle( + fontSize: 14.sp, + color: const Color.fromRGBO(69, 83, 100, 1), + ), + labelStyle: TextStyle( + fontSize: 14.sp, + color: const Color(0xFF4CC793), + ), + // labelColor: const Color.fromRGBO(45, 56, 76, 1), + indicator: const BoxDecoration(), + onTap: (index) { + state.tabIndex.value = index; + if (index == 1 && state.completedToRefresh) { + // 已阅卷 + // _refreshController2.callRefresh(); + state.completedToRefresh = false; + } + }, + tabs: [ + Tab( + iconMargin: EdgeInsets.zero, + height: 34.h, + child: Obx(() { + return Container( + width: 140.w, + alignment: Alignment.center, + decoration: BoxDecoration( + color: state.tabIndex.value == 0 ? const Color.fromRGBO(255, 255, 255, 1) : null, + borderRadius: BorderRadius.all(Radius.circular(8.r)), + ), + child: quickText( + '待批阅', + size: 14.sp, + color: state.tabIndex.value == 0 + ? Theme.of(context).primaryColor + : const Color.fromRGBO(80, 94, 110, 1), + fontWeight: state.tabIndex.value == 0 ? FontWeight.bold : null, + ), + ); + }), + ), + Tab( + iconMargin: EdgeInsets.zero, + height: 34.h, + child: Obx(() { + return Container( + width: 140.w, + alignment: Alignment.center, + decoration: BoxDecoration( + color: state.tabIndex.value == 1 ? const Color.fromRGBO(255, 255, 255, 1) : null, + borderRadius: BorderRadius.all(Radius.circular(8.r)), + ), + child: quickText( + '已批阅', + size: 14.sp, + color: state.tabIndex.value == 1 + ? Theme.of(context).primaryColor + : const Color.fromRGBO(80, 94, 110, 1), + fontWeight: state.tabIndex.value == 1 ? FontWeight.bold : null, + ), + ); + }), + ), + ], + ), + ), + ), + Expanded( + flex: 1, + child: InkWell( + onTap: () { + Get.toNamed(Routes.studentHistoryWorkPage, arguments: {'page': 'set'}); + }, + child: Icon(const IconData(0xe63e, fontFamily: "AlibabaIcon"), + color: const Color.fromRGBO(44, 48, 63, 1), size: 24.sp), + ), + ), + ], + ), + ), + Expanded( + child: Obx(() { + return AnnotateList( + tabIndex: state.tabIndex.value, + assessType: 1, + ); + }), + ), + ], + ), + ); + } +} diff --git a/making_school_asignment_app/lib/page/work_page/work_view.dart b/making_school_asignment_app/lib/page/work_page/work_view.dart index ea75602..73ec49c 100644 --- a/making_school_asignment_app/lib/page/work_page/work_view.dart +++ b/making_school_asignment_app/lib/page/work_page/work_view.dart @@ -1,141 +1,13 @@ import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:making_school_asignment_app/common/mixins/getx_keepalive_widget.dart'; -import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; -import 'package:making_school_asignment_app/page/home_page/children/read_over/widget/annotate_list.dart'; -import 'package:making_school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/common/utils/platform_utils.dart'; +import 'package:making_school_asignment_app/page/work_page/work_desktop_view.dart'; +import 'package:making_school_asignment_app/page/work_page/work_mobile_view.dart'; -import 'work_logic.dart'; - -class WorkPage extends GetxKeepAliveWidget { +class WorkPage extends StatelessWidget { const WorkPage({super.key}); @override - Widget buildContent(BuildContext context, WorkLogic controller) { - final state = controller.state; - return Scaffold( - backgroundColor: const Color.fromRGBO(244, 244, 244, 1), - body: Column( - children: [ - Container( - color: Colors.white, - margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top), - padding: EdgeInsets.only(bottom: 9.h, top: 4.h), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - flex: 1, - child: Container( - alignment: Alignment.centerLeft, - padding: EdgeInsets.only(left: 10.w), - )), - Expanded( - flex: 4, - child: Container( - padding: EdgeInsets.symmetric(vertical: 2.h), - alignment: Alignment.center, - decoration: BoxDecoration( - color: const Color.fromRGBO(243, 243, 243, 1), - borderRadius: BorderRadius.circular(8.r), - ), - child: TabBar( - padding: EdgeInsets.zero, - indicatorPadding: EdgeInsets.zero, - indicatorWeight: 0, - labelPadding: EdgeInsets.symmetric(horizontal: 2.w), - controller: controller.tabController, - unselectedLabelStyle: TextStyle( - fontSize: 14.sp, - color: const Color.fromRGBO(69, 83, 100, 1), - ), - labelStyle: TextStyle( - fontSize: 14.sp, - color: const Color(0xFF4CC793), - ), - // labelColor: const Color.fromRGBO(45, 56, 76, 1), - indicator: const BoxDecoration(), - onTap: (index) { - state.tabIndex.value = index; - if (index == 1 && state.completedToRefresh) { - // 已阅卷 - // _refreshController2.callRefresh(); - state.completedToRefresh = false; - } - }, - tabs: [ - Tab( - iconMargin: EdgeInsets.zero, - height: 34.h, - child: Obx(() { - return Container( - width: 140.w, - alignment: Alignment.center, - decoration: BoxDecoration( - color: state.tabIndex.value == 0 ? const Color.fromRGBO(255, 255, 255, 1) : null, - borderRadius: BorderRadius.all(Radius.circular(8.r)), - ), - child: quickText( - '待批阅', - size: 14.sp, - color: state.tabIndex.value == 0 - ? Theme.of(context).primaryColor - : const Color.fromRGBO(80, 94, 110, 1), - fontWeight: state.tabIndex.value == 0 ? FontWeight.bold : null, - ), - ); - }), - ), - Tab( - iconMargin: EdgeInsets.zero, - height: 34.h, - child: Obx(() { - return Container( - width: 140.w, - alignment: Alignment.center, - decoration: BoxDecoration( - color: state.tabIndex.value == 1 ? const Color.fromRGBO(255, 255, 255, 1) : null, - borderRadius: BorderRadius.all(Radius.circular(8.r)), - ), - child: quickText( - '已批阅', - size: 14.sp, - color: state.tabIndex.value == 1 - ? Theme.of(context).primaryColor - : const Color.fromRGBO(80, 94, 110, 1), - fontWeight: state.tabIndex.value == 1 ? FontWeight.bold : null, - ), - ); - }), - ), - ], - ), - ), - ), - Expanded( - flex: 1, - child: InkWell( - onTap: () { - Get.toNamed(Routes.studentHistoryWorkPage, arguments: {'page': 'set'}); - }, - child: Icon(const IconData(0xe63e, fontFamily: "AlibabaIcon"), - color: const Color.fromRGBO(44, 48, 63, 1), size: 24.sp), - ), - ), - ], - ), - ), - Expanded( - child: Obx(() { - return AnnotateList( - tabIndex: state.tabIndex.value, - assessType: 1, - ); - }), - ), - ], - ), - ); + Widget build(BuildContext context) { + return PlatformUtils.isDesktop ? const WorkDesktopPage() : const WorkMobilePage(); } }