diff --git a/lib/http/ApiService.dart b/lib/http/ApiService.dart index 494b83a..ff71459 100644 --- a/lib/http/ApiService.dart +++ b/lib/http/ApiService.dart @@ -9,11 +9,11 @@ class ApiService { static final bool isProduct = true; /// 登录及其他管理后台接口 - // static final String basePath = "http://192.168.198.8:30140"; - static final String basePath = - isProduct - ? "https://gbs-gateway.qhdsafety.com" - : "http://192.168.20.100:30140"; + static final String basePath = "https://skqhdg.porthebei.com:9007"; + // static final String basePath = + // isProduct + // ? "https://gbs-gateway.qhdsafety.com" + // : "http://192.168.20.100:30140"; /// 图片文件服务 diff --git a/lib/http/modules/appmenu_api.dart b/lib/http/modules/appmenu_api.dart index 7528797..c73116c 100644 --- a/lib/http/modules/appmenu_api.dart +++ b/lib/http/modules/appmenu_api.dart @@ -4,13 +4,14 @@ import 'package:qhd_prevention/http/HttpManager.dart'; import 'package:qhd_prevention/services/SessionService.dart'; class AppMenuApi { - static Future> getAppMenu() async { + static Future> getAppMenu(Map data) async { return HttpManager().request( ApiService.basePath, '/appmenu/appMenu/appListTree', method: Method.get, data: { 'menuAttribution': 'QINGANG_RELATED_PARTIES', + ...data }, ); } diff --git a/lib/http/modules/auth_api.dart b/lib/http/modules/auth_api.dart index 9c79503..41442b0 100644 --- a/lib/http/modules/auth_api.dart +++ b/lib/http/modules/auth_api.dart @@ -70,8 +70,8 @@ class AuthApi { static Future> getUserData() { return HttpManager().request( ApiService.basePath, - // '/basicInfo/user/getInfo', - '/basicInfo/user/${SessionService.instance.accountId}', + '/basicInfo/user/getInfo', + // '/basicInfo/user/${SessionService.instance.accountId}', method: Method.get, data: {}, ); diff --git a/lib/pages/home/home_page.dart b/lib/pages/home/home_page.dart index c43b26f..772d0bc 100644 --- a/lib/pages/home/home_page.dart +++ b/lib/pages/home/home_page.dart @@ -126,6 +126,7 @@ class HomePageState extends RouteAwareState "todoStats": "dashboard-todo-sort", "checklist": "dashboard-todo-list", "scan": "dashboard-scan", + "joinFirm": "dashboard-start-work", }; @override @@ -419,7 +420,7 @@ class HomePageState extends RouteAwareState final routeService = RouteService(); final bool showScan = routeService.hasPerm(_modulePerms['scan']!); - final bool showJoin = true; // 加入企业图标始终显示(或根据业务决定) + final bool showJoin = routeService.hasPerm(_modulePerms['joinFirm']!); final List children = []; if (showScan) { diff --git a/lib/pages/main_tab.dart b/lib/pages/main_tab.dart index 7f74e79..5aa9d82 100644 --- a/lib/pages/main_tab.dart +++ b/lib/pages/main_tab.dart @@ -4,19 +4,24 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart' show rootBundle; import 'package:qhd_prevention/common/route_service.dart'; +import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart'; import 'package:qhd_prevention/http/modules/appmenu_api.dart'; import 'package:qhd_prevention/pages/badge_manager.dart'; import 'package:qhd_prevention/pages/home/home_page.dart'; import 'package:qhd_prevention/pages/my_appbar.dart'; import 'package:qhd_prevention/pages/notif/notif_page.dart'; +import 'package:qhd_prevention/pages/user/login_page.dart'; +import 'package:qhd_prevention/services/SessionService.dart'; import 'package:qhd_prevention/services/heartbeat_service.dart'; import 'package:qhd_prevention/tools/tools.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'mine/mine_page.dart'; /// 用于向子树公布当前 tab 索引 class CurrentTabNotifier extends InheritedWidget { final int currentIndex; + const CurrentTabNotifier({ required this.currentIndex, required Widget child, @@ -68,7 +73,6 @@ class _MainPageState extends State with WidgetsBindingObserver { _badgeManager.initAllModules(); } - // 初始化固定页面(顺序固定) — **这里保持你要求的构造不变** _pages = [ HomePage(key: _homeKey, isChooseFirm: widget.isChooseFirm), @@ -91,33 +95,28 @@ class _MainPageState extends State with WidgetsBindingObserver { try { Map? route; // 接口获取 - // try { - // LoadingDialogHelper.show(message: '加载中...'); - - // final res = await AppMenuApi.getAppMenu(); - // if (res != null && res['success'] == true && res['data'] is List) { - // route = res; - // } else { - // debugPrint('AppMenuApi.getAppMenu returned no data or failed; fallback to local assets.'); - // } - // } catch (e) { - // debugPrint('AppMenuApi.getAppMenu error: $e -> fallback to local assets.'); - // } - // 本地获取 try { - final routeString = await loadFromAssets(); - route = jsonDecode(routeString) as Map; + LoadingDialogHelper.show(message: '加载中...'); + final roleId = SessionService.instance.roleId; + final res = await AppMenuApi.getAppMenu({'roleId': roleId}); + LoadingDialogHelper.hide(); + if (res['success'] == true) { + route = res; + } else {} } catch (e) { - debugPrint('loadFromAssets error: $e'); - } - - if (route != null && route['data'] is List) { - final data = route['data'] as List; - RouteService().initializeRoutes(data); - // initializeRoutes 内部会 notifyListeners -> _onRoutesUpdated 被调用 - } else { - debugPrint('No valid route data to initialize RouteService.'); + debugPrint( + 'AppMenuApi.getAppMenu error: $e -> fallback to local assets.', + ); } + // 本地获取 + // try { + // final routeString = await loadFromAssets(); + // route = jsonDecode(routeString) as Map; + // } catch (e) { + // debugPrint('loadFromAssets error: $e'); + // } + final data = route?['data'] ?? []; + RouteService().initializeRoutes(data); } catch (e) { debugPrint('获取路由配置失败: $e'); } finally { @@ -145,6 +144,7 @@ class _MainPageState extends State with WidgetsBindingObserver { // 使用 mainTabs,如果为空(尚未有路由或后端返回空),保持当前 _tabVisibility(即不自动显示) final mainTabs = routeService.mainTabs; if (mainTabs.isEmpty) { + _showErrorDialog(); return; } @@ -157,10 +157,10 @@ class _MainPageState extends State with WidgetsBindingObserver { if (!homeVisible && perms == 'dashboard' && m.visible) { homeVisible = true; } - if (!notifVisible && perms == 'notice'&& m.visible) { + if (!notifVisible && perms == 'notice' && m.visible) { notifVisible = true; } - if (!mineVisible && perms == 'my-center'&& m.visible) { + if (!mineVisible && perms == 'my-center' && m.visible) { mineVisible = true; } if (homeVisible && notifVisible && mineVisible) break; @@ -168,7 +168,11 @@ class _MainPageState extends State with WidgetsBindingObserver { // 后端未匹配到就隐藏(不兜底) setState(() { - _tabVisibility = [homeVisible, widget.isChooseFirm ? notifVisible : false, mineVisible]; + _tabVisibility = [ + homeVisible, + widget.isChooseFirm ? notifVisible : false, + mineVisible, + ]; // 若当前激活的 tab 被隐藏,则切换到第一个可见 tab(若没有可见 tab,则保持当前索引为 0) if (!_isIndexVisible(_currentIndex)) { @@ -176,6 +180,31 @@ class _MainPageState extends State with WidgetsBindingObserver { _currentIndex = first; } }); + if (!homeVisible && !notifVisible && !mineVisible) { + _showErrorDialog(); + } + } + + Future _showErrorDialog() async { + final confirmed = await CustomAlertDialog.showConfirm( + context, + title: '温馨提示', + content: '暂无登录权限,请联系管理员授权!', + force: true, + ); + if (confirmed) { + // 清除用户登录状态 + final prefs = await SharedPreferences.getInstance(); + await prefs.remove('isLoggedIn'); + // 清理 SessionService 中的内容(如果你需要) + SessionService.instance.clear(); + // 跳转到登录页并清除所有历史路由 + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute(builder: (context) => LoginPage()), + (Route route) => false, // 移除所有历史路由 + ); + } } // 返回第一个可见 tab 的索引;如果没有可见项,返回给定的 fallback(默认0) @@ -292,33 +321,63 @@ class _MainPageState extends State with WidgetsBindingObserver { if (_tabVisibility[i]) { switch (i) { case 0: - visibleItems.add(BottomNavigationBarItem( - icon: Image.asset('assets/tabbar/basics.png', width: 24, height: 24), - activeIcon: Image.asset('assets/tabbar/basics_cur.png', width: 24, height: 24), - label: '首页', - )); + visibleItems.add( + BottomNavigationBarItem( + icon: Image.asset( + 'assets/tabbar/basics.png', + width: 24, + height: 24, + ), + activeIcon: Image.asset( + 'assets/tabbar/basics_cur.png', + width: 24, + height: 24, + ), + label: '首页', + ), + ); visiblePages.add(_pages[i]); break; case 1: - visibleItems.add(BottomNavigationBarItem( - icon: _buildIconWithBadge( - icon: Image.asset('assets/tabbar/works.png', width: 24, height: 24), - badgeCount: bm.notifCount, + visibleItems.add( + BottomNavigationBarItem( + icon: _buildIconWithBadge( + icon: Image.asset( + 'assets/tabbar/works.png', + width: 24, + height: 24, + ), + badgeCount: bm.notifCount, + ), + activeIcon: _buildIconWithBadge( + icon: Image.asset( + 'assets/tabbar/works_cur.png', + width: 24, + height: 24, + ), + badgeCount: bm.notifCount, + ), + label: '通知', ), - activeIcon: _buildIconWithBadge( - icon: Image.asset('assets/tabbar/works_cur.png', width: 24, height: 24), - badgeCount: bm.notifCount, - ), - label: '通知', - )); + ); visiblePages.add(_pages[i]); break; case 2: - visibleItems.add(BottomNavigationBarItem( - icon: Image.asset('assets/tabbar/my.png', width: 24, height: 24), - activeIcon: Image.asset('assets/tabbar/my_cur.png', width: 24, height: 24), - label: '我的', - )); + visibleItems.add( + BottomNavigationBarItem( + icon: Image.asset( + 'assets/tabbar/my.png', + width: 24, + height: 24, + ), + activeIcon: Image.asset( + 'assets/tabbar/my_cur.png', + width: 24, + height: 24, + ), + label: '我的', + ), + ); visiblePages.add(_pages[i]); break; } @@ -329,7 +388,10 @@ class _MainPageState extends State with WidgetsBindingObserver { final bool hasVisiblePages = visiblePages.isNotEmpty; // 将当前索引映射到可见Tab的索引(用于 IndexedStack/BottomNavigationBar) - final visibleCurrentIndex = _originalToVisibleIndex(_currentIndex, _tabVisibility); + final visibleCurrentIndex = _originalToVisibleIndex( + _currentIndex, + _tabVisibility, + ); // ---------- 关键:根据 visibleItems 个数选择底栏渲染方式 ---------- Widget? bottomBarWidget; @@ -341,7 +403,10 @@ class _MainPageState extends State with WidgetsBindingObserver { selectedItemColor: Colors.blue, unselectedItemColor: Colors.grey, onTap: (visibleIndex) { - final originalIndex = _visibleToOriginalIndex(visibleIndex, _tabVisibility); + final originalIndex = _visibleToOriginalIndex( + visibleIndex, + _tabVisibility, + ); setState(() => _currentIndex = originalIndex); }, items: visibleItems, @@ -349,11 +414,17 @@ class _MainPageState extends State with WidgetsBindingObserver { } else if (visibleItems.length == 1) { // 自定义单个 tab 底栏(避免 BottomNavigationBar 的断言) final single = visibleItems[0]; - final singleVisibleOriginalIndex = _visibleToOriginalIndex(0, _tabVisibility); + final singleVisibleOriginalIndex = _visibleToOriginalIndex( + 0, + _tabVisibility, + ); final isSelected = _currentIndex == singleVisibleOriginalIndex; // 取选中或未选中的 icon 小部件 - final Widget iconWidget = isSelected && single.activeIcon != null ? single.activeIcon! : single.icon; + final Widget iconWidget = + isSelected && single.activeIcon != null + ? single.activeIcon! + : single.icon; bottomBarWidget = Material( elevation: 8, @@ -400,12 +471,13 @@ class _MainPageState extends State with WidgetsBindingObserver { currentIndex: _currentIndex, child: Scaffold( appBar: null, - body: hasVisiblePages - ? IndexedStack( - index: visibleCurrentIndex, - children: visiblePages, - ) - : const SizedBox.shrink(), + body: + hasVisiblePages + ? IndexedStack( + index: visibleCurrentIndex, + children: visiblePages, + ) + : const SizedBox.shrink(), bottomNavigationBar: bottomBarWidget, ), ); @@ -415,4 +487,4 @@ class _MainPageState extends State with WidgetsBindingObserver { // 当角标数据变化时,只更新需要重建的部分 if (mounted) setState(() {}); } -} \ No newline at end of file +} diff --git a/lib/pages/mine/mine_page.dart b/lib/pages/mine/mine_page.dart index e4715ff..69348e4 100644 --- a/lib/pages/mine/mine_page.dart +++ b/lib/pages/mine/mine_page.dart @@ -26,6 +26,7 @@ import 'package:qhd_prevention/common/route_model.dart'; class MinePage extends StatefulWidget { const MinePage({super.key, required this.isChooseFirm}); + final bool isChooseFirm; @override @@ -63,7 +64,7 @@ class MinePageState extends State { 'title': '扫码入职', 'icon': 'assets/images/ico10.png', // 如果你希望扫码入职也受后端控制,可以保留下面 perm;否则置空 [] - 'perms': ['dashboard-scan'], + 'perms': ['my-center-Scan-Code-Onboarding'], 'action': 'scanOnboarding', }, { @@ -130,7 +131,9 @@ class MinePageState extends State { RouteService().addListener(_onRouteServiceUpdated); // 尝试立即应用(如果 route 已加载) - WidgetsBinding.instance.addPostFrameCallback((_) => _updateVisibilityFromRoute()); + WidgetsBinding.instance.addPostFrameCallback( + (_) => _updateVisibilityFromRoute(), + ); } @override @@ -189,20 +192,27 @@ class MinePageState extends State { } } - // 获取用户信息(保持原逻辑) + // 获取用户信息 Future _getUserInfo() async { - final res = await BasicInfoApi.getUserMessage( - '${SessionService.instance.accountId}', - ); - if (res['success'] == true) { - final data = res['data'] as Map; - SessionService.instance.updateFromApiResponse(data); - await SessionService.instance.saveToPrefs(); - setState(() { - name = SessionService.instance.userData?.name ?? "登录/注册"; - phone = SessionService.instance.userData?.phone ?? ""; - }); - } + setState(() { + name = SessionService.instance.userData?.name ?? "登录/注册"; + phone = SessionService.instance.userData?.phone ?? ""; + }); + // final accountId = + // SessionService.instance.accountId ?? + // SessionService.instance.userData?.id ?? + // SessionService.instance.userData?.accountId ?? + // ''; + // final res = await BasicInfoApi.getUserMessage(accountId); + // if (res['success'] == true) { + // final data = res['data'] as Map; + // SessionService.instance.updateFromApiResponse(data); + // await SessionService.instance.saveToPrefs(); + // setState(() { + // name = SessionService.instance.userData?.name ?? "登录/注册"; + // phone = SessionService.instance.userData?.phone ?? ""; + // }); + // } } Future _logout() async { @@ -228,19 +238,18 @@ class MinePageState extends State { ); if (result) { CustomAlertDialog.showInputWithCode( - context, - title: '手机号:${SessionService.instance.phone}', - onGetCode: () async { - LoadingDialogHelper.show(); - final res = await BasicInfoApi.sendRegisterSms({ - 'phone': phone, - }); - LoadingDialogHelper.dismiss(); - return true; - }, - onConfirm: (code) async { - _quit(code); - }); + context, + title: '手机号:${SessionService.instance.phone}', + onGetCode: () async { + LoadingDialogHelper.show(); + final res = await BasicInfoApi.sendRegisterSms({'phone': phone}); + LoadingDialogHelper.dismiss(); + return true; + }, + onConfirm: (code) async { + _quit(code); + }, + ); } } } else { @@ -252,10 +261,7 @@ class MinePageState extends State { // 离职 Future _quit(String code) async { LoadingDialogHelper.show(); - Map data = { - 'id': SessionService.instance.accountId, - 'phoneCode': code, - }; + Map data = {'id': SessionService.instance.accountId, 'phoneCode': code}; await BasicInfoApi.logout(data).then((res) async { LoadingDialogHelper.dismiss(); if (res['success'] == true) { @@ -343,28 +349,41 @@ class MinePageState extends State { void _onSettingTapAction(String action) async { switch (action) { case 'userinfo': - await pushPage(FullUserinfoPage(isEidt: false, isChooseFirm: true), context); + await pushPage( + FullUserinfoPage(isEidt: false, isChooseFirm: true), + context, + ); break; case 'changePwd': await pushPage(MineSetPwdPage('0'), context); break; case 'scanOnboarding': - final result = await pushPage(ScanPage(type: ScanType.Onboarding), context); + final result = await pushPage( + ScanPage(type: ScanType.Onboarding), + context, + ); if (result == null) return; pushPage(OnboardingFullPage(scanData: result), context); break; case 'face': - pushPage(const FaceRecognitionPage(studentId: '', data: {}, mode: FaceMode.setUpdata), context); + pushPage( + const FaceRecognitionPage( + studentId: '', + data: {}, + mode: FaceMode.setUpdata, + ), + context, + ); break; case 'certificate': pushPage(const CertificateListPage(), context); break; case 'version': - // 版本检查逻辑(占位) - ToastUtil.showNormal(context, '功能开发中...'); + // 版本检查逻辑(占位) + ToastUtil.showNormal(context, '功能开发中...'); break; case 'about': - // 关于我们(占位) + // 关于我们(占位) ToastUtil.showNormal(context, '功能开发中...'); break; @@ -392,12 +411,14 @@ class MinePageState extends State { // 只在 isChooseFirm 为 true 时显示 if (title == '切换账户' && !widget.isChooseFirm) continue; - children.add(_buildSettingItem( - title: title, - icon: item['icon'] as String, - value: false, - onChanged: (_) => _onSettingTapAction(item['action'] as String), - )); + children.add( + _buildSettingItem( + title: title, + icon: item['icon'] as String, + value: false, + onChanged: (_) => _onSettingTapAction(item['action'] as String), + ), + ); } return Container( @@ -414,21 +435,28 @@ class MinePageState extends State { ), ], ), - child: Column( - children: children, - ), + child: Column(children: children), ); } @override Widget build(BuildContext context) { + RouteModel? showLogot = RouteService().findRouteByPerm('my-center-Logout'); + bool showLogout = showLogot?.showFlag == 1; + final double headerHeight = 300.0; final double overlap = 100.0; return SizedBox( height: MediaQuery.of(context).size.height, child: Stack( children: [ - Positioned(top: 0, left: 0, right: 0, height: headerHeight, child: _buildHeaderSection()), + Positioned( + top: 0, + left: 0, + right: 0, + height: headerHeight, + child: _buildHeaderSection(), + ), Positioned.fill( child: NotificationListener( onNotification: (overscroll) { @@ -436,33 +464,41 @@ class MinePageState extends State { return false; }, child: ListView( - padding: EdgeInsets.only(top: headerHeight - overlap, bottom: 24, left: 0, right: 0), + padding: EdgeInsets.only( + top: headerHeight - overlap, + bottom: 24, + left: 0, + right: 0, + ), children: [ _buildSettingsList(), const SizedBox(height: 15), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 15), - child: CustomButton( - text: '退出登录', - textStyle: const TextStyle(fontSize: 16), - backgroundColor: Colors.blue, - onPressed: () { - CustomAlertDialog.showConfirm( - context, - title: '确认退出', - content: '确定要退出当前账号吗', - onConfirm: () async { - await _clearUserSession(); - Navigator.pushAndRemoveUntil( - context, - MaterialPageRoute(builder: (context) => const LoginPage()), - (Route route) => false, - ); - }, - ); - }, + if (showLogout) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 15), + child: CustomButton( + text: '退出登录', + textStyle: const TextStyle(fontSize: 16), + backgroundColor: Colors.blue, + onPressed: () { + CustomAlertDialog.showConfirm( + context, + title: '确认退出', + content: '确定要退出当前账号吗', + onConfirm: () async { + await _clearUserSession(); + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute( + builder: (context) => const LoginPage(), + ), + (Route route) => false, + ); + }, + ); + }, + ), ), - ), ], ), ), @@ -488,11 +524,15 @@ class MinePageState extends State { top: 51, child: Text( "我的", - style: TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold), + style: TextStyle( + color: Colors.white, + fontSize: 20, + fontWeight: FontWeight.bold, + ), ), ), _buildSloganSection(), ], ); } -} \ No newline at end of file +} diff --git a/lib/services/SessionService.dart b/lib/services/SessionService.dart index 7b3d10c..f1add70 100644 --- a/lib/services/SessionService.dart +++ b/lib/services/SessionService.dart @@ -395,6 +395,8 @@ class SessionService { // ---------- convenience setters ---------- void setToken(String t) => token = t; + // void setRoleId(String t) => roleId = t; + void setName(String t) => name = t; void setLoginPhone(String phone) => loginPhone = phone; @@ -408,6 +410,8 @@ class SessionService { print('姓名: ${userData!.name}'); print('部门: ${userData!.departmentName}'); print('租户ID: ${userData!.tenantId}'); + print('Account ID: ${userData!.id}'); + // printLongString(text) } } diff --git a/lib/services/auth_service.dart b/lib/services/auth_service.dart index 0464b40..2251193 100644 --- a/lib/services/auth_service.dart +++ b/lib/services/auth_service.dart @@ -50,6 +50,14 @@ class AuthService { }; return AuthService.gbsLogin(username, password, data); } else if (firmList.length > 1) { + // 多个企业 也没有缓存过登录的企业 + return { + 'isChooseFirm': false, + 'isInfoComplete': isInfoComplete, + 'firmList': firmList, + 'userName': username, + 'password': password, + }; // 如果入职多个 if (StorageService.instance.getString('key.saveJoinFirmInfo') != null) { // 有缓存的登录过的企业,并且这个企业在登录返回的企业列表中 @@ -124,14 +132,14 @@ class AuthService { final success = result['success'] as bool; if (!success) { Fluttertoast.showToast(msg: result['errMessage'] ?? ''); - return result; // return false; } - printLongString('token:${jsonEncode(result['data']['token'])}'); final data = result['data'] as Map; final token = data['token'] ?? ''; SessionService.instance.setToken(token); + // SessionService.instance.setRo(token); + final prefs = await SharedPreferences.getInstance(); await prefs.setString(_keyUser, json.encode(data)); await prefs.setStringList(_keyRemember, [username, password]); @@ -156,6 +164,8 @@ class AuthService { SessionService.instance.printUserInfo(); }); + return result; + } catch (e) { LoadingDialogHelper.hide(); Fluttertoast.showToast(msg: '用户信息获取失败,请重试');