feat: inventory inout TIME
This commit is contained in:
parent
322368339f
commit
11df20c98e
|
@ -15,6 +15,11 @@ class Api {
|
|||
);
|
||||
}
|
||||
|
||||
/// 获取权限资源
|
||||
static Future<Response> getResources() {
|
||||
return DioService.dio.get(Urls.accountResources);
|
||||
}
|
||||
|
||||
/// 获取分页角色列表
|
||||
static Future<Response<PaginationData>> getRoles(Map params) {
|
||||
return DioService.dio.get<PaginationData>(Urls.roles,
|
||||
|
|
|
@ -27,7 +27,7 @@ class AppTheme {
|
|||
static const Color dividerColor = Color.fromARGB(255, 224, 224, 224);
|
||||
static const Color appbarBgColor = AppTheme.primaryColor;
|
||||
static const Color scaffoldBackgroundColor = Color(0XFFe9f0fd);
|
||||
static const Color inputFillColor = Color(0xFFf5f8ff);
|
||||
static const Color inputFillColor = Color(0xfffefefe);
|
||||
}
|
||||
|
||||
final theme = ThemeData(
|
||||
|
@ -48,17 +48,29 @@ final theme = ThemeData(
|
|||
fontFamily: AppTheme.fontName,
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
style: ButtonStyle(
|
||||
textStyle: MaterialStateProperty.all<TextStyle>(TextStyle(
|
||||
fontSize: ScreenAdaper.height(26),
|
||||
)), // 设置文本样式为白色
|
||||
foregroundColor:
|
||||
MaterialStateProperty.all<Color>(AppTheme.primaryColor), // 设置文本颜色为红色
|
||||
)),
|
||||
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
||||
floatingActionButtonTheme: const FloatingActionButtonThemeData(
|
||||
backgroundColor: AppTheme.primaryColorLight,
|
||||
),
|
||||
dialogTheme: const DialogTheme(
|
||||
elevation: 0.2,
|
||||
backgroundColor: AppTheme.nearlyWhite,
|
||||
),
|
||||
dialogBackgroundColor: AppTheme.nearlyWhite,
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
onPrimary: AppTheme.nearlyWhite,
|
||||
seedColor: AppTheme.primaryColor,
|
||||
primary: AppTheme.primaryColor),
|
||||
datePickerTheme: DatePickerThemeData(
|
||||
confirmButtonStyle: ButtonStyle(
|
||||
textStyle: MaterialStateProperty.resolveWith<TextStyle?>(
|
||||
(Set<MaterialState> states) {
|
||||
return const TextStyle(color: AppTheme.primaryColor);
|
||||
return TextStyle(color: AppTheme.primaryColor);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -84,6 +96,7 @@ final theme = ThemeData(
|
|||
visualDensity: VisualDensity.adaptivePlatformDensity,
|
||||
primaryColor: AppTheme.primaryColor,
|
||||
primaryColorDark: AppTheme.primaryColorDark,
|
||||
textTheme: TextTheme(bodySmall: TextStyle(fontSize: ScreenAdaper.height(26))),
|
||||
progressIndicatorTheme:
|
||||
const ProgressIndicatorThemeData(color: AppTheme.primaryColor),
|
||||
dividerColor: AppTheme.dividerColor,
|
||||
|
|
|
@ -14,7 +14,7 @@ class Urls {
|
|||
static String getDictType = 'system/dict-type/all';
|
||||
static String uploadAttachemnt = 'tools/upload';
|
||||
static String systemParamConfig = 'system/param-config';
|
||||
static String accountMenus = 'account/menus';
|
||||
static String accountResources = 'account/menus';
|
||||
static String depts = 'system/depts';
|
||||
static String roles = 'system/roles';
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@ class RouteConfig {
|
|||
static const String login = '/login';
|
||||
static const String userinfo = '/userinfo';
|
||||
static const String inventory = '/inventory';
|
||||
static const String saleQuotation = '/sale_quotation';
|
||||
static const String hrManage = '/hr_manage';
|
||||
static const String saleQuotation = '/workbench/sale_quotation';
|
||||
static const String hrManage = '/workbench/hr_manage';
|
||||
static const String employeeDetail = '/employee_detail';
|
||||
|
||||
static final List<GetPage> getPages = [
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sk_base_mobile/store/dict.store.dart';
|
||||
import 'package:sk_base_mobile/store/resource.store.dart';
|
||||
import 'package:sk_base_mobile/util/loading_util.dart';
|
||||
import 'package:timeago/timeago.dart' as timeago;
|
||||
import 'package:sk_base_mobile/constants/cache_key.dart';
|
||||
|
@ -48,6 +49,9 @@ class Global {
|
|||
/// 依赖注入字典信息
|
||||
await Get.putAsync<DictService>(() => DictService().init());
|
||||
|
||||
/// 依赖注入资源信息
|
||||
await Get.putAsync<ResourceService>(() => ResourceService().init());
|
||||
|
||||
if (StorageService.to.getString(CacheKeys.token, isWithUser: false) !=
|
||||
null) {
|
||||
/// 这里做一些缓存初始化后的操作
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:sk_base_mobile/config.dart';
|
||||
|
@ -31,7 +32,16 @@ class IndexPage extends StatelessWidget {
|
|||
maxOverScrollExtent: 80,
|
||||
footerTriggerDistance: 150,
|
||||
child: GetMaterialApp(
|
||||
theme: theme,
|
||||
locale: const Locale('zh', 'CN'), // 设置为中文
|
||||
localizationsDelegates: const [
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate, // 添加这一行
|
||||
],
|
||||
supportedLocales: const [
|
||||
Locale('zh', 'CN'), // 支持的语言
|
||||
],
|
||||
theme: _getAppTheme(),
|
||||
title: GloablConfig.DOMAIN_NAME,
|
||||
getPages: RouteConfig.getPages,
|
||||
initialRoute: getInitialRoute(),
|
||||
|
@ -55,4 +65,8 @@ class IndexPage extends StatelessWidget {
|
|||
bool isLogined = token != null;
|
||||
return isLogined ? RouteConfig.home : RouteConfig.login;
|
||||
}
|
||||
|
||||
ThemeData _getAppTheme() {
|
||||
return theme;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
class ResourceModel {
|
||||
ResourceModel({
|
||||
required this.id,
|
||||
required this.path,
|
||||
required this.component,
|
||||
required this.name,
|
||||
required this.meta,
|
||||
required this.redirect,
|
||||
required this.children,
|
||||
});
|
||||
|
||||
final int? id;
|
||||
final String? path;
|
||||
final String? component;
|
||||
final String? name;
|
||||
final Meta? meta;
|
||||
final String? redirect;
|
||||
final List<ResourceModel> children;
|
||||
|
||||
factory ResourceModel.fromJson(Map<String, dynamic> json) {
|
||||
return ResourceModel(
|
||||
id: json["id"],
|
||||
path: json["path"],
|
||||
component: json["component"],
|
||||
name: json["name"],
|
||||
meta: json["meta"] == null ? null : Meta.fromJson(json["meta"]),
|
||||
redirect: json["redirect"],
|
||||
children: json["children"] == null
|
||||
? []
|
||||
: List<ResourceModel>.from(
|
||||
json["children"]!.map((x) => ResourceModel.fromJson(x))),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"id": id,
|
||||
"path": path,
|
||||
"component": component,
|
||||
"name": name,
|
||||
"meta": meta?.toJson(),
|
||||
"redirect": redirect,
|
||||
"children": children.map((x) => x?.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
class Meta {
|
||||
Meta({
|
||||
required this.title,
|
||||
required this.icon,
|
||||
required this.isExt,
|
||||
required this.extOpenMode,
|
||||
required this.type,
|
||||
required this.orderNo,
|
||||
required this.show,
|
||||
required this.activeMenu,
|
||||
required this.status,
|
||||
required this.keepAlive,
|
||||
});
|
||||
|
||||
final String? title;
|
||||
final String? icon;
|
||||
final bool? isExt;
|
||||
final int? extOpenMode;
|
||||
final int? type;
|
||||
final int? orderNo;
|
||||
final int? show;
|
||||
final String? activeMenu;
|
||||
final int? status;
|
||||
final int? keepAlive;
|
||||
|
||||
factory Meta.fromJson(Map<String, dynamic> json) {
|
||||
return Meta(
|
||||
title: json["title"],
|
||||
icon: json["icon"],
|
||||
isExt: json["isExt"],
|
||||
extOpenMode: json["extOpenMode"],
|
||||
type: json["type"],
|
||||
orderNo: json["orderNo"],
|
||||
show: json["show"],
|
||||
activeMenu: json["activeMenu"],
|
||||
status: json["status"],
|
||||
keepAlive: json["keepAlive"],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"title": title,
|
||||
"icon": icon,
|
||||
"isExt": isExt,
|
||||
"extOpenMode": extOpenMode,
|
||||
"type": type,
|
||||
"orderNo": orderNo,
|
||||
"show": show,
|
||||
"activeMenu": activeMenu,
|
||||
"status": status,
|
||||
"keepAlive": keepAlive,
|
||||
};
|
||||
}
|
|
@ -194,7 +194,7 @@ class EditUserInfo extends StatelessWidget {
|
|||
image: controller.filePath.value.isNotEmpty
|
||||
? FileImage(File(controller.filePath.value))
|
||||
: NetworkImage(MediaUtil.getMediaUrl(
|
||||
controller.userInfo.value!.avatar!))
|
||||
controller.userInfo.value.avatar))
|
||||
as ImageProvider<Object>),
|
||||
)),
|
||||
),
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'package:sk_base_mobile/constants/bg_color.dart';
|
|||
import 'package:sk_base_mobile/models/user_info.model.dart';
|
||||
import 'package:sk_base_mobile/screens/inventory_inout/components/responsive.dart';
|
||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_avatar.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_tag.dart';
|
||||
import 'package:sk_base_mobile/widgets/fade_in_cache_image.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_appbar.dart';
|
||||
|
@ -44,13 +45,7 @@ class EmployeeDetail extends StatelessWidget {
|
|||
color: AppTheme.white,
|
||||
child: Row(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(30)),
|
||||
child: FadeInCacheImage(
|
||||
height: ScreenAdaper.height(80),
|
||||
width: ScreenAdaper.height(80),
|
||||
url: '${GloablConfig.OSS_URL}${userInfo.avatar}'),
|
||||
),
|
||||
SkAvatar(url: userInfo.avatar),
|
||||
SizedBox(
|
||||
width: ScreenAdaper.width(defaultPadding),
|
||||
),
|
||||
|
|
|
@ -13,8 +13,10 @@ import 'package:sk_base_mobile/util/debouncer.dart';
|
|||
import 'package:sk_base_mobile/util/device.util.dart';
|
||||
import 'package:sk_base_mobile/util/media_util.dart';
|
||||
import 'package:sk_base_mobile/util/modal.util.dart';
|
||||
import 'package:sk_base_mobile/util/router.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/widgets/core/sk_avatar.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_ink.dart';
|
||||
import 'package:sk_base_mobile/widgets/core/sk_tag.dart';
|
||||
import 'package:sk_base_mobile/widgets/form_item/sk_text_input.dart';
|
||||
|
@ -149,7 +151,7 @@ class HrManagePage extends StatelessWidget {
|
|||
Widget buildUserCard(int index) {
|
||||
return SkInk(
|
||||
onTap: () {
|
||||
Get.toNamed(RouteConfig.employeeDetail,
|
||||
RouterUtil.toNamed(RouteConfig.employeeDetail,
|
||||
arguments: controller.list[index]);
|
||||
},
|
||||
margin: EdgeInsets.only(bottom: ScreenAdaper.height(defaultPadding)),
|
||||
|
@ -163,14 +165,7 @@ class HrManagePage extends StatelessWidget {
|
|||
Row(
|
||||
children: [
|
||||
// 头像
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(30)),
|
||||
child: FadeInCacheImage(
|
||||
height: ScreenAdaper.height(80),
|
||||
width: ScreenAdaper.height(80),
|
||||
url:
|
||||
MediaUtil.getMediaUrl(controller.list[index].avatar)),
|
||||
),
|
||||
SkAvatar(url: controller.list[index].avatar),
|
||||
SizedBox(
|
||||
width: ScreenAdaper.height(defaultPadding),
|
||||
),
|
||||
|
|
|
@ -13,6 +13,7 @@ import 'package:sk_base_mobile/screens/new_inventory_inout/components/inventory_
|
|||
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/util/util.dart';
|
||||
import 'package:sk_base_mobile/widgets/form_item/sk_datetime_picker.dart';
|
||||
import 'package:sk_base_mobile/widgets/form_item/sk_number_input.dart';
|
||||
import 'package:sk_base_mobile/widgets/form_item/sk_search_select.dart';
|
||||
import 'package:sk_base_mobile/widgets/form_item/sk_date_picker.dart';
|
||||
|
@ -75,28 +76,35 @@ class NewInventoryInout extends StatelessWidget {
|
|||
SizedBox(
|
||||
height: ScreenAdaper.height(formVerticalGap),
|
||||
),
|
||||
if (inOrOut == InventoryInOrOutEnum.In) ...[
|
||||
Row(
|
||||
children: [
|
||||
if (inOrOut == InventoryInOrOutEnum.In) ...[
|
||||
Expanded(flex: 1, child: buildUnitPrice()),
|
||||
SizedBox(
|
||||
width: ScreenAdaper.width(formHorizontalGap),
|
||||
),
|
||||
Expanded(flex: 1, child: buildAmount())
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: ScreenAdaper.height(formVerticalGap),
|
||||
),
|
||||
],
|
||||
if (inOrOut == InventoryInOrOutEnum.In) ...[
|
||||
Row(
|
||||
children: [
|
||||
Expanded(child: buildDatePicker()),
|
||||
SizedBox(
|
||||
width: ScreenAdaper.width(formHorizontalGap),
|
||||
),
|
||||
Expanded(child: buildAgent()),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: ScreenAdaper.height(formVerticalGap),
|
||||
),
|
||||
// buildDatePicker(),
|
||||
// SizedBox(
|
||||
// height: ScreenAdaper.height(formVerticalGap),
|
||||
// ),
|
||||
buildAgent(),
|
||||
SizedBox(
|
||||
height: ScreenAdaper.height(formVerticalGap),
|
||||
),
|
||||
],
|
||||
if (inOrOut == InventoryInOrOutEnum.Out) buildAgent(),
|
||||
if (inOrOut == InventoryInOrOutEnum.In) buildPositionBottomPicker(),
|
||||
SizedBox(
|
||||
height: ScreenAdaper.height(formVerticalGap),
|
||||
|
@ -281,15 +289,16 @@ class NewInventoryInout extends StatelessWidget {
|
|||
|
||||
/// 时间
|
||||
Widget buildDatePicker() {
|
||||
return SkDatePicker(
|
||||
return SkDateTimePicker(
|
||||
initialDate: DateTime.tryParse('${controller.payload['time'] ?? ''}'),
|
||||
textController: controller.dateTextController,
|
||||
onClear: () {
|
||||
controller.payload.remove('time');
|
||||
},
|
||||
onDateSelected: (date) {
|
||||
onSelected: (date) {
|
||||
if (date != null) {
|
||||
controller.dateTextController.text = SkDateUtil.format(date);
|
||||
controller.payload['time'] = controller.dateTextController.text;
|
||||
controller.payload['time'] = date.millisecondsSinceEpoch;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
|
@ -75,7 +75,7 @@ class NewInventoryInoutController extends GetxController {
|
|||
onReady() {
|
||||
super.onReady();
|
||||
dateTextController.text = SkDateUtil.format(DateTime.now());
|
||||
payload['time'] = SkDateUtil.format(DateTime.now());
|
||||
payload['time'] = DateTime.now().microsecondsSinceEpoch;
|
||||
payload['inOrOut'] = inOrOut;
|
||||
}
|
||||
|
||||
|
@ -128,29 +128,8 @@ class NewInventoryInoutController extends GetxController {
|
|||
);
|
||||
return;
|
||||
}
|
||||
// 暂时时间定位提交时间
|
||||
// if (payload['time'] == null) {
|
||||
// SnackBarUtil().error(
|
||||
// '时间不能为空',
|
||||
// );
|
||||
// return;
|
||||
// }
|
||||
|
||||
payload['time'] = SkDateUtil.format(DateTime.now(), formats: [
|
||||
'yyyy',
|
||||
'-',
|
||||
'mm',
|
||||
'-',
|
||||
'dd',
|
||||
' ',
|
||||
'HH',
|
||||
':',
|
||||
'nn',
|
||||
":",
|
||||
'ss'
|
||||
]);
|
||||
payload['quantity'] = quantityTextController.text;
|
||||
|
||||
if (payload['quantity'].isEmpty || payload['quantity'] == '0') {
|
||||
SnackBarUtil().error(
|
||||
'数量必须大于1',
|
||||
|
@ -186,11 +165,10 @@ class NewInventoryInoutController extends GetxController {
|
|||
} else {
|
||||
payload['amount'] = amountTextController.text;
|
||||
}
|
||||
|
||||
payload['time'] = payload['time'] ?? DateTime.now().microsecondsSinceEpoch;
|
||||
payload['remark'] = remarkTextController.text;
|
||||
await LoadingUtil.to.show(status: '提交中请稍后...');
|
||||
// uploadImgFilesPath
|
||||
|
||||
try {
|
||||
// final recordId = res.data as int;
|
||||
// 批量同时上传
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:get/get.dart';
|
||||
import 'package:sk_base_mobile/constants/constants.dart';
|
||||
import 'package:sk_base_mobile/models/workbench.model.dart';
|
||||
|
||||
class WorkBenchController extends GetxController {
|
||||
|
@ -6,11 +7,13 @@ class WorkBenchController extends GetxController {
|
|||
WorkBenchModel(title: '库存', route: '/inventory', icon: 'inventory.svg'),
|
||||
WorkBenchModel(title: '产品', route: '/product', icon: 'product.svg'),
|
||||
WorkBenchModel(title: '合同', route: '/contract', icon: 'contract.svg'),
|
||||
WorkBenchModel(title: '人事', route: '/hr_manage', icon: 'hr.svg'),
|
||||
WorkBenchModel(title: '人事', route: RouteConfig.hrManage, icon: 'hr.svg'),
|
||||
WorkBenchModel(title: '公车', route: '/vehicle', icon: 'vehicle.svg'),
|
||||
WorkBenchModel(title: '任务', route: '/task_manage', icon: 'task_manage.svg'),
|
||||
WorkBenchModel(title: '报表', route: '/report', icon: 'report.svg'),
|
||||
WorkBenchModel(
|
||||
title: '报价计算', route: '/sale_quotation', icon: 'sale_quotation.svg'),
|
||||
title: '报价计算',
|
||||
route: RouteConfig.saleQuotation,
|
||||
icon: 'sale_quotation.svg'),
|
||||
];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
import 'package:get/get.dart';
|
||||
import 'package:sk_base_mobile/apis/api.dart';
|
||||
import 'package:sk_base_mobile/models/resource.model.dart';
|
||||
import 'package:sk_base_mobile/store/auth.store.dart';
|
||||
import 'package:sk_base_mobile/util/logger_util.dart';
|
||||
|
||||
class ResourceService extends GetxService {
|
||||
static ResourceService get to => Get.find();
|
||||
Future<ResourceService> init() async {
|
||||
if (AuthStore.to.userInfo.value.id == null) return this;
|
||||
|
||||
await getResources();
|
||||
return this;
|
||||
}
|
||||
|
||||
RxList<ResourceModel> resources = RxList([]);
|
||||
Future<void> getResources() async {
|
||||
try {
|
||||
final response = await Api.getResources();
|
||||
resources.value = (response.data as List)
|
||||
.map((item) => ResourceModel.fromJson(item))
|
||||
.toList();
|
||||
} catch (e) {
|
||||
LoggerUtil().error('getResources error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// List<DictItemModel> getDictItemsByCode(String code) {
|
||||
// return dictTypes.firstWhereOrNull((item) => item.code == code)?.dictItems ??
|
||||
// [];
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class RouterUtil {
|
||||
static Future<T?> toNamed<T>(String routeName, {arguments}) async {
|
||||
//关闭键盘
|
||||
if (Get.context != null) {
|
||||
FocusScope.of(Get.context!).requestFocus(FocusNode());
|
||||
}
|
||||
return await Get.toNamed<T?>(routeName, arguments: arguments);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:sk_base_mobile/app_theme.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/widgets/fade_in_cache_image.dart';
|
||||
|
||||
class SkAvatar extends StatelessWidget {
|
||||
final String? url;
|
||||
const SkAvatar({super.key, this.url});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(40)),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: AppTheme.dividerColor),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(40))),
|
||||
child: FadeInCacheImage(
|
||||
defaultWidget: Icon(Icons.person_2_outlined,
|
||||
size: ScreenAdaper.height(60), color: AppTheme.grey),
|
||||
height: ScreenAdaper.height(80),
|
||||
width: ScreenAdaper.height(80),
|
||||
url: MediaUtil.getMediaUrl(url)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -11,11 +11,13 @@ class FadeInCacheImage extends StatefulWidget {
|
|||
final BoxFit? fit;
|
||||
final bool compress;
|
||||
final bool canFullscreen;
|
||||
final Widget? defaultWidget;
|
||||
const FadeInCacheImage(
|
||||
{super.key,
|
||||
this.width,
|
||||
this.height,
|
||||
this.url,
|
||||
this.defaultWidget,
|
||||
this.fit = BoxFit.cover,
|
||||
this.compress = false,
|
||||
this.canFullscreen = false});
|
||||
|
@ -78,7 +80,8 @@ class _FadeInCacheImageState extends State<FadeInCacheImage> {
|
|||
alignment: Alignment.center,
|
||||
width: widget.width,
|
||||
height: widget.height,
|
||||
child: Icon(Icons.image_not_supported,
|
||||
child: widget.defaultWidget ??
|
||||
Icon(Icons.image_not_supported,
|
||||
size: ScreenAdaper.height((widget.width ?? 200)),
|
||||
color: AppTheme.grey),
|
||||
);
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:sk_base_mobile/app_theme.dart';
|
||||
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||
import 'package:sk_datetime_picker/sk_datetime_picker.dart';
|
||||
|
||||
class SkDateTimePicker extends StatelessWidget {
|
||||
final TextEditingController textController;
|
||||
final VoidCallback? onClear;
|
||||
final Function(DateTime?)? onSelected;
|
||||
final bool isRequired;
|
||||
final String labelText;
|
||||
final DateTime? initialDate;
|
||||
const SkDateTimePicker({
|
||||
super.key,
|
||||
this.onClear,
|
||||
this.onSelected,
|
||||
this.initialDate,
|
||||
this.labelText = '日期',
|
||||
this.isRequired = false,
|
||||
required this.textController,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextFormField(
|
||||
controller: textController,
|
||||
onTapOutside: (event) {
|
||||
FocusScope.of(context).unfocus();
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||
prefixIcon: Icon(
|
||||
Icons.date_range_outlined,
|
||||
size: ScreenAdaper.height(40),
|
||||
),
|
||||
suffixIcon: textController.text.isNotEmpty
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.clear),
|
||||
// 当点击这个按钮时,清除TextFormField的值
|
||||
onPressed: () {
|
||||
textController.clear();
|
||||
if (onClear != null) {
|
||||
onClear!();
|
||||
}
|
||||
},
|
||||
)
|
||||
: const SizedBox(),
|
||||
hintText: '请选择',
|
||||
label: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (isRequired)
|
||||
Text(
|
||||
"*",
|
||||
style: TextStyle(
|
||||
color: Colors.red, fontSize: ScreenAdaper.height(30)),
|
||||
),
|
||||
Text(
|
||||
labelText,
|
||||
style: TextStyle(fontSize: ScreenAdaper.height(30)),
|
||||
),
|
||||
])),
|
||||
keyboardType: TextInputType.none,
|
||||
onTap: () async {
|
||||
DateTime? dateTime = await showSkDateTimePicker(
|
||||
theme: theme,
|
||||
is24HourMode: true,
|
||||
title: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: ScreenAdaper.height(10)),
|
||||
child: Text(
|
||||
'选择日期时间',
|
||||
style: TextStyle(fontSize: ScreenAdaper.height(30)),
|
||||
),
|
||||
),
|
||||
context: context,
|
||||
initialDate: initialDate ?? DateTime.now(),
|
||||
firstDate: DateTime(1600).subtract(const Duration(days: 3652)),
|
||||
lastDate: DateTime.now().add(
|
||||
const Duration(days: 3652),
|
||||
),
|
||||
isForce2Digits: true,
|
||||
isShowSeconds: false,
|
||||
minutesInterval: 1,
|
||||
secondsInterval: 1,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 350,
|
||||
maxHeight: 650,
|
||||
),
|
||||
transitionBuilder: (context, anim1, anim2, child) {
|
||||
return FadeTransition(
|
||||
opacity: anim1.drive(
|
||||
Tween(
|
||||
begin: 0,
|
||||
end: 1,
|
||||
),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
transitionDuration: const Duration(milliseconds: 200),
|
||||
barrierDismissible: true,
|
||||
selectableDayPredicate: (dateTime) {
|
||||
return true;
|
||||
},
|
||||
);
|
||||
if (onSelected != null) {
|
||||
onSelected!(dateTime);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
18
pubspec.lock
18
pubspec.lock
|
@ -334,6 +334,11 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
flutter_localizations:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_native_splash:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -532,10 +537,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: intl
|
||||
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
||||
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.19.0"
|
||||
version: "0.18.1"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -896,6 +901,15 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
sk_datetime_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: HEAD
|
||||
resolved-ref: "2a7073a2e7fee1ddf0ba67ce87ab2716de876e25"
|
||||
url: "https://gitee.com/lu-zixun/sk-date-time-picker.git"
|
||||
source: git
|
||||
version: "1.0.9"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
|
|
@ -30,7 +30,8 @@ environment:
|
|||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.2
|
||||
|
@ -68,6 +69,11 @@ dependencies:
|
|||
math_expressions: ^2.4.0
|
||||
install_plugin: ^2.1.0
|
||||
url_launcher: ^6.2.5
|
||||
sk_datetime_picker:
|
||||
git:
|
||||
url: https://gitee.com/lu-zixun/sk-date-time-picker.git
|
||||
# sk_datetime_picker:
|
||||
# path: ./lib/widgets/common/datetime_picker
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
|
Loading…
Reference in New Issue