master
hs 2026-04-01 17:53:42 +08:00
parent fb412d90e3
commit 2d0c587321
8 changed files with 271 additions and 143 deletions

View File

@ -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";
///

View File

@ -4,13 +4,14 @@ import 'package:qhd_prevention/http/HttpManager.dart';
import 'package:qhd_prevention/services/SessionService.dart';
class AppMenuApi {
static Future<Map<String, dynamic>> getAppMenu() async {
static Future<Map<String, dynamic>> getAppMenu(Map data) async {
return HttpManager().request(
ApiService.basePath,
'/appmenu/appMenu/appListTree',
method: Method.get,
data: {
'menuAttribution': 'QINGANG_RELATED_PARTIES',
...data
},
);
}

View File

@ -70,8 +70,8 @@ class AuthApi {
static Future<Map<String, dynamic>> 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: {},
);

View File

@ -126,6 +126,7 @@ class HomePageState extends RouteAwareState<HomePage>
"todoStats": "dashboard-todo-sort",
"checklist": "dashboard-todo-list",
"scan": "dashboard-scan",
"joinFirm": "dashboard-start-work",
};
@override
@ -419,7 +420,7 @@ class HomePageState extends RouteAwareState<HomePage>
final routeService = RouteService();
final bool showScan = routeService.hasPerm(_modulePerms['scan']!);
final bool showJoin = true; //
final bool showJoin = routeService.hasPerm(_modulePerms['joinFirm']!);
final List<Widget> children = [];
if (showScan) {

View File

@ -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<MainPage> with WidgetsBindingObserver {
_badgeManager.initAllModules();
}
// ****
_pages = <Widget>[
HomePage(key: _homeKey, isChooseFirm: widget.isChooseFirm),
@ -91,33 +95,28 @@ class _MainPageState extends State<MainPage> 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<String, dynamic>;
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');
debugPrint(
'AppMenuApi.getAppMenu error: $e -> fallback to local assets.',
);
}
if (route != null && route['data'] is List) {
final data = route['data'] as List<dynamic>;
//
// try {
// final routeString = await loadFromAssets();
// route = jsonDecode(routeString) as Map<String, dynamic>;
// } catch (e) {
// debugPrint('loadFromAssets error: $e');
// }
final data = route?['data'] ?? [];
RouteService().initializeRoutes(data);
// initializeRoutes notifyListeners -> _onRoutesUpdated
} else {
debugPrint('No valid route data to initialize RouteService.');
}
} catch (e) {
debugPrint('获取路由配置失败: $e');
} finally {
@ -145,6 +144,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
// 使 mainTabs _tabVisibility
final mainTabs = routeService.mainTabs;
if (mainTabs.isEmpty) {
_showErrorDialog();
return;
}
@ -168,7 +168,11 @@ class _MainPageState extends State<MainPage> 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<MainPage> with WidgetsBindingObserver {
_currentIndex = first;
}
});
if (!homeVisible && !notifVisible && !mineVisible) {
_showErrorDialog();
}
}
Future<void> _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<dynamic> route) => false, //
);
}
}
// tab fallback0
@ -292,33 +321,63 @@ class _MainPageState extends State<MainPage> 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),
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(
visibleItems.add(
BottomNavigationBarItem(
icon: _buildIconWithBadge(
icon: Image.asset('assets/tabbar/works.png', width: 24, height: 24),
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),
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),
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<MainPage> 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<MainPage> 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<MainPage> 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,7 +471,8 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
currentIndex: _currentIndex,
child: Scaffold(
appBar: null,
body: hasVisiblePages
body:
hasVisiblePages
? IndexedStack(
index: visibleCurrentIndex,
children: visiblePages,

View File

@ -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<MinePage> {
'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<MinePage> {
RouteService().addListener(_onRouteServiceUpdated);
// route
WidgetsBinding.instance.addPostFrameCallback((_) => _updateVisibilityFromRoute());
WidgetsBinding.instance.addPostFrameCallback(
(_) => _updateVisibilityFromRoute(),
);
}
@override
@ -189,20 +192,27 @@ class MinePageState extends State<MinePage> {
}
}
//
//
Future<void> _getUserInfo() async {
final res = await BasicInfoApi.getUserMessage(
'${SessionService.instance.accountId}',
);
if (res['success'] == true) {
final data = res['data'] as Map<String, dynamic>;
SessionService.instance.updateFromApiResponse(data);
await SessionService.instance.saveToPrefs();
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<String, dynamic>;
// SessionService.instance.updateFromApiResponse(data);
// await SessionService.instance.saveToPrefs();
// setState(() {
// name = SessionService.instance.userData?.name ?? "登录/注册";
// phone = SessionService.instance.userData?.phone ?? "";
// });
// }
}
Future<void> _logout() async {
@ -232,15 +242,14 @@ class MinePageState extends State<MinePage> {
title: '手机号:${SessionService.instance.phone}',
onGetCode: () async {
LoadingDialogHelper.show();
final res = await BasicInfoApi.sendRegisterSms({
'phone': phone,
});
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<MinePage> {
//
Future<void> _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,18 +349,31 @@ class MinePageState extends State<MinePage> {
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);
@ -392,12 +411,14 @@ class MinePageState extends State<MinePage> {
// isChooseFirm true
if (title == '切换账户' && !widget.isChooseFirm) continue;
children.add(_buildSettingItem(
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<MinePage> {
),
],
),
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<OverscrollIndicatorNotification>(
onNotification: (overscroll) {
@ -436,10 +464,16 @@ class MinePageState extends State<MinePage> {
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),
if (showLogout)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: CustomButton(
@ -455,7 +489,9 @@ class MinePageState extends State<MinePage> {
await _clearUserSession();
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => const LoginPage()),
MaterialPageRoute(
builder: (context) => const LoginPage(),
),
(Route<dynamic> route) => false,
);
},
@ -488,7 +524,11 @@ class MinePageState extends State<MinePage> {
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(),

View File

@ -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)
}
}

View File

@ -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<String, dynamic>;
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: '用户信息获取失败,请重试');