feat:适配多租户
This commit is contained in:
1 parent
cdbb69f843
commit
b370be9111
13 files changed
+175
-8
No files matched your search
@@ -56,4 +56,13 @@ abstract class UserApi {
|
||||
?.map<ServiceAsyncFace>((e) => ServiceAsyncFace.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// 获取租户列表
|
||||
static Future<List<ServiceTenant>?> getTenantList() async {
|
||||
final res = await HttpManage().dio.get("/admin/tenant/list");
|
||||
if (res.data == null) return null;
|
||||
return res.data
|
||||
?.map<ServiceTenant>((e) => ServiceTenant.fromJson(e))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
@@ -126,3 +126,32 @@ class ServiceAsyncFace {
|
||||
|
||||
Map<String, dynamic> toJson() => _$ServiceAsyncFaceToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class ServiceTenant {
|
||||
/// id
|
||||
final String? id;
|
||||
|
||||
/// 编号
|
||||
final String? code;
|
||||
|
||||
/// 编号
|
||||
final String? name;
|
||||
|
||||
final String? menuId;
|
||||
|
||||
final String? miniQr;
|
||||
|
||||
ServiceTenant({
|
||||
this.id,
|
||||
this.code,
|
||||
this.name,
|
||||
this.menuId,
|
||||
this.miniQr,
|
||||
});
|
||||
|
||||
factory ServiceTenant.fromJson(Map<String, dynamic> json) =>
|
||||
_$ServiceTenantFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$ServiceTenantToJson(this);
|
||||
}
|
||||
@@ -72,3 +72,21 @@ Map<String, dynamic> _$ServiceAsyncFaceToJson(ServiceAsyncFace instance) =>
|
||||
'deptId': instance.deptId,
|
||||
'deptName': instance.deptName,
|
||||
};
|
||||
|
||||
ServiceTenant _$ServiceTenantFromJson(Map<String, dynamic> json) =>
|
||||
ServiceTenant(
|
||||
id: json['id'] as String?,
|
||||
code: json['code'] as String?,
|
||||
name: json['name'] as String?,
|
||||
menuId: json['menuId'] as String?,
|
||||
miniQr: json['miniQr'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ServiceTenantToJson(ServiceTenant instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'code': instance.code,
|
||||
'name': instance.name,
|
||||
'menuId': instance.menuId,
|
||||
'miniQr': instance.miniQr,
|
||||
};
|
||||
@@ -180,6 +180,9 @@ class UserSetting extends Equatable {
|
||||
|
||||
/// end 服务端信息 end
|
||||
|
||||
/// 租户id
|
||||
String? tenantId;
|
||||
|
||||
UserSetting({
|
||||
this.username,
|
||||
this.password,
|
||||
@@ -199,6 +202,7 @@ class UserSetting extends Equatable {
|
||||
accessToken,
|
||||
refreshToken,
|
||||
expiresTime,
|
||||
tenantId,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +136,8 @@ UserSetting _$UserSettingFromJson(Map<String, dynamic> json) => UserSetting(
|
||||
..userId = (json['userId'] as num?)?.toInt()
|
||||
..accessToken = json['accessToken'] as String?
|
||||
..refreshToken = json['refreshToken'] as String?
|
||||
..expiresTime = (json['expiresTime'] as num?)?.toInt();
|
||||
..expiresTime = (json['expiresTime'] as num?)?.toInt()
|
||||
..tenantId = json['tenantId'] as String?;
|
||||
|
||||
Map<String, dynamic> _$UserSettingToJson(UserSetting instance) =>
|
||||
<String, dynamic>{
|
||||
@@ -147,6 +148,7 @@ Map<String, dynamic> _$UserSettingToJson(UserSetting instance) =>
|
||||
'accessToken': instance.accessToken,
|
||||
'refreshToken': instance.refreshToken,
|
||||
'expiresTime': instance.expiresTime,
|
||||
'tenantId': instance.tenantId,
|
||||
};
|
||||
|
||||
CanteenExtraPriceSetting _$CanteenExtraPriceSettingFromJson(
|
||||
|
||||
@@ -125,6 +125,10 @@ abstract class AppSettingTool {
|
||||
static Future<void> setUserSetting(UserSetting userInfo) async {
|
||||
final globalUserInfo = await getUserSetting();
|
||||
if (globalUserInfo == userInfo) return;
|
||||
if (ObjectUtil.isEmpty(userInfo.tenantId) &&
|
||||
ObjectUtil.isNotEmpty(globalUserInfo.tenantId)) {
|
||||
userInfo.tenantId = globalUserInfo.tenantId;
|
||||
}
|
||||
await _setSetting(userJson: userInfo);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,14 +30,14 @@ class HttpManage {
|
||||
InterceptorsWrapper(
|
||||
onRequest: (RequestOptions options, handler) async {
|
||||
options.headers["CLIENT-TOC"] = "Y";
|
||||
options.headers["TENANT-ID"] = 1;
|
||||
final userInfo = await AppSettingTool.getUserSetting();
|
||||
if (!options.path.contains(Constants.oauth2AppApiUrl)) {
|
||||
final userInfo = await AppSettingTool.getUserSetting();
|
||||
if (ObjectUtil.isNotEmpty(userInfo.accessToken)) {
|
||||
options.headers['Authorization'] =
|
||||
"Bearer ${userInfo.accessToken}";
|
||||
}
|
||||
}
|
||||
options.headers["TENANT-ID"] = userInfo.tenantId ?? 1;
|
||||
return handler.next(options);
|
||||
},
|
||||
onResponse: (e, handler) async {
|
||||
|
||||
@@ -12,7 +12,7 @@ class Constants {
|
||||
/// 服务 url
|
||||
// static const apiUrl = 'https://stgl.pj.gov.cn/api';
|
||||
|
||||
static const apiUrl = 'http://192.168.101.81:9999';
|
||||
static const apiUrl = 'http://192.168.101.107:9999';
|
||||
|
||||
/// 静态资源 url
|
||||
static const ossUrl = apiUrl;
|
||||
|
||||
@@ -29,3 +29,4 @@ export './order/order_supermarket_common.dart';
|
||||
export './setting/setting_password_dialog.dart';
|
||||
|
||||
export './user/user_info.dart';
|
||||
export './user/user_tenant_dialog.dart';
|
||||
@@ -0,0 +1,50 @@
|
||||
import 'package:common_utils/common_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:forui/forui.dart';
|
||||
|
||||
import 'package:pj_supermarket_cloud/common/index.dart';
|
||||
|
||||
Widget appTenantDialog(
|
||||
BuildContext context,
|
||||
FRadioSelectGroupController<String> controller, {
|
||||
required List<ServiceTenant> list,
|
||||
}) {
|
||||
final theme = FTheme.of(context);
|
||||
final selectList = list.where((v) => ObjectUtil.isNotEmpty(v.code));
|
||||
return FSelectMenuTile<String>(
|
||||
title: Text(
|
||||
"单位",
|
||||
style: theme.typography.base,
|
||||
),
|
||||
groupController: controller,
|
||||
validator: (value) => value == null ? '请选择' : null,
|
||||
autoHide: true,
|
||||
prefixIcon: FIcon(
|
||||
FAssets.icons.building2,
|
||||
size: theme.typography.xl.fontSize,
|
||||
),
|
||||
menu: selectList.map((v) {
|
||||
return FSelectTile(
|
||||
title: Text(
|
||||
v.name!,
|
||||
style: theme.typography.base,
|
||||
),
|
||||
value: v.code!,
|
||||
);
|
||||
}).toList(),
|
||||
details: ListenableBuilder(
|
||||
listenable: controller,
|
||||
builder: (context, _) {
|
||||
final v = controller.value.firstOrNull;
|
||||
if (v == null) return const SizedBox();
|
||||
final target = selectList.firstWhere((i) => i.code == v);
|
||||
return Text(
|
||||
target.name!,
|
||||
style: theme.typography.base.copyWith(
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:common_utils/common_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:forui/forui.dart';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
|
||||
@@ -11,8 +12,16 @@ class LoginController extends GetxController {
|
||||
|
||||
late SysSetting sysSetting;
|
||||
|
||||
late UserSetting userSetting;
|
||||
|
||||
Rx<SysType> sysType = SysType.CANTEEN.obs;
|
||||
|
||||
RxList<ServiceTenant> tenantList = <ServiceTenant>[].obs;
|
||||
|
||||
final tenantC = FRadioSelectGroupController<String>();
|
||||
|
||||
ServiceTenant currentTenant = ServiceTenant();
|
||||
|
||||
// 用户名
|
||||
final usernameC = TextEditingController();
|
||||
// 密码
|
||||
@@ -26,8 +35,22 @@ class LoginController extends GetxController {
|
||||
void onInit() async {
|
||||
super.onInit();
|
||||
sysSetting = await AppSettingTool.getSysSetting();
|
||||
userSetting = await AppSettingTool.getUserSetting();
|
||||
sysType.value = sysSetting.sysType;
|
||||
await getTenantList();
|
||||
await autoLogin();
|
||||
tenantC.addValueListener((v) async {
|
||||
final target = tenantList.firstWhereOrNull((i) => i.code == v.first);
|
||||
if (target == null) return;
|
||||
EasyLoading.show(
|
||||
status: '切换中...',
|
||||
maskType: EasyLoadingMaskType.black,
|
||||
);
|
||||
currentTenant = target;
|
||||
userSetting.tenantId = target.id;
|
||||
await AppSettingTool.setUserSetting(userSetting);
|
||||
EasyLoading.dismiss();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -59,7 +82,6 @@ class LoginController extends GetxController {
|
||||
if (visibleMsg) EasyLoading.dismiss();
|
||||
return;
|
||||
}
|
||||
final userSetting = await AppSettingTool.getUserSetting();
|
||||
userSetting.userId = data['user_id'];
|
||||
userSetting.accessToken = data['access_token'];
|
||||
userSetting.refreshToken = data['refresh_token'];
|
||||
@@ -67,6 +89,7 @@ class LoginController extends GetxController {
|
||||
userSetting.sysType = sysSetting.sysType;
|
||||
userSetting.username = usernameC.value.text;
|
||||
userSetting.password = passwordC.value.text;
|
||||
userSetting.tenantId = currentTenant.id;
|
||||
await AppSettingTool.setUserSetting(userSetting);
|
||||
if (visibleMsg) {
|
||||
Toast.success(msg: "登录成功");
|
||||
@@ -82,7 +105,6 @@ class LoginController extends GetxController {
|
||||
}
|
||||
|
||||
Future<void> autoLogin() async {
|
||||
final userSetting = await AppSettingTool.getUserSetting();
|
||||
if (ObjectUtil.isEmpty(userSetting.username) ||
|
||||
ObjectUtil.isEmpty(userSetting.password) ||
|
||||
ObjectUtil.isEmpty(userSetting.sysType?.name)) {
|
||||
@@ -122,6 +144,23 @@ class LoginController extends GetxController {
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<void> getTenantList() async {
|
||||
try {
|
||||
final list = await UserApi.getTenantList();
|
||||
if (list == null) return;
|
||||
tenantList.value = list;
|
||||
if (ObjectUtil.isNotEmpty(userSetting.tenantId)) {
|
||||
tenantC.value = {list.first.code!};
|
||||
} else {
|
||||
if (!ObjectUtil.isEmptyList(list)) {
|
||||
tenantC.value = {list.first.code!};
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
logger.e("|$_tag|获取租户列表错误error:|$e|");
|
||||
}
|
||||
}
|
||||
|
||||
void _clearForm() {
|
||||
usernameC.clear();
|
||||
passwordC.clear();
|
||||
|
||||
@@ -13,14 +13,23 @@ class LoginPage extends GetView<LoginController> {
|
||||
// 主视图
|
||||
Widget _buildView() {
|
||||
final theme = FTheme.of(Get.context!);
|
||||
final context = Get.context!;
|
||||
return SizedBox(
|
||||
width: Get.context!.sizes.width * 0.3,
|
||||
width: context.sizes.width * 0.3,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
FCard(
|
||||
title: appLogo(),
|
||||
child: [
|
||||
SizedBox(height: 30.h),
|
||||
Obx(
|
||||
() => appTenantDialog(
|
||||
context,
|
||||
controller.tenantC,
|
||||
list: controller.tenantList,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 30.h),
|
||||
Obx(
|
||||
() => FTextField(
|
||||
|
||||
@@ -21,7 +21,9 @@ Future<void> _bindServiceDialog(BuildContext context, SysSetting sys) async {
|
||||
// 正式环境-测试
|
||||
// uniqueCodeC.text = "1896157295523049473";
|
||||
// 测试环境-测试设备
|
||||
uniqueCodeC.text = "1877592554489143298";
|
||||
// uniqueCodeC.text = "1877592554489143298";
|
||||
// 测试环境-食堂-浦阳
|
||||
uniqueCodeC.text = "1914567628657778690";
|
||||
}
|
||||
await showAdaptiveDialog(
|
||||
context: context,
|
||||
|
||||
Reference in new issue
Block a user