效果图 功能 1:输入用户名按下键盘的回车按键,能够根据用户名进行查询对应的仓库,仓库下拉框默认选中第一条记录。 2.当查询到仓库后,光标自动从用户名那边跳转到密码框。 3.点击登陆按钮,判断是否内容都不为空,然后访问服务端验证用户名密码是否正确,正确的情况下查询用户的权限,并且记录用户名和密码。然后跳转到主页。
以下是主要的俩个页面。Global是一个存全局变量的一个类,而Services就是一个统一管网络访问的一个类,主要功能就是访问对应的接口,并返回查询到的数据。数据类型是BaseResult
mian.dart
import 'package:flutter/material.dart';
import 'home.dart';
import 'login.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget { //整个APP的设置
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
initialRoute: "login" ,//设置默认的首页面(对本app而言,是登陆页)
theme: ThemeData(
primarySwatch: Colors.blue, //设置主题为蓝色
),
//在路由表注册路由,对应的字符对应哪个route
routes: {"login":(context)=> LoginRoute(),
"home":(context)=>HomeRoute()
},
);
}
}
login.dart
import 'dart:collection';
import 'package:app_flutter/common/obj_util.dart';
import 'package:app_flutter/models/userinfo.dart';
import 'package:app_flutter/models/warehouse.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'common/global.dart';
import 'common/services.dart';
import 'models/function_obj.dart';
class LoginRoute extends StatefulWidget{
const LoginRoute({Key? key}) : super(key: key);
@override
State<LoginRoute> createState() =>_LoginRouteState();
}
class _LoginRouteState extends State<LoginRoute>{
//输入框控制器
late TextEditingController _userController;
late TextEditingController _passwordController;
FocusNode _passwordFocusNode=FocusNode();
String userId="";
String? dropdownValue=null;
List<WareHouse>? wareList= <WareHouse>[];
//根据用户名去获取仓库
void _getWareHouse(String userId) async {
//获取查询结果
var _params=LinkedHashMap<String,dynamic>();
_params['userId']=userId;
_params['methodName']='getWareHouse';
var _result =await Services.getWarehouse(_params);
if(_result.code==Global.SUCCESS){
setState(() {
wareList=_result.data;
dropdownValue=wareList?[0].warehouseId;
FocusScope.of(context).requestFocus(_passwordFocusNode);
});
}else{
Global.showCenterCodeToast(_result.code,_result.msg);
}
}
//根据用户和密码进行登陆
void _login() async{
var _params=LinkedHashMap<String,dynamic>();
if(_userController.text.isEmpty){//如果用户为空
Global.showCenterToast("请输入账号");
}else if(_passwordController.text.isEmpty){
Global.showCenterToast("请输入密码");
}else if(ObjUtil.isEmpty(dropdownValue)){
Global.showCenterToast("请选择仓库");
}
_params['userId']=_userController.text;
_params['password']=_passwordController.text;
_params['methodName']='doLogin';
var _result =await Services.doLogin(_params);
if(_result.code==Global.SUCCESS) {//查询成功了
UserInfo? _userInfo=_result.data?[0];
//存到持久化里面去 下次登陆可以用
SharedPreferences _prefs = await SharedPreferences.getInstance();
_prefs.setString('userId', _userInfo?.userId??'');
_prefs.setString('password',_passwordController.text);
Global.roleId=_userInfo?.roleId??'';
Global.userId=_userController.text;
Global.warehouseId=dropdownValue??'';
_getFunction();
}else{//失败
Global.showCenterCodeToast(_result.code,_result.msg);
}
}
//获取权限
void _getFunction() async{
var _result =await Services.getFunction({'methodName':'getFunction','userID':_userController.text});
if(_result.code==Global.SUCCESS) { //查询成功了
List<FunctionObj>? _functionList=_result.data;
_functionList?.forEach((element) {
Global.functionMap.addAll(element.toJson());//赋值给全局变量 之后可以用
});
Navigator.pushNamed(context, "home");
}else{
Global.showCenterCodeToast(_result.code,_result.msg);
}
}
@override
void initState() {
super.initState();
_userController = TextEditingController();
_userController.addListener(() {
userId=_userController.text;
});
_passwordController = TextEditingController();
}
@override
void dispose() {
_userController.dispose();
_passwordController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
//该界面输入框的外框样式(用户框,密码框)
final OutlineInputBorder outlineInputBorder= OutlineInputBorder(borderRadius: BorderRadius.circular(40.0),borderSide: BorderSide(
color: Color(0xFFFFFFFF)
) );
return Scaffold(
resizeToAvoidBottomInset: false,
body: ConstrainedBox(
constraints: BoxConstraints(
minWidth:double.infinity,
minHeight: double.infinity
),
child: DecoratedBox(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill ,
image: AssetImage("images/bg.jpg")
),
),
child:Column(
children: [
Expanded( // 1/3空间
flex: 1,
child: Center(
child: Image.asset('images/hzlogo.png'),
),
),
Expanded( // 1/3空间
flex: 1,
child: Column(
children: [
Padding(
padding:EdgeInsets.symmetric(vertical: 2.0,horizontal: 30.0),
child: TextField(
controller: _userController,
onChanged:(String value)=> {
setState( () {
wareList=<WareHouse>[];
dropdownValue=null;
})
} ,
onSubmitted: (String value)=>_getWareHouse(value),
autofocus:true,
decoration: InputDecoration(
border: outlineInputBorder,
focusedBorder: outlineInputBorder,
enabledBorder: outlineInputBorder,
fillColor:Colors.white ,
filled: true,
hintText: "用户名",
prefixIcon: Icon(Icons.person)
),
),
)
,
Padding(
padding: EdgeInsets.symmetric(vertical: 2.0,horizontal: 30.0),
child: TextField(
controller: _passwordController,
cursorRadius: Radius.circular(20.0),
obscureText: true,
autofocus:true ,
focusNode: _passwordFocusNode,
decoration: InputDecoration(
border: outlineInputBorder,
focusedBorder: outlineInputBorder,
enabledBorder: outlineInputBorder,
fillColor:Colors.white ,
filled: true,
hintText: "密码",
prefixIcon: Icon(Icons.lock),
),
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 2.0,horizontal: 30.0),
child:DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40.0),
shape: BoxShape.rectangle,
color: Colors.white
),
child: ConstrainedBox(
constraints:BoxConstraints(minWidth: double.infinity,minHeight: 60.0) ,
child: Padding(
padding: EdgeInsets.fromLTRB(46.0, 12.0, 40.0, 0.0),
child: DropdownButton<String>(
value:dropdownValue,
icon: const Icon(Icons.arrow_downward,color: Colors.black,),
iconSize: 24,
style: const TextStyle(color: Colors.black,
fontSize: 16.0
),
underline:Container(
height: 0,
color: Colors.deepPurpleAccent,
) ,
onChanged: (String? newValue) {
setState(() {
print(newValue);
dropdownValue = newValue!;
});
},
items: wareList?.map<DropdownMenuItem<String>>((WareHouse value) {
return DropdownMenuItem<String>(
value: value.warehouseId,
child: Text(value.warehouseId),
);
}).toList(),
),
)
)
)
),
Padding(
padding: EdgeInsets.symmetric(vertical: 6.0),
child:ElevatedButton(
onPressed: _login,
style:ButtonStyle(
minimumSize: MaterialStateProperty.all<Size>(Size(150.0, 50.0)),
//背景色
backgroundColor: MaterialStateProperty.all<Color>(Colors.blueAccent),
//前景色 字体颜色
foregroundColor:MaterialStateProperty.all<Color>(Colors.white),
textStyle: MaterialStateProperty.all<TextStyle>(TextStyle(fontSize: 20.0)),
shape: MaterialStateProperty.all<OutlinedBorder>(RoundedRectangleBorder(borderRadius: BorderRadius.circular(40.0))),
),
child: Text("登陆"),
) ,)
],
),
),
Expanded( // 1/3空间
flex: 1,
child: Row(
),
),
],
)
),
)
);
}
}
BaseResult是用来接收所有返回结果的。主要是code 代码,msg 详细信息,data就是查询的结果。futter中泛型的使用方法https://blog.csdn.net/K_Hello/article/details/115525018
import 'package:json_annotation/json_annotation.dart';
part 'bas_result.g.dart';
@JsonSerializable(genericArgumentFactories: true)
class BaseResult<T>{
int code;
String msg;
List<T>? data;
BaseResult(this.code,this.msg,this.data);
factory BaseResult.fromJson(Map<String, dynamic> json, T Function(dynamic json) fromJsonT) => _$BaseResultFromJson(json, fromJsonT);
Map<String, dynamic> toJson(Object? Function(T value) toJsonT) =>
_$BaseResultToJson(this, toJsonT);
}
|