feat: 出入库登记功能完成
|
@ -3,6 +3,11 @@ plugins {
|
||||||
id "kotlin-android"
|
id "kotlin-android"
|
||||||
id "dev.flutter.flutter-gradle-plugin"
|
id "dev.flutter.flutter-gradle-plugin"
|
||||||
}
|
}
|
||||||
|
def keystoreProperties = new Properties()
|
||||||
|
def keystorePropertiesFile = rootProject.file('key.properties')
|
||||||
|
if (keystorePropertiesFile.exists()) {
|
||||||
|
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||||
|
}
|
||||||
|
|
||||||
def localProperties = new Properties()
|
def localProperties = new Properties()
|
||||||
def localPropertiesFile = rootProject.file('local.properties')
|
def localPropertiesFile = rootProject.file('local.properties')
|
||||||
|
@ -50,12 +55,19 @@ android {
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
}
|
}
|
||||||
|
signingConfigs {
|
||||||
|
release {
|
||||||
|
keyAlias keystoreProperties['keyAlias']
|
||||||
|
keyPassword keystoreProperties['keyPassword']
|
||||||
|
storeFile file(keystoreProperties['storeFile'])
|
||||||
|
storePassword keystoreProperties['storePassword']
|
||||||
|
}
|
||||||
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
// TODO: Add your own signing config for the release build.
|
// TODO: Add your own signing config for the release build.
|
||||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||||
signingConfig signingConfigs.debug
|
signingConfig signingConfigs.release
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,4 +31,18 @@
|
||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
android:value="2" />
|
android:value="2" />
|
||||||
</application>
|
</application>
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.READ_PHONE_STATE" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.CAMERA" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
</manifest>
|
</manifest>
|
After Width: | Height: | Size: 26 KiB |
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item>
|
|
||||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
|
||||||
</item>
|
|
||||||
</layer-list>
|
|
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 121 KiB |
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 121 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 121 KiB |
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 121 KiB |
|
@ -6,6 +6,8 @@
|
||||||
<item name="android:windowFullscreen">false</item>
|
<item name="android:windowFullscreen">false</item>
|
||||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||||
|
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
|
||||||
|
<item name="android:windowSplashScreenIconBackgroundColor">#ffffff</item>
|
||||||
</style>
|
</style>
|
||||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||||
This theme determines the color of the Android Window while your
|
This theme determines the color of the Android Window while your
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
<item name="android:windowFullscreen">false</item>
|
<item name="android:windowFullscreen">false</item>
|
||||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||||
|
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
|
||||||
|
<item name="android:windowSplashScreenIconBackgroundColor">#ffffff</item>
|
||||||
</style>
|
</style>
|
||||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||||
This theme determines the color of the Android Window while your
|
This theme determines the color of the Android Window while your
|
||||||
|
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 57 KiB |
After Width: | Height: | Size: 40 KiB |
|
@ -1,8 +0,0 @@
|
||||||
flutter_native_splash:
|
|
||||||
background_image: 'assets/images/launch_image.jpg'
|
|
||||||
android: true
|
|
||||||
ios: true
|
|
||||||
landscape:
|
|
||||||
image: assets/images/launch_image_landscape.jpg
|
|
||||||
android: true
|
|
||||||
ios: true
|
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 121 KiB |
|
@ -17,7 +17,7 @@
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" image="LaunchBackground" translatesAutoresizingMaskIntoConstraints="NO" id="tWc-Dq-wcI"/>
|
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" image="LaunchBackground" translatesAutoresizingMaskIntoConstraints="NO" id="tWc-Dq-wcI"/>
|
||||||
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4"></imageView>
|
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleAspectFill" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4"></imageView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
|
|
|
@ -47,5 +47,7 @@
|
||||||
<true/>
|
<true/>
|
||||||
<key>UIStatusBarHidden</key>
|
<key>UIStatusBarHidden</key>
|
||||||
<false/>
|
<false/>
|
||||||
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
|
<false/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -19,7 +19,7 @@ class Api {
|
||||||
// 获取个人信息
|
// 获取个人信息
|
||||||
static Future<Response> getUserInfo() {
|
static Future<Response> getUserInfo() {
|
||||||
return DioService.dio.get(
|
return DioService.dio.get(
|
||||||
Urls.getUserInfo,
|
Urls.userInfo,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +64,12 @@ class Api {
|
||||||
queryParameters: {'page': 1, 'pageSize': 10, ...(params)});
|
queryParameters: {'page': 1, 'pageSize': 10, ...(params)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 分页获取用户
|
||||||
|
static Future<Response<PaginationData>> getUsers(Map params) {
|
||||||
|
return DioService.dio.get<PaginationData>(Urls.sysUser,
|
||||||
|
queryParameters: {'page': 1, 'pageSize': 10, ...(params)});
|
||||||
|
}
|
||||||
|
|
||||||
// 一次性获取所有的字典类型(不分页)
|
// 一次性获取所有的字典类型(不分页)
|
||||||
static Future<Response> getDictTypeAll(Map params) {
|
static Future<Response> getDictTypeAll(Map params) {
|
||||||
return DioService.dio.post(Urls.getDictType, data: params);
|
return DioService.dio.post(Urls.getDictType, data: params);
|
||||||
|
@ -81,11 +87,6 @@ class Api {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<Response> getAppConfig() {
|
|
||||||
Map<String, dynamic> query = {'ver': 0};
|
|
||||||
return DioService.dio.get(Urls.getAppConfig, queryParameters: query);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<Response> saveUserInfo(Map<String, dynamic> data) {
|
static Future<Response> saveUserInfo(Map<String, dynamic> data) {
|
||||||
return DioService.dio.post(Urls.saveUserInfo, data: data);
|
return DioService.dio.post(Urls.saveUserInfo, data: data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
/// Global config
|
/// Global config
|
||||||
class GloablConfig {
|
class GloablConfig {
|
||||||
// static const BASE_URL = "http://10.0.2.2:7001/api/";
|
// static const BASE_URL = "http://10.0.2.2:7001/api/";
|
||||||
static const BASE_URL = "http://192.168.60.220:7001/api/";
|
// static const BASE_URL = "http://144.123.43.138:3001/api/";
|
||||||
static const OSS_URL = "http://192.168.60.220:7001";
|
// static const OSS_URL = "http://144.123.43.138:3001";
|
||||||
|
static const BASE_URL = "http://192.168.60.220:8001/api/";
|
||||||
|
static const OSS_URL = "http://192.168.60.220:8001";
|
||||||
static const DOMAIN_NAME = "山矿通";
|
static const DOMAIN_NAME = "山矿通";
|
||||||
static const DEBUG = true;
|
static const DEBUG = true;
|
||||||
static const PRIVACY_POLICY = 'http://h5.heeru.xyz/privacyPolicy.html';
|
static const PRIVACY_POLICY = 'http://h5.heeru.xyz/privacyPolicy.html';
|
||||||
static const TERM_OF_USER = 'http://h5.heeru.xyz/termConditions.html';
|
static const TERM_OF_USER = 'http://h5.heeru.xyz/termConditions.html';
|
||||||
static const APPLE_STORE_PAGE = 'https://apps.apple.com/cn/app';
|
static const APPLE_STORE_PAGE = 'https://apps.apple.com/cn/app';
|
||||||
|
static const DIO_TIMEOUT = 10;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
class Urls {
|
class Urls {
|
||||||
static String getAppConfig = 'config/getAppConfig';
|
|
||||||
static String login = 'auth/login';
|
static String login = 'auth/login';
|
||||||
static String isValidToken = 'security/isValidToken';
|
static String isValidToken = 'security/isValidToken';
|
||||||
static String logout = 'security/logout';
|
static String logout = 'security/logout';
|
||||||
static String deleteAccount = 'user/deleteAccount';
|
static String deleteAccount = 'user/deleteAccount';
|
||||||
static String saveUserInfo = 'user/saveUserInfo';
|
static String saveUserInfo = 'user/saveUserInfo';
|
||||||
static String getUserInfo = 'account/profile';
|
static String sysUser = 'system/users';
|
||||||
|
static String userInfo = 'account/profile';
|
||||||
static String projects = 'project';
|
static String projects = 'project';
|
||||||
static String products = 'product';
|
static String products = 'product';
|
||||||
static String inventoryInout = 'materials-in-out';
|
static String inventoryInout = 'materials-in-out';
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
// import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
import 'package:sk_base_mobile/global.dart';
|
import 'package:sk_base_mobile/global.dart';
|
||||||
import 'package:sk_base_mobile/index.dart';
|
import 'package:sk_base_mobile/index.dart';
|
||||||
import 'package:sk_base_mobile/util/logger_util.dart';
|
import 'package:sk_base_mobile/util/logger_util.dart';
|
||||||
|
@ -10,5 +14,23 @@ Future<void> main() async {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
LoggerUtil().error('Init failed, please try again.${e}');
|
LoggerUtil().error('Init failed, please try again.${e}');
|
||||||
}
|
}
|
||||||
runApp(const IndexPage());
|
bool isProduction = kReleaseMode;
|
||||||
|
// await SentryFlutter.init(
|
||||||
|
// (options) {
|
||||||
|
// options.environment = isProduction ? 'production' : 'development';
|
||||||
|
// // options.beforeSend = (event, {hint}) {
|
||||||
|
// // if (!isProduction) {
|
||||||
|
// // return null;
|
||||||
|
// // }
|
||||||
|
// // return event;
|
||||||
|
// // };
|
||||||
|
// options.dsn =
|
||||||
|
// 'https://ce4f75d3cd9120a1bd9f1a807e573de1@o1078619.ingest.us.sentry.io/4506981258952704';
|
||||||
|
// // Set tracesSampleRate to 1.0 to capture 100% of transactions for performance monitoring.
|
||||||
|
// // We recommend adjusting this value in production.
|
||||||
|
// options.tracesSampleRate = 1.0;
|
||||||
|
// },
|
||||||
|
// appRunner: () => runApp(const IndexPage()),
|
||||||
|
// );
|
||||||
|
return runApp(const IndexPage());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
class DeptModel {
|
||||||
|
DeptModel({
|
||||||
|
required this.id,
|
||||||
|
required this.createdAt,
|
||||||
|
required this.updatedAt,
|
||||||
|
required this.name,
|
||||||
|
required this.orderNo,
|
||||||
|
});
|
||||||
|
|
||||||
|
final int? id;
|
||||||
|
final DateTime? createdAt;
|
||||||
|
final DateTime? updatedAt;
|
||||||
|
final String? name;
|
||||||
|
final int? orderNo;
|
||||||
|
|
||||||
|
factory DeptModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return DeptModel(
|
||||||
|
id: json["id"],
|
||||||
|
createdAt: DateTime.tryParse(json["createdAt"] ?? ""),
|
||||||
|
updatedAt: DateTime.tryParse(json["updatedAt"] ?? ""),
|
||||||
|
name: json["name"],
|
||||||
|
orderNo: json["orderNo"],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
"id": id,
|
||||||
|
"createdAt": createdAt?.toIso8601String(),
|
||||||
|
"updatedAt": updatedAt?.toIso8601String(),
|
||||||
|
"name": name,
|
||||||
|
"orderNo": orderNo,
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,40 +1,45 @@
|
||||||
class RoleModel {
|
class RoleModel {
|
||||||
int? id;
|
RoleModel({
|
||||||
String? createdAt;
|
required this.id,
|
||||||
String? updatedAt;
|
required this.createdAt,
|
||||||
String? name;
|
required this.updatedAt,
|
||||||
String? value;
|
required this.name,
|
||||||
String? remark;
|
required this.value,
|
||||||
int? status;
|
required this.remark,
|
||||||
|
required this.status,
|
||||||
|
required this.roleDefault,
|
||||||
|
});
|
||||||
|
|
||||||
RoleModel(
|
final int? id;
|
||||||
{this.id,
|
final DateTime? createdAt;
|
||||||
this.createdAt,
|
final DateTime? updatedAt;
|
||||||
this.updatedAt,
|
final String? name;
|
||||||
this.name,
|
final String? value;
|
||||||
this.value,
|
final String? remark;
|
||||||
this.remark,
|
final int? status;
|
||||||
this.status});
|
final dynamic roleDefault;
|
||||||
|
|
||||||
RoleModel.fromJson(Map<String, dynamic> json) {
|
factory RoleModel.fromJson(Map<String, dynamic> json) {
|
||||||
id = json['id'];
|
return RoleModel(
|
||||||
createdAt = json['createdAt'];
|
id: json["id"],
|
||||||
updatedAt = json['updatedAt'];
|
createdAt: DateTime.tryParse(json["createdAt"] ?? ""),
|
||||||
name = json['name'];
|
updatedAt: DateTime.tryParse(json["updatedAt"] ?? ""),
|
||||||
value = json['value'];
|
name: json["name"],
|
||||||
remark = json['remark'];
|
value: json["value"],
|
||||||
status = json['status'];
|
remark: json["remark"],
|
||||||
|
status: json["status"],
|
||||||
|
roleDefault: json["default"],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() => {
|
||||||
final Map<String, dynamic> data = <String, dynamic>{};
|
"id": id,
|
||||||
data['id'] = id;
|
"createdAt": createdAt?.toIso8601String(),
|
||||||
data['createdAt'] = createdAt;
|
"updatedAt": updatedAt?.toIso8601String(),
|
||||||
data['updatedAt'] = updatedAt;
|
"name": name,
|
||||||
data['name'] = name;
|
"value": value,
|
||||||
data['value'] = value;
|
"remark": remark,
|
||||||
data['remark'] = remark;
|
"status": status,
|
||||||
data['status'] = status;
|
"default": roleDefault,
|
||||||
return data;
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,13 @@
|
||||||
|
import 'package:sk_base_mobile/models/dept.model.dart';
|
||||||
import 'package:sk_base_mobile/models/role.model.dart';
|
import 'package:sk_base_mobile/models/role.model.dart';
|
||||||
|
|
||||||
class UserInfoModel {
|
class UserInfoModel {
|
||||||
int? id;
|
UserInfoModel({
|
||||||
String? createdAt;
|
this.id,
|
||||||
String? updatedAt;
|
|
||||||
String? username;
|
|
||||||
String? nickname;
|
|
||||||
String? avatar;
|
|
||||||
String? qq;
|
|
||||||
String? email;
|
|
||||||
String? phone;
|
|
||||||
String? remark;
|
|
||||||
int? status;
|
|
||||||
List<RoleModel>? roles;
|
|
||||||
|
|
||||||
UserInfoModel(
|
|
||||||
{this.id,
|
|
||||||
this.createdAt,
|
this.createdAt,
|
||||||
this.updatedAt,
|
this.updatedAt,
|
||||||
this.username,
|
this.username,
|
||||||
|
this.psalt,
|
||||||
this.nickname,
|
this.nickname,
|
||||||
this.avatar,
|
this.avatar,
|
||||||
this.qq,
|
this.qq,
|
||||||
|
@ -26,44 +15,61 @@ class UserInfoModel {
|
||||||
this.phone,
|
this.phone,
|
||||||
this.remark,
|
this.remark,
|
||||||
this.status,
|
this.status,
|
||||||
this.roles});
|
this.dept,
|
||||||
|
this.roles = const [],
|
||||||
UserInfoModel.fromJson(Map<String, dynamic> json) {
|
|
||||||
id = json['id'];
|
|
||||||
createdAt = json['createdAt'];
|
|
||||||
updatedAt = json['updatedAt'];
|
|
||||||
username = json['username'];
|
|
||||||
nickname = json['nickname'];
|
|
||||||
avatar = json['avatar'];
|
|
||||||
qq = json['qq'];
|
|
||||||
email = json['email'];
|
|
||||||
phone = json['phone'];
|
|
||||||
remark = json['remark'];
|
|
||||||
status = json['status'];
|
|
||||||
if (json['roles'] != null) {
|
|
||||||
roles = <RoleModel>[];
|
|
||||||
json['roles'].forEach((v) {
|
|
||||||
roles!.add(RoleModel.fromJson(v));
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
final int? id;
|
||||||
|
final DateTime? createdAt;
|
||||||
|
final DateTime? updatedAt;
|
||||||
|
final String? username;
|
||||||
|
final String? psalt;
|
||||||
|
final String? nickname;
|
||||||
|
final String? avatar;
|
||||||
|
final String? qq;
|
||||||
|
final String? email;
|
||||||
|
final String? phone;
|
||||||
|
final String? remark;
|
||||||
|
final int? status;
|
||||||
|
final DeptModel? dept;
|
||||||
|
List<RoleModel> roles;
|
||||||
|
|
||||||
|
factory UserInfoModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
return UserInfoModel(
|
||||||
|
id: json["id"],
|
||||||
|
createdAt: DateTime.tryParse(json["createdAt"] ?? ""),
|
||||||
|
updatedAt: DateTime.tryParse(json["updatedAt"] ?? ""),
|
||||||
|
username: json["username"],
|
||||||
|
psalt: json["psalt"],
|
||||||
|
nickname: json["nickname"],
|
||||||
|
avatar: json["avatar"],
|
||||||
|
qq: json["qq"],
|
||||||
|
email: json["email"],
|
||||||
|
phone: json["phone"],
|
||||||
|
remark: json["remark"],
|
||||||
|
status: json["status"],
|
||||||
|
dept: json["dept"] == null ? null : DeptModel.fromJson(json["dept"]),
|
||||||
|
roles: json["roles"] == null
|
||||||
|
? []
|
||||||
|
: List<RoleModel>.from(
|
||||||
|
json["roles"]!.map((x) => RoleModel.fromJson(x))),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() => {
|
||||||
final Map<String, dynamic> data = <String, dynamic>{};
|
"id": id,
|
||||||
data['id'] = id;
|
"createdAt": createdAt?.toIso8601String(),
|
||||||
data['createdAt'] = createdAt;
|
"updatedAt": updatedAt?.toIso8601String(),
|
||||||
data['updatedAt'] = updatedAt;
|
"username": username,
|
||||||
data['username'] = username;
|
"psalt": psalt,
|
||||||
data['nickname'] = nickname;
|
"nickname": nickname,
|
||||||
data['avatar'] = avatar;
|
"avatar": avatar,
|
||||||
data['qq'] = qq;
|
"qq": qq,
|
||||||
data['email'] = email;
|
"email": email,
|
||||||
data['phone'] = phone;
|
"phone": phone,
|
||||||
data['remark'] = remark;
|
"remark": remark,
|
||||||
data['status'] = status;
|
"status": status,
|
||||||
if (roles != null) {
|
"dept": dept?.toJson(),
|
||||||
data['roles'] = roles!.map((v) => v.toJson()).toList();
|
"roles": roles.map((x) => x?.toJson()).toList(),
|
||||||
}
|
};
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ class CustomAppBar extends StatelessWidget {
|
||||||
),
|
),
|
||||||
Obx(
|
Obx(
|
||||||
() => Text(
|
() => Text(
|
||||||
AuthStore.to.userInfo.value.username ?? '',
|
AuthStore.to.userInfo.value.nickname ?? '',
|
||||||
style: Theme.of(context).textTheme.titleMedium!.copyWith(
|
style: Theme.of(context).textTheme.titleMedium!.copyWith(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
|
|
@ -59,17 +59,6 @@ class LoginScreen extends StatelessWidget {
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
// Row(
|
|
||||||
// mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
// children: [
|
|
||||||
// Text(
|
|
||||||
// '山矿通',
|
|
||||||
// style: TextStyle(
|
|
||||||
// letterSpacing: ScreenAdaper.sp(10),
|
|
||||||
// fontSize: ScreenAdaper.sp(70)),
|
|
||||||
// )
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
SizedBox(height: ScreenAdaper.height(50)),
|
SizedBox(height: ScreenAdaper.height(50)),
|
||||||
buildForm(),
|
buildForm(),
|
||||||
SizedBox(height: ScreenAdaper.height(50)),
|
SizedBox(height: ScreenAdaper.height(50)),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import '../../store/auth.store.dart';
|
import '../../store/auth.store.dart';
|
||||||
|
// import 'package:sentry/sentry.dart';
|
||||||
|
|
||||||
class LoginController extends GetxController {
|
class LoginController extends GetxController {
|
||||||
final isAgreeTerm = RxBool(false);
|
final isAgreeTerm = RxBool(false);
|
||||||
|
@ -13,6 +14,7 @@ class LoginController extends GetxController {
|
||||||
if (!formKey.currentState!.validate()) {
|
if (!formKey.currentState!.validate()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 拿出form中的数据
|
// 拿出form中的数据
|
||||||
AuthStore.to.login(username: username, password: password);
|
AuthStore.to.login(username: username, password: password);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,201 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||||
|
import 'package:sk_base_mobile/apis/index.dart';
|
||||||
|
import 'package:sk_base_mobile/app_theme.dart';
|
||||||
|
import 'package:sk_base_mobile/constants/bg_color.dart';
|
||||||
|
import 'package:sk_base_mobile/models/index.dart';
|
||||||
|
import 'package:sk_base_mobile/models/inventory.model.dart';
|
||||||
|
import 'package:sk_base_mobile/models/user_info.model.dart';
|
||||||
|
import 'package:sk_base_mobile/util/debouncer.dart';
|
||||||
|
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||||
|
import 'package:sk_base_mobile/widgets/empty.dart';
|
||||||
|
import 'package:sk_base_mobile/widgets/fade_in_cache_image.dart';
|
||||||
|
|
||||||
|
class AgentSearch extends StatelessWidget {
|
||||||
|
Function(UserInfoModel)? onSelected;
|
||||||
|
Function(UserInfoModel)? beforeSelectedCheck;
|
||||||
|
AgentSearch({super.key, this.onSelected, this.beforeSelectedCheck});
|
||||||
|
final controller = Get.put(AgentSearchController());
|
||||||
|
final listTitleTextStyle =
|
||||||
|
TextStyle(fontSize: ScreenAdaper.sp(20), fontWeight: FontWeight.w600);
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: ScreenAdaper.width(20),
|
||||||
|
vertical: ScreenAdaper.height(20)),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
buildSearchBar(),
|
||||||
|
SizedBox(
|
||||||
|
height: ScreenAdaper.height(defaultPadding) / 2,
|
||||||
|
),
|
||||||
|
Expanded(child: buildList())
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildSearchBar() {
|
||||||
|
final doSearch = debouncer((String value) {
|
||||||
|
controller.searchKey.value = value;
|
||||||
|
controller.onRefresh();
|
||||||
|
}, delayTime: 500);
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 5,
|
||||||
|
child: TextField(
|
||||||
|
controller: controller.searchBarTextConroller,
|
||||||
|
onChanged: (value) => doSearch(value),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
contentPadding: EdgeInsets.symmetric(
|
||||||
|
vertical: ScreenAdaper.height(10),
|
||||||
|
horizontal: ScreenAdaper.width(10)),
|
||||||
|
hintText: '姓名',
|
||||||
|
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||||
|
prefixIcon: const Icon(Icons.search),
|
||||||
|
// 当searchBarController有值时不显示
|
||||||
|
suffixIcon: Obx(() => controller.searchKey.value.isEmpty
|
||||||
|
? const SizedBox()
|
||||||
|
: IconButton(
|
||||||
|
icon: const Icon(Icons.clear),
|
||||||
|
onPressed: () {
|
||||||
|
controller.searchKey.value = '';
|
||||||
|
controller.searchBarTextConroller.clear();
|
||||||
|
doSearch('');
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
))),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildList() {
|
||||||
|
final textStyle = TextStyle(fontSize: ScreenAdaper.sp(22));
|
||||||
|
return Obx(() => SmartRefresher(
|
||||||
|
enablePullDown: true,
|
||||||
|
enablePullUp: true,
|
||||||
|
controller: controller.refreshController,
|
||||||
|
onLoading: controller.onLoading,
|
||||||
|
onRefresh: controller.onRefresh,
|
||||||
|
child: controller.refreshController.isLoading
|
||||||
|
? SizedBox()
|
||||||
|
: controller.list.isEmpty
|
||||||
|
? Center(
|
||||||
|
child: Empty(text: '暂无数据'),
|
||||||
|
)
|
||||||
|
: ListView.separated(
|
||||||
|
separatorBuilder: (context, index) => Divider(
|
||||||
|
color: AppTheme.dividerColor,
|
||||||
|
),
|
||||||
|
itemCount: controller.list.length,
|
||||||
|
itemBuilder: (_, index) => buildItem(index))));
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildItem(int index) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: () => {
|
||||||
|
if (beforeSelectedCheck != null)
|
||||||
|
{
|
||||||
|
if (beforeSelectedCheck!(controller.list[index]))
|
||||||
|
{onSelected!(controller.list[index])}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{onSelected!(controller.list[index])}
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: ScreenAdaper.width(5),
|
||||||
|
vertical: ScreenAdaper.height(10)),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(ScreenAdaper.sp(15)),
|
||||||
|
child: FadeInCacheImage(
|
||||||
|
url: controller.list[index].avatar ?? '',
|
||||||
|
width: ScreenAdaper.width(60),
|
||||||
|
height: ScreenAdaper.width(60),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: ScreenAdaper.width(20),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'${controller.list[index].nickname}',
|
||||||
|
style: TextStyle(fontSize: ScreenAdaper.sp(25)),
|
||||||
|
),
|
||||||
|
if (controller.list[index].dept != null) ...[
|
||||||
|
SizedBox(
|
||||||
|
width: ScreenAdaper.width(20),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: ScreenAdaper.width(10),
|
||||||
|
vertical: ScreenAdaper.height(5)),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[300],
|
||||||
|
borderRadius: BorderRadius.circular(ScreenAdaper.sp(10))),
|
||||||
|
child: Text('${controller.list[index].dept?.name}'),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AgentSearchController extends GetxController {
|
||||||
|
RxList<UserInfoModel> list = RxList([]);
|
||||||
|
RxString searchKey = ''.obs;
|
||||||
|
final searchBarTextConroller = TextEditingController();
|
||||||
|
RefreshController refreshController = RefreshController(initialRefresh: true);
|
||||||
|
int page = 1;
|
||||||
|
int limit = 15;
|
||||||
|
int total = 0;
|
||||||
|
Future<List<UserInfoModel>> getData({bool isRefresh = false}) async {
|
||||||
|
if (isRefresh == true) {
|
||||||
|
page = 1;
|
||||||
|
} else {
|
||||||
|
page++;
|
||||||
|
}
|
||||||
|
final res = await Api.getUsers({
|
||||||
|
'page': page,
|
||||||
|
'pageSize': 15,
|
||||||
|
'keyword': searchKey.value,
|
||||||
|
});
|
||||||
|
List<UserInfoModel> newList =
|
||||||
|
res.data!.items.map((e) => UserInfoModel.fromJson(e)).toList();
|
||||||
|
isRefresh == true ? list.assignAll(newList) : list.addAll(newList);
|
||||||
|
|
||||||
|
return newList;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> onRefresh() async {
|
||||||
|
await getData(isRefresh: true).then((_) {
|
||||||
|
refreshController.refreshCompleted(resetFooterState: true);
|
||||||
|
}).catchError((_) {
|
||||||
|
refreshController.refreshFailed();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> onLoading() async {
|
||||||
|
await getData().then((_) {
|
||||||
|
if (_.isEmpty) {
|
||||||
|
refreshController.loadNoData();
|
||||||
|
} else {
|
||||||
|
refreshController.loadComplete();
|
||||||
|
}
|
||||||
|
}).catchError((_) {
|
||||||
|
refreshController.loadFailed();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,8 @@ import 'package:sk_base_mobile/constants/constants.dart';
|
||||||
import 'package:sk_base_mobile/constants/dict_enum.dart';
|
import 'package:sk_base_mobile/constants/dict_enum.dart';
|
||||||
import 'package:sk_base_mobile/models/index.dart';
|
import 'package:sk_base_mobile/models/index.dart';
|
||||||
import 'package:sk_base_mobile/models/inventory.model.dart';
|
import 'package:sk_base_mobile/models/inventory.model.dart';
|
||||||
|
import 'package:sk_base_mobile/models/user_info.model.dart';
|
||||||
|
import 'package:sk_base_mobile/screens/new_inventory_inout/components/agent_search.dart';
|
||||||
import 'package:sk_base_mobile/screens/new_inventory_inout/components/inventory_search.dart';
|
import 'package:sk_base_mobile/screens/new_inventory_inout/components/inventory_search.dart';
|
||||||
import 'package:sk_base_mobile/screens/new_inventory_inout/components/product_search.dart';
|
import 'package:sk_base_mobile/screens/new_inventory_inout/components/product_search.dart';
|
||||||
import 'package:sk_base_mobile/store/dict.store.dart';
|
import 'package:sk_base_mobile/store/dict.store.dart';
|
||||||
|
@ -287,11 +289,49 @@ class NewInventoryInout extends StatelessWidget {
|
||||||
|
|
||||||
/// 经办人
|
/// 经办人
|
||||||
Widget buildAgent() {
|
Widget buildAgent() {
|
||||||
return ZtTextInput(
|
return TextFormField(
|
||||||
textController: controller.agentTextController,
|
controller: controller.agentTextController,
|
||||||
labelText: '经办人',
|
decoration: InputDecoration(
|
||||||
isRequired: true,
|
hintText: '请选择经办人',
|
||||||
);
|
label: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"*",
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.red, fontSize: ScreenAdaper.sp(30)),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'经办人',
|
||||||
|
style: TextStyle(fontSize: ScreenAdaper.sp(30)),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
floatingLabelBehavior: FloatingLabelBehavior.always),
|
||||||
|
readOnly: true,
|
||||||
|
onTap: () {
|
||||||
|
if (inOrOut == InventoryInOrOutEnum.In) {
|
||||||
|
ModalUtil.showGeneralDialog(content: AgentSearch(
|
||||||
|
onSelected: (UserInfoModel userInfo) {
|
||||||
|
Get.back();
|
||||||
|
controller.payload['agent'] = userInfo.nickname;
|
||||||
|
controller.agentTextController.text = userInfo.nickname!;
|
||||||
|
},
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
ModalUtil.showGeneralDialog(
|
||||||
|
content: AgentSearch(
|
||||||
|
onSelected: (UserInfoModel userInfo) {
|
||||||
|
Get.back();
|
||||||
|
controller.payload['agent'] = userInfo.nickname;
|
||||||
|
controller.agentTextController.text =
|
||||||
|
userInfo.nickname!;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
width: Get.width - ScreenAdaper.width(50))
|
||||||
|
.then((value) => Get.delete<AgentSearchController>());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 备注
|
/// 备注
|
||||||
|
|
|
@ -95,7 +95,7 @@ class WorkBenchPage extends StatelessWidget {
|
||||||
Text(
|
Text(
|
||||||
works[index].title,
|
works[index].title,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
letterSpacing: ScreenAdaper.width(5),
|
letterSpacing: ScreenAdaper.width(10),
|
||||||
fontSize: ScreenAdaper.sp(40),
|
fontSize: ScreenAdaper.sp(40),
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
foreground: Paint()
|
foreground: Paint()
|
||||||
|
@ -106,7 +106,7 @@ class WorkBenchPage extends StatelessWidget {
|
||||||
Text(
|
Text(
|
||||||
works[index].title,
|
works[index].title,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
letterSpacing: ScreenAdaper.width(5),
|
letterSpacing: ScreenAdaper.width(10),
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: ScreenAdaper.sp(40),
|
fontSize: ScreenAdaper.sp(40),
|
||||||
fontWeight: FontWeight.bold),
|
fontWeight: FontWeight.bold),
|
||||||
|
|
|
@ -82,20 +82,20 @@ class AppInfoService extends GetxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> getAppConfig() async {
|
Future<void> getAppConfig() async {
|
||||||
if (StorageService.to.getString(CacheKeys.token, isWithUser: false) !=
|
// if (StorageService.to.getString(CacheKeys.token, isWithUser: false) !=
|
||||||
null) {
|
// null) {
|
||||||
final response = await Api.getAppConfig();
|
// final response = await Api.getAppConfig();
|
||||||
if (response.data != null) {
|
// if (response.data != null) {
|
||||||
appConfig = AppConfig.fromJson(response.data['data']);
|
// appConfig = AppConfig.fromJson(response.data['data']);
|
||||||
await StorageService.to.setString(
|
// await StorageService.to.setString(
|
||||||
CacheKeys.appConfig, jsonEncode(appConfig.items!),
|
// CacheKeys.appConfig, jsonEncode(appConfig.items!),
|
||||||
isWithUser: false);
|
// isWithUser: false);
|
||||||
if (appConfig.ver != null) {
|
// if (appConfig.ver != null) {
|
||||||
await StorageService.to
|
// await StorageService.to
|
||||||
.setString(CacheKeys.ver, appConfig.ver!, isWithUser: false);
|
// .setString(CacheKeys.ver, appConfig.ver!, isWithUser: false);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// need token
|
// need token
|
||||||
|
|
|
@ -16,7 +16,7 @@ class DioService extends Get.GetxService {
|
||||||
static late Dio _dio;
|
static late Dio _dio;
|
||||||
List<String> whiteList = [Urls.login];
|
List<String> whiteList = [Urls.login];
|
||||||
BaseOptions dioBaseOptions = BaseOptions(
|
BaseOptions dioBaseOptions = BaseOptions(
|
||||||
connectTimeout: const Duration(seconds: 20),
|
connectTimeout: const Duration(seconds: GloablConfig.DIO_TIMEOUT),
|
||||||
baseUrl: '${GloablConfig.BASE_URL}',
|
baseUrl: '${GloablConfig.BASE_URL}',
|
||||||
followRedirects: true);
|
followRedirects: true);
|
||||||
|
|
||||||
|
@ -62,10 +62,10 @@ class DioService extends Get.GetxService {
|
||||||
e.response?.data['message'],
|
e.response?.data['message'],
|
||||||
);
|
);
|
||||||
} else if (e.response?.statusCode == 401) {
|
} else if (e.response?.statusCode == 401) {
|
||||||
await SnackBarUtil().error('请重新登录');
|
|
||||||
// dio.lock();
|
// dio.lock();
|
||||||
LoggerUtil().error('[Service-dio] logout:${e.response}');
|
LoggerUtil().error('[Service-dio] logout:${e.response}');
|
||||||
await AuthStore().logout(force: true);
|
await AuthStore().logout(force: true);
|
||||||
|
SnackBarUtil().error('请重新登录');
|
||||||
} else if (e.response?.statusCode == 403) {
|
} else if (e.response?.statusCode == 403) {
|
||||||
await SnackBarUtil().error(
|
await SnackBarUtil().error(
|
||||||
'${e.response?.data['message']}.',
|
'${e.response?.data['message']}.',
|
||||||
|
|
|
@ -25,7 +25,7 @@ class AuthStore extends GetxService {
|
||||||
|
|
||||||
if (token != null) {
|
if (token != null) {
|
||||||
if (preUserInfo != null) {
|
if (preUserInfo != null) {
|
||||||
userInfo(UserInfoModel.fromJson(jsonDecode(preUserInfo)));
|
await getUserInfo();
|
||||||
LoggerUtil().info('[Store-Auth] userId: ${userInfo.value.id}');
|
LoggerUtil().info('[Store-Auth] userId: ${userInfo.value.id}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,19 +56,11 @@ class AuthStore extends GetxService {
|
||||||
Future<void> logout({bool force = false}) async {
|
Future<void> logout({bool force = false}) async {
|
||||||
await StorageService.to.remove(CacheKeys.token, isWithUser: false);
|
await StorageService.to.remove(CacheKeys.token, isWithUser: false);
|
||||||
await StorageService.to.remove(CacheKeys.userInfo, isWithUser: false);
|
await StorageService.to.remove(CacheKeys.userInfo, isWithUser: false);
|
||||||
try {
|
|
||||||
// final response = await Api.logout();
|
|
||||||
// if (response.data != null) {
|
|
||||||
LoggerUtil().info('[Store-Auth] Logout succeed.');
|
LoggerUtil().info('[Store-Auth] Logout succeed.');
|
||||||
// 如果当前已经在login界面 不需要跳转
|
// 如果当前已经在login界面 不需要跳转
|
||||||
if (Get.currentRoute != RouteConfig.login) {
|
if (Get.currentRoute != RouteConfig.login) {
|
||||||
Get.offAllNamed(RouteConfig.login);
|
Get.offAllNamed(RouteConfig.login);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
print(e);
|
|
||||||
} finally {
|
|
||||||
LoadingUtil.to.dismiss();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> login(
|
Future<void> login(
|
||||||
|
@ -94,11 +86,11 @@ class AuthStore extends GetxService {
|
||||||
.setString(CacheKeys.token, auth.token!, isWithUser: false);
|
.setString(CacheKeys.token, auth.token!, isWithUser: false);
|
||||||
}
|
}
|
||||||
await getUserInfo();
|
await getUserInfo();
|
||||||
|
await getCommonInfo();
|
||||||
Get.offNamed(RouteConfig.home);
|
Get.offNamed(RouteConfig.home);
|
||||||
getCommonInfo();
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await SnackBarUtil().error('账号密码错误');
|
await SnackBarUtil().error('账号密码错误$e');
|
||||||
LoggerUtil().error(e);
|
LoggerUtil().error(e);
|
||||||
} finally {
|
} finally {
|
||||||
LoadingUtil.to.dismiss();
|
LoadingUtil.to.dismiss();
|
||||||
|
@ -112,7 +104,6 @@ class AuthStore extends GetxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> getUserInfo() async {
|
Future<void> getUserInfo() async {
|
||||||
await LoadingUtil.to.show();
|
|
||||||
try {
|
try {
|
||||||
final response = await Api.getUserInfo();
|
final response = await Api.getUserInfo();
|
||||||
if (response.data != null) {
|
if (response.data != null) {
|
||||||
|
@ -121,9 +112,7 @@ class AuthStore extends GetxService {
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
SnackBarUtil().error('$e');
|
SnackBarUtil().error('$e');
|
||||||
} finally {
|
} finally {}
|
||||||
LoadingUtil.to.dismiss();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> saveUserInfo(Map<String, dynamic> data) async {
|
Future<void> saveUserInfo(Map<String, dynamic> data) async {
|
||||||
|
|
|
@ -42,12 +42,7 @@ class _FadeInCacheImageState extends State<FadeInCacheImage> {
|
||||||
theContext = context;
|
theContext = context;
|
||||||
|
|
||||||
if ((widget.url == null || widget.url == '' || widget.url == 'null')) {
|
if ((widget.url == null || widget.url == '' || widget.url == 'null')) {
|
||||||
return SizedBox(
|
return defaultImg();
|
||||||
width: widget.width,
|
|
||||||
height: widget.height,
|
|
||||||
child: Icon(Icons.image_not_supported,
|
|
||||||
size: ScreenAdaper.sp(100), color: AppTheme.grey),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildImg(widget.url);
|
return buildImg(widget.url);
|
||||||
|
@ -68,12 +63,20 @@ class _FadeInCacheImageState extends State<FadeInCacheImage> {
|
||||||
decoration: const BoxDecoration(color: AppTheme.grey),
|
decoration: const BoxDecoration(color: AppTheme.grey),
|
||||||
child: const CupertinoActivityIndicator(),
|
child: const CupertinoActivityIndicator(),
|
||||||
),
|
),
|
||||||
errorWidget: (context, error, stackTrace) => SizedBox(
|
errorWidget: (context, error, stackTrace) => defaultImg(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget defaultImg() {
|
||||||
|
return Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(), borderRadius: BorderRadius.circular(15)),
|
||||||
width: widget.width,
|
width: widget.width,
|
||||||
height: widget.height,
|
height: widget.height,
|
||||||
child: Icon(Icons.image_not_supported,
|
child: Icon(Icons.image_not_supported,
|
||||||
size: ScreenAdaper.sp(100), color: AppTheme.grey),
|
size: ScreenAdaper.sp((widget.width ?? 200) * 3 / 4),
|
||||||
),
|
color: AppTheme.grey),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import 'package:sk_base_mobile/util/loading_util.dart';
|
||||||
import 'package:sk_base_mobile/util/media_util.dart';
|
import 'package:sk_base_mobile/util/media_util.dart';
|
||||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||||
import 'package:sk_base_mobile/util/snack_bar.util.dart';
|
import 'package:sk_base_mobile/util/snack_bar.util.dart';
|
||||||
import 'package:sk_base_mobile/widgets/fade_in_cache_image.dart';
|
|
||||||
import 'package:sk_base_mobile/widgets/loading_indicator.dart';
|
import 'package:sk_base_mobile/widgets/loading_indicator.dart';
|
||||||
|
|
||||||
class ImagePreivew extends StatefulWidget {
|
class ImagePreivew extends StatefulWidget {
|
||||||
|
|
16
pubspec.lock
|
@ -181,10 +181,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: dio
|
name: dio
|
||||||
sha256: "49af28382aefc53562459104f64d16b9dfd1e8ef68c862d5af436cc8356ce5a8"
|
sha256: "50fec96118958b97c727d0d8f67255d3683f16cc1f90d9bc917b5d4fe3abeca9"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.4.1"
|
version: "5.4.2"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -330,10 +330,10 @@ packages:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: flutter_lints
|
name: flutter_lints
|
||||||
sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04
|
sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.3"
|
version: "3.0.2"
|
||||||
flutter_native_splash:
|
flutter_native_splash:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
@ -516,10 +516,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: lints
|
name: lints
|
||||||
sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
|
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "3.0.0"
|
||||||
loading_animation_widget:
|
loading_animation_widget:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -652,10 +652,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_apple
|
name: permission_handler_apple
|
||||||
sha256: bdafc6db74253abb63907f4e357302e6bb786ab41465e8635f362ee71fd8707b
|
sha256: e9ad66020b89ff1b63908f247c2c6f931c6e62699b756ef8b3c4569350cd8662
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.4.0"
|
version: "9.4.4"
|
||||||
permission_handler_html:
|
permission_handler_html:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
16
pubspec.yaml
|
@ -62,6 +62,7 @@ dependencies:
|
||||||
image_gallery_saver: ^2.0.3
|
image_gallery_saver: ^2.0.3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
@ -71,11 +72,24 @@ dev_dependencies:
|
||||||
# activated in the `analysis_options.yaml` file located at the root of your
|
# activated in the `analysis_options.yaml` file located at the root of your
|
||||||
# package. See that file for information about deactivating specific lint
|
# package. See that file for information about deactivating specific lint
|
||||||
# rules and activating additional ones.
|
# rules and activating additional ones.
|
||||||
flutter_lints: ^2.0.0
|
flutter_lints: ^3.0.2
|
||||||
flutter_launcher_icons: ^0.13.1
|
flutter_launcher_icons: ^0.13.1
|
||||||
flutter_native_splash: ^2.3.11
|
flutter_native_splash: ^2.3.11
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
|
||||||
|
flutter_native_splash:
|
||||||
|
background_image: 'assets/images/launch_image.jpg'
|
||||||
|
android: true
|
||||||
|
ios: true
|
||||||
|
android_gravity: scaleAspectFill
|
||||||
|
ios_content_mode: scaleAspectFill
|
||||||
|
android_12:
|
||||||
|
image: assets/images/launch_image.jpg
|
||||||
|
icon_background_color: "#ffffff"
|
||||||
|
android_gravity: scaleAspectFill
|
||||||
|
ios_content_mode: scaleAspectFill
|
||||||
|
|
||||||
flutter_launcher_icons:
|
flutter_launcher_icons:
|
||||||
android: 'launcher_icon'
|
android: 'launcher_icon'
|
||||||
ios: true
|
ios: true
|
||||||
|
|
100
web/index.html
|
@ -1,6 +1,4 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html><html><head>
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!--
|
<!--
|
||||||
If you are serving your web app in a path other than the root, change the
|
If you are serving your web app in a path other than the root, change the
|
||||||
href value below to reflect the base path you are serving from.
|
href value below to reflect the base path you are serving from.
|
||||||
|
@ -27,7 +25,7 @@
|
||||||
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||||||
|
|
||||||
<!-- Favicon -->
|
<!-- Favicon -->
|
||||||
<link rel="icon" type="image/png" href="favicon.png"/>
|
<link rel="icon" type="image/png" href="favicon.png">
|
||||||
|
|
||||||
<title>sk_base_mobile</title>
|
<title>sk_base_mobile</title>
|
||||||
<link rel="manifest" href="manifest.json">
|
<link rel="manifest" href="manifest.json">
|
||||||
|
@ -37,7 +35,94 @@
|
||||||
const serviceWorkerVersion = null;
|
const serviceWorkerVersion = null;
|
||||||
</script>
|
</script>
|
||||||
<!-- This script adds the flutter initialization JS code -->
|
<!-- This script adds the flutter initialization JS code -->
|
||||||
<script src="flutter.js" defer></script>
|
<script src="flutter.js" defer=""></script>
|
||||||
|
|
||||||
|
|
||||||
|
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<style id="splash-screen-style">
|
||||||
|
html {
|
||||||
|
height: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
min-height: 100%;
|
||||||
|
background-color: #ffffff;
|
||||||
|
background-image: url("splash/img/light-background.png");
|
||||||
|
background-size: 100% 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
margin: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
-ms-transform: translate(-50%, -50%);
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contain {
|
||||||
|
display:block;
|
||||||
|
width:100%; height:100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stretch {
|
||||||
|
display:block;
|
||||||
|
width:100%; height:100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover {
|
||||||
|
display:block;
|
||||||
|
width:100%; height:100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
-ms-transform: translate(-50%, 0);
|
||||||
|
transform: translate(-50%, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottomLeft {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottomRight {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script id="splash-screen-script">
|
||||||
|
function removeSplashFromWeb() {
|
||||||
|
document.getElementById("splash")?.remove();
|
||||||
|
document.getElementById("splash-branding")?.remove();
|
||||||
|
document.body.style.background = "transparent";
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script>
|
||||||
|
@ -55,5 +140,6 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
</body></html>
|
After Width: | Height: | Size: 121 KiB |