Merge remote-tracking branch 'remotes/origin/dev'

This commit is contained in:
jyuesong
2022-01-21 10:45:37 +08:00
12 changed files with 169 additions and 124 deletions

View File

@@ -1,3 +1,8 @@
## 1.0.3
* 解决2.10.12及以下版本无法登录的问题
* 适配最新版qinglong 相关接口字段
## 1.0.2 ## 1.0.2
* 支持修改用户名密码(仅限使用用户名密码登录用户) * 支持修改用户名密码(仅限使用用户名密码登录用户)

View File

@@ -24,7 +24,18 @@ class Api {
}, },
); );
} }
static Future<HttpResponse<LoginBean>> loginOld(
String userName,
String passWord,
) async {
return await Http.post<LoginBean>(
Url.loginOld,
{
"username": userName,
"password": passWord,
},
);
}
static Future<HttpResponse<LoginBean>> loginTwo( static Future<HttpResponse<LoginBean>> loginTwo(
String userName, String userName,
String passWord, String passWord,
@@ -103,6 +114,7 @@ class Api {
if (id != null) { if (id != null) {
data["_id"] = id; data["_id"] = id;
data["id"] = id;
return await Http.put<NullResponse>( return await Http.put<NullResponse>(
Url.addTask, Url.addTask,
data, data,
@@ -207,6 +219,7 @@ class Api {
if (id != null) { if (id != null) {
data["_id"] = id; data["_id"] = id;
data["id"] = id;
return await Http.put<NullResponse>( return await Http.put<NullResponse>(
Url.addEnv, Url.addEnv,
data, data,

View File

@@ -5,6 +5,7 @@ import 'package:dio/dio.dart';
import 'package:dio_log/dio_log.dart'; import 'package:dio_log/dio_log.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:qinglong_app/base/http/token_interceptor.dart'; import 'package:qinglong_app/base/http/token_interceptor.dart';
import 'package:qinglong_app/base/http/url.dart';
import 'package:qinglong_app/base/userinfo_viewmodel.dart'; import 'package:qinglong_app/base/userinfo_viewmodel.dart';
import 'package:qinglong_app/utils/extension.dart'; import 'package:qinglong_app/utils/extension.dart';
@@ -54,7 +55,7 @@ class Http {
return decodeResponse<T>(response, serializationName, compute); return decodeResponse<T>(response, serializationName, compute);
} on DioError catch (e) { } on DioError catch (e) {
return exceptionHandler<T>(e); return exceptionHandler<T>(e, uri);
} }
} }
@@ -74,7 +75,7 @@ class Http {
compute, compute,
); );
} on DioError catch (e) { } on DioError catch (e) {
return exceptionHandler<T>(e); return exceptionHandler<T>(e, uri);
} }
} }
@@ -94,7 +95,7 @@ class Http {
compute, compute,
); );
} on DioError catch (e) { } on DioError catch (e) {
return exceptionHandler<T>(e); return exceptionHandler<T>(e, uri);
} }
} }
@@ -113,7 +114,7 @@ class Http {
compute, compute,
); );
} on DioError catch (e) { } on DioError catch (e) {
return exceptionHandler<T>(e); return exceptionHandler<T>(e, uri);
} }
} }
@@ -125,8 +126,8 @@ class Http {
} }
} }
static HttpResponse<T> exceptionHandler<T>(DioError e) { static HttpResponse<T> exceptionHandler<T>(DioError e, String path) {
if (e.response?.statusCode == 401) { if (e.response?.statusCode == 401 && !Url.inWhiteList(path)) {
if (!getIt<UserInfoViewModel>().useSecretLogined) { if (!getIt<UserInfoViewModel>().useSecretLogined) {
exitLogin(); exitLogin();
} }

View File

@@ -7,18 +7,18 @@ import '../userinfo_viewmodel.dart';
class TokenInterceptor extends Interceptor { class TokenInterceptor extends Interceptor {
@override @override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) { void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
if (getIt<UserInfoViewModel>().token != null && if (getIt<UserInfoViewModel>().token != null && getIt<UserInfoViewModel>().token!.isNotEmpty) {
getIt<UserInfoViewModel>().token!.isNotEmpty) { options.headers["Authorization"] = "Bearer " + getIt<UserInfoViewModel>().token!;
options.headers["Authorization"] =
"Bearer " + getIt<UserInfoViewModel>().token!;
} }
options.headers["User-Agent"] = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"; options.headers["User-Agent"] =
"Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1";
options.headers["Content-Type"] = "application/json;charset=UTF-8"; options.headers["Content-Type"] = "application/json;charset=UTF-8";
if (options.path != Url.loginByClientId && options.path!= Url.loginTwo) {
options.queryParameters["t"] =
(DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(); if (!Url.inWhiteList(options.path)) {
options.queryParameters["t"] = (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString();
} }
return handler.next(options); return handler.next(options);
} }

View File

@@ -3,6 +3,9 @@ import '../userinfo_viewmodel.dart';
class Url { class Url {
static get login => "/api/user/login"; static get login => "/api/user/login";
static get loginOld => "/api/login";
static get loginTwo => "/api/user/two-factor/login"; static get loginTwo => "/api/user/two-factor/login";
static const loginByClientId = "/open/auth/token"; static const loginByClientId = "/open/auth/token";
static const user = "/api/user"; static const user = "/api/user";
@@ -50,6 +53,7 @@ class Url {
static get taskLogDetail => getIt<UserInfoViewModel>().useSecretLogined ? "/open/logs/" : "/api/logs/"; static get taskLogDetail => getIt<UserInfoViewModel>().useSecretLogined ? "/open/logs/" : "/api/logs/";
static get scripts => getIt<UserInfoViewModel>().useSecretLogined ? "/open/scripts/files" : "/api/scripts/files"; static get scripts => getIt<UserInfoViewModel>().useSecretLogined ? "/open/scripts/files" : "/api/scripts/files";
static get scriptUpdate => getIt<UserInfoViewModel>().useSecretLogined ? "/open/scripts" : "/api/scripts"; static get scriptUpdate => getIt<UserInfoViewModel>().useSecretLogined ? "/open/scripts" : "/api/scripts";
static get scriptDetail => getIt<UserInfoViewModel>().useSecretLogined ? "/open/scripts/" : "/api/scripts/"; static get scriptDetail => getIt<UserInfoViewModel>().useSecretLogined ? "/open/scripts/" : "/api/scripts/";
@@ -58,9 +62,6 @@ class Url {
static get dependencyReinstall => getIt<UserInfoViewModel>().useSecretLogined ? "/open/dependencies/reinstall" : "/api/dependencies/reinstall"; static get dependencyReinstall => getIt<UserInfoViewModel>().useSecretLogined ? "/open/dependencies/reinstall" : "/api/dependencies/reinstall";
static intimeLog(String cronId) { static intimeLog(String cronId) {
return getIt<UserInfoViewModel>().useSecretLogined ? "/open/crons/$cronId/log" : "/api/crons/$cronId/log"; return getIt<UserInfoViewModel>().useSecretLogined ? "/open/crons/$cronId/log" : "/api/crons/$cronId/log";
} }
@@ -68,4 +69,11 @@ class Url {
static envMove(String envId) { static envMove(String envId) {
return getIt<UserInfoViewModel>().useSecretLogined ? "/open/envs/$envId/move" : "/api/envs/$envId/move"; return getIt<UserInfoViewModel>().useSecretLogined ? "/open/envs/$envId/move" : "/api/envs/$envId/move";
} }
static bool inWhiteList(String path) {
if (path == login || path == loginByClientId || path == loginTwo || path == loginOld) {
return true;
}
return false;
}
} }

View File

@@ -10,18 +10,11 @@ class EnvBean {
String? name; String? name;
String? remarks; String? remarks;
EnvBean( EnvBean({this.value, this.sId, this.created, this.status, this.timestamp, this.name, this.remarks});
{this.value,
this.sId,
this.created,
this.status,
this.timestamp,
this.name,
this.remarks});
EnvBean.fromJson(Map<String, dynamic> json) { EnvBean.fromJson(Map<String, dynamic> json) {
value = json['value']; value = json['value'];
sId = json['_id']; sId = json.containsKey('_id') ? json['_id'].toString() : (json.containsKey('id') ? json['id'].toString() : "");
created = json['created']; created = json['created'];
status = json['status']; status = json['status'];
timestamp = json['timestamp']; timestamp = json['timestamp'];

View File

@@ -94,43 +94,25 @@ class _LoginPageState extends ConsumerState<LoginPage> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox( SizedBox(
height: MediaQuery.of(context).size.height / 10, height: MediaQuery.of(context).size.height / 8,
), ),
SizedBox( Row(
height: 50,
width: MediaQuery.of(context).size.width,
child: Stack(
children: [ children: [
Positioned( Expanded(
top: 0, child: Align(
left: 0, alignment: Alignment.centerLeft,
child: Image.asset( child: Image.asset(
"assets/images/login_tip.png", "assets/images/login_tip.png",
height: 45, height: 45,
), ),
), ),
const Positioned(
top: 10,
left: 0,
child: Text(
"登录",
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
), ),
), Image.asset(
),
Positioned(
top: 5,
right: 0,
child: Image.asset(
"assets/images/ql.png", "assets/images/ql.png",
height: 45, height: 45,
), ),
),
], ],
), ),
),
SizedBox( SizedBox(
height: MediaQuery.of(context).size.height / 15, height: MediaQuery.of(context).size.height / 15,
), ),
@@ -276,7 +258,9 @@ class _LoginPageState extends ConsumerState<LoginPage> {
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 25,), padding: const EdgeInsets.symmetric(
horizontal: 25,
),
child: Row( child: Row(
children: [ children: [
Checkbox( Checkbox(
@@ -307,7 +291,9 @@ class _LoginPageState extends ConsumerState<LoginPage> {
), ),
), ),
), ),
SizedBox(width: 10,), SizedBox(
width: 10,
),
], ],
), ),
), ),
@@ -316,7 +302,9 @@ class _LoginPageState extends ConsumerState<LoginPage> {
), ),
Container( Container(
alignment: Alignment.center, alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 40,), padding: const EdgeInsets.symmetric(
horizontal: 40,
),
child: SizedBox( child: SizedBox(
width: MediaQuery.of(context).size.width - 80, width: MediaQuery.of(context).size.width - 80,
child: IgnorePointer( child: IgnorePointer(
@@ -377,11 +365,60 @@ class _LoginPageState extends ConsumerState<LoginPage> {
} }
if (response.success) { if (response.success) {
loginSuccess(response, userName, password); loginSuccess(response, userName, password);
} else if (loginByUserName() && response.code == 401) {
//可能用户使用的是老版本qinglong
HttpResponse<LoginBean> oldResponse = await Api.loginOld(userName, password);
if (oldResponse.success) {
loginSuccess(oldResponse, userName, password);
} else {
(oldResponse.message ?? "请检查网络情况").toast();
if (oldResponse.code == 420) {
twoFact(userName, password);
} else {
isLoading = false;
setState(() {});
}
}
} else { } else {
print(response.code); print(response.code);
(response.message ?? "请检查网络情况").toast(); (response.message ?? "请检查网络情况").toast();
//420代表需要2步验证 //420代表需要2步验证
if (response.code == 420) { if (response.code == 420) {
twoFact(userName, password);
} else {
isLoading = false;
setState(() {});
}
}
}
void loginFailed(HttpResponse<LoginBean> response) {
(response.message ?? "请检查网络情况").toast();
isLoading = false;
setState(() {});
}
void loginSuccess(HttpResponse<LoginBean> response, String userName, String password) {
getIt<UserInfoViewModel>().updateToken(response.bean?.token ?? "");
getIt<UserInfoViewModel>().useSecretLogin(!loginByUserName());
if (rememberPassword) {
getIt<UserInfoViewModel>().updateUserName(userName, password);
}
Navigator.of(context).pushReplacementNamed(Routes.routeHomePage);
}
bool canClickLoginBtn() {
if (isLoading) return false;
if (_hostController.text.isEmpty) return false;
if (!loginByUserName()) {
return _cIdController.text.isNotEmpty && _cSecretController.text.isNotEmpty;
} else {
return _userNameController.text.isNotEmpty && _passwordController.text.isNotEmpty;
}
}
void twoFact(String userName, String password) {
String twoFact = ""; String twoFact = "";
showCupertinoDialog( showCupertinoDialog(
context: context, context: context,
@@ -443,36 +480,5 @@ class _LoginPageState extends ConsumerState<LoginPage> {
setState(() {}); setState(() {});
} }
}); });
} else {
isLoading = false;
setState(() {});
}
}
}
void loginFailed(HttpResponse<LoginBean> response) {
(response.message ?? "请检查网络情况").toast();
isLoading = false;
setState(() {});
}
void loginSuccess(HttpResponse<LoginBean> response, String userName, String password) {
getIt<UserInfoViewModel>().updateToken(response.bean?.token ?? "");
getIt<UserInfoViewModel>().useSecretLogin(!loginByUserName());
if (rememberPassword) {
getIt<UserInfoViewModel>().updateUserName(userName, password);
}
Navigator.of(context).pushReplacementNamed(Routes.routeHomePage);
}
bool canClickLoginBtn() {
if (isLoading) return false;
if (_hostController.text.isEmpty) return false;
if (!loginByUserName()) {
return _cIdController.text.isNotEmpty && _cSecretController.text.isNotEmpty;
} else {
return _userNameController.text.isNotEmpty && _passwordController.text.isNotEmpty;
}
} }
} }

View File

@@ -66,6 +66,21 @@ class _AboutPageState extends ConsumerState<AboutPage> {
fontSize: 16, fontSize: 16,
), ),
), ),
const SizedBox(
height: 15,
),
GestureDetector(
onTap: () {
_launchURL("https://t.me/qinglongapp");
},
child: Text(
"Telegram频道",
style: TextStyle(
color: primaryColor,
fontSize: 16,
),
),
),
const Spacer(), const Spacer(),
Row( Row(
children: [ children: [

View File

@@ -367,6 +367,9 @@ class _OtherPageState extends ConsumerState<OtherPage> {
}), }),
), ),
), ),
const SizedBox(
height: 30,
),
], ],
), ),
); );

View File

@@ -43,7 +43,7 @@ class TaskBean {
command = json['command'].toString(); command = json['command'].toString();
schedule = json['schedule'].toString(); schedule = json['schedule'].toString();
saved = json['saved']; saved = json['saved'];
sId = json['_id'].toString(); sId = json.containsKey('_id') ? json['_id'].toString() : (json.containsKey('id') ? json['id'].toString() : "");
created = json['created']; created = json['created'];
status = json['status']; status = json['status'];
timestamp = json['timestamp'].toString(); timestamp = json['timestamp'].toString();

View File

@@ -884,4 +884,4 @@ packages:
version: "3.1.0" version: "3.1.0"
sdks: sdks:
dart: ">=2.15.1 <3.0.0" dart: ">=2.15.1 <3.0.0"
flutter: ">=2.5.0" flutter: ">=2.8.1"

View File

@@ -1,10 +1,11 @@
name: qinglong_app name: qinglong_app
description: A new Flutter project. description: A new Flutter project.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.2+3 version: 1.0.3+4
environment: environment:
sdk: ">=2.15.1 <3.0.0" sdk: ">=2.15.1 <3.0.0"
flutter: ">=2.8.1"
dependencies: dependencies: