feat: inventory inout history
This commit is contained in:
parent
f725a72a9d
commit
b0c51290cf
15
.metadata
15
.metadata
|
@ -15,24 +15,9 @@ migration:
|
||||||
- platform: root
|
- platform: root
|
||||||
create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
||||||
base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
||||||
- platform: android
|
|
||||||
create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
|
||||||
base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
|
||||||
- platform: ios
|
|
||||||
create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
|
||||||
base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
|
||||||
- platform: linux
|
|
||||||
create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
|
||||||
base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
|
||||||
- platform: macos
|
|
||||||
create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
|
||||||
base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
|
||||||
- platform: web
|
- platform: web
|
||||||
create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
||||||
base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
||||||
- platform: windows
|
|
||||||
create_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
|
||||||
base_revision: 41456452f29d64e8deb623a3c927524bcf9f111b
|
|
||||||
|
|
||||||
# User provided section
|
# User provided section
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,12 @@ Future<Response<PaginationData>> getProducts(Map params) {
|
||||||
queryParameters: {'page': 1, 'pageSize': 10, ...params});
|
queryParameters: {'page': 1, 'pageSize': 10, ...params});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 分页获取原材料出入库列表
|
||||||
|
Future<Response<PaginationData>> getInventoryInout(Map params) {
|
||||||
|
return DioService.dio.get<PaginationData>(Urls.getInventoryInout,
|
||||||
|
queryParameters: {'page': 1, 'pageSize': 10, ...(params)});
|
||||||
|
}
|
||||||
|
|
||||||
Future<Response> logout() {
|
Future<Response> logout() {
|
||||||
return DioService.dio.post(
|
return DioService.dio.post(
|
||||||
Urls.logout,
|
Urls.logout,
|
||||||
|
|
|
@ -39,7 +39,13 @@ final theme = ThemeData(
|
||||||
800: AppTheme.primaryColorDark,
|
800: AppTheme.primaryColorDark,
|
||||||
900: AppTheme.primaryColorDark,
|
900: AppTheme.primaryColorDark,
|
||||||
}),
|
}),
|
||||||
|
primaryColorLight: AppTheme.primaryColorLight,
|
||||||
fontFamily: AppTheme.fontName,
|
fontFamily: AppTheme.fontName,
|
||||||
|
textButtonTheme: TextButtonThemeData(
|
||||||
|
style: ButtonStyle(
|
||||||
|
foregroundColor:
|
||||||
|
MaterialStateProperty.all<Color>(AppTheme.primaryColor), // 设置文本颜色为红色
|
||||||
|
)),
|
||||||
datePickerTheme: DatePickerThemeData(
|
datePickerTheme: DatePickerThemeData(
|
||||||
confirmButtonStyle: ButtonStyle(
|
confirmButtonStyle: ButtonStyle(
|
||||||
textStyle: MaterialStateProperty.resolveWith<TextStyle?>(
|
textStyle: MaterialStateProperty.resolveWith<TextStyle?>(
|
||||||
|
@ -57,7 +63,7 @@ final theme = ThemeData(
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
rangeSelectionBackgroundColor: AppTheme.primaryColor,
|
// rangeSelectionBackgroundColor: AppTheme.primaryColor,
|
||||||
dayBackgroundColor: MaterialStateProperty.resolveWith<Color?>(
|
dayBackgroundColor: MaterialStateProperty.resolveWith<Color?>(
|
||||||
(Set<MaterialState> states) {
|
(Set<MaterialState> states) {
|
||||||
if (states.contains(MaterialState.selected)) {
|
if (states.contains(MaterialState.selected)) {
|
||||||
|
@ -91,7 +97,7 @@ final theme = ThemeData(
|
||||||
backgroundColor: AppTheme.primaryColor,
|
backgroundColor: AppTheme.primaryColor,
|
||||||
titleTextStyle: TextStyle(
|
titleTextStyle: TextStyle(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
fontSize: ScreenAdaper.sp(25),
|
fontSize: ScreenAdaper.sp(30),
|
||||||
fontWeight: FontWeight.bold),
|
fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
inputDecorationTheme: InputDecorationTheme(
|
inputDecorationTheme: InputDecorationTheme(
|
||||||
|
|
|
@ -8,5 +8,6 @@ class Urls {
|
||||||
static String getUserInfo = 'account/profile';
|
static String getUserInfo = 'account/profile';
|
||||||
static String getProjects = 'project';
|
static String getProjects = 'project';
|
||||||
static String getProducts = 'product';
|
static String getProducts = 'product';
|
||||||
|
static String getInventoryInout = 'materials-in-out';
|
||||||
static String updateAvatar = 'user/updateAvatar';
|
static String updateAvatar = 'user/updateAvatar';
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:sk_base_mobile/app_theme.dart';
|
import 'package:sk_base_mobile/app_theme.dart';
|
||||||
|
@ -5,6 +6,7 @@ import 'package:sk_base_mobile/constants/constants.dart';
|
||||||
import 'package:sk_base_mobile/screens/inventory_inout/inventory_inout_controller.dart';
|
import 'package:sk_base_mobile/screens/inventory_inout/inventory_inout_controller.dart';
|
||||||
import 'package:sk_base_mobile/store/auth.store.dart';
|
import 'package:sk_base_mobile/store/auth.store.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/widgets/core/zt_base_date_picker.dart';
|
||||||
|
|
||||||
class CustomAppBar extends StatelessWidget {
|
class CustomAppBar extends StatelessWidget {
|
||||||
CustomAppBar({super.key});
|
CustomAppBar({super.key});
|
||||||
|
@ -44,12 +46,57 @@ class CustomAppBar extends StatelessWidget {
|
||||||
const Spacer(
|
const Spacer(
|
||||||
flex: 10,
|
flex: 10,
|
||||||
),
|
),
|
||||||
Container(
|
buildDatePicker(),
|
||||||
|
if (ScreenAdaper.isLandspace()) const Spacer(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildDatePicker() {
|
||||||
|
return InkWell(
|
||||||
|
onTap: () async {
|
||||||
|
showCupertinoModalPopup(
|
||||||
|
context: Get.overlayContext!,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return ZtBaseDatePicker();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// showCupertinoModalPopup(
|
||||||
|
// context: Get.overlayContext!,
|
||||||
|
// builder: (BuildContext context) {
|
||||||
|
// return Container(
|
||||||
|
// height: 200,
|
||||||
|
// color: Colors.white,
|
||||||
|
// child: CupertinoDatePicker(
|
||||||
|
// mode: CupertinoDatePickerMode.date,
|
||||||
|
// initialDateTime: DateTime.now(),
|
||||||
|
// onDateTimeChanged: (DateTime newDateTime) {
|
||||||
|
// // 处理用户选择的日期
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
// final picker = await CupertinoDatePicker(
|
||||||
|
// context: Get.overlayContext!,
|
||||||
|
// initialDate: DateTime.now(),
|
||||||
|
// helpText: '选择的日期',
|
||||||
|
// confirmText: '确定',
|
||||||
|
// cancelText: '取消',
|
||||||
|
// firstDate: DateTime(2000, 1, 1),
|
||||||
|
// lastDate: DateTime.now().add(const Duration(days: 7)));
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
height: ScreenAdaper.height(70),
|
height: ScreenAdaper.height(70),
|
||||||
width: ScreenAdaper.width(70),
|
width: ScreenAdaper.width(70),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
color: AppTheme.primaryColorLight,
|
color: AppTheme.primaryColorLight,
|
||||||
|
gradient: LinearGradient(colors: [
|
||||||
|
AppTheme.primaryColorLight,
|
||||||
|
AppTheme.primaryColor,
|
||||||
|
]),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: AppTheme.primaryColor,
|
color: AppTheme.primaryColor,
|
||||||
|
@ -57,14 +104,11 @@ class CustomAppBar extends StatelessWidget {
|
||||||
offset: Offset(0, ScreenAdaper.height(10)))
|
offset: Offset(0, ScreenAdaper.height(10)))
|
||||||
]),
|
]),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.account_circle_outlined,
|
Icons.calendar_month_outlined,
|
||||||
size: ScreenAdaper.sp(40),
|
size: ScreenAdaper.sp(40),
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (ScreenAdaper.isLandspace()) const Spacer(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ class DateContainer extends StatelessWidget {
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: const Duration(milliseconds: 200),
|
||||||
height: ScreenAdaper.height(120),
|
height: ScreenAdaper.height(120),
|
||||||
width: ScreenAdaper.width(110),
|
width: ScreenAdaper.width(110),
|
||||||
margin: EdgeInsets.only(left: ScreenAdaper.width(size.width) * 0.05),
|
margin: EdgeInsets.only(right: ScreenAdaper.width(size.width) * 0.05),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
borderRadius: BorderRadius.circular(ScreenAdaper.sp(20)),
|
borderRadius: BorderRadius.circular(ScreenAdaper.sp(20)),
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import 'dart:ui';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:sk_base_mobile/screens/inventory_inout/inventory_inout_controller.dart';
|
import 'package:sk_base_mobile/screens/inventory_inout/inventory_inout_controller.dart';
|
||||||
|
@ -16,37 +14,37 @@ class Dates extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Obx(
|
Obx(
|
||||||
() => Text(
|
() => Text(
|
||||||
DateUtil.getMonth(DateTime.now().add(Duration(days: index))),
|
DateUtil.getMonth(DateTime.now().add(Duration(days: -index))),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: controller.currentIndex.value == index
|
color: controller.currentIndex.value == index
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: Colors.black,
|
: Colors.black,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: ScreenAdaper.sp(16),
|
fontSize: ScreenAdaper.sp(18),
|
||||||
height: 0),
|
height: 0),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Obx(
|
Obx(
|
||||||
() => Text(
|
() => Text(
|
||||||
DateUtil.getDate(DateTime.now().add(Duration(days: index))),
|
DateUtil.getDate(DateTime.now().add(Duration(days: -index))),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: controller.currentIndex.value == index
|
color: controller.currentIndex.value == index
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: Colors.black,
|
: Colors.black,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 26,
|
fontSize: ScreenAdaper.sp(30),
|
||||||
height: 0),
|
height: 0),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Obx(
|
Obx(
|
||||||
() => Text(
|
() => Text(
|
||||||
DateUtil.getDay(DateTime.now().add(Duration(days: index))),
|
DateUtil.getDay(DateTime.now().add(Duration(days: -index))),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: controller.currentIndex.value == index
|
color: controller.currentIndex.value == index
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: Colors.black,
|
: Colors.black,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 13),
|
fontSize: ScreenAdaper.sp(16)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|
|
@ -56,6 +56,7 @@ class Grid extends StatelessWidget {
|
||||||
)
|
)
|
||||||
: GridView.builder(
|
: GridView.builder(
|
||||||
padding: const EdgeInsets.only(top: 40),
|
padding: const EdgeInsets.only(top: 40),
|
||||||
|
reverse: true,
|
||||||
itemCount: controller.list[ind].length,
|
itemCount: controller.list[ind].length,
|
||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
crossAxisCount: crossAsis, childAspectRatio: ratio),
|
crossAxisCount: crossAsis, childAspectRatio: ratio),
|
||||||
|
|
|
@ -9,7 +9,14 @@ class TaskPageBody extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
Positioned.fill(
|
buildBackground(),
|
||||||
|
ChangeButtonRow(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildBackground() {
|
||||||
|
return Positioned.fill(
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: EdgeInsets.only(top: ScreenAdaper.height(25)),
|
margin: EdgeInsets.only(top: ScreenAdaper.height(25)),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
@ -32,9 +39,6 @@ class TaskPageBody extends StatelessWidget {
|
||||||
Colors.white.withOpacity(.0),
|
Colors.white.withOpacity(.0),
|
||||||
])),
|
])),
|
||||||
child: TaskPageView(),
|
child: TaskPageView(),
|
||||||
)),
|
));
|
||||||
ChangeButtonRow(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,9 @@ class UperBody extends StatelessWidget {
|
||||||
height: ScreenAdaper.height(150),
|
height: ScreenAdaper.height(150),
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
controller: controller.scrollController,
|
controller: controller.scrollController,
|
||||||
itemCount: 7,
|
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
|
reverse: true,
|
||||||
|
itemCount: 20,
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
bottom: ScreenAdaper.height(20), top: defaultPadding),
|
bottom: ScreenAdaper.height(20), top: defaultPadding),
|
||||||
|
|
|
@ -3,11 +3,10 @@ import 'package:get/get.dart';
|
||||||
import 'package:sk_base_mobile/app_theme.dart';
|
import 'package:sk_base_mobile/app_theme.dart';
|
||||||
import 'package:sk_base_mobile/db_helper/dbHelper.dart';
|
import 'package:sk_base_mobile/db_helper/dbHelper.dart';
|
||||||
import 'package:sk_base_mobile/screens/new_inventory_inout/new_inventory_inout.dart';
|
import 'package:sk_base_mobile/screens/new_inventory_inout/new_inventory_inout.dart';
|
||||||
import 'package:sk_base_mobile/screens/new_inventory_inout/new_inventory_inout_controller.dart';
|
|
||||||
import 'package:sk_base_mobile/util/date.util.dart';
|
import 'package:sk_base_mobile/util/date.util.dart';
|
||||||
import 'package:sk_base_mobile/util/modal.util.dart';
|
import 'package:sk_base_mobile/util/modal.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/apis/api.dart' as Api;
|
||||||
import 'components/responsive.dart';
|
import 'components/responsive.dart';
|
||||||
|
|
||||||
class InventoryInoutController extends GetxController {
|
class InventoryInoutController extends GetxController {
|
||||||
|
@ -192,20 +191,12 @@ class InventoryInoutController extends GetxController {
|
||||||
Future<void> showInventoryInoutCreateDialog(String inOrOut) async {
|
Future<void> showInventoryInoutCreateDialog(String inOrOut) async {
|
||||||
final isTablet = Responsive.isTablet(Get.context!);
|
final isTablet = Responsive.isTablet(Get.context!);
|
||||||
isTablet
|
isTablet
|
||||||
? showGeneralDialog(
|
? Get.generalDialog(
|
||||||
context: Get.overlayContext!,
|
|
||||||
barrierLabel: "CreateInventoryInout",
|
barrierLabel: "CreateInventoryInout",
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
transitionDuration: const Duration(milliseconds: 400),
|
transitionDuration: const Duration(milliseconds: 400),
|
||||||
pageBuilder: (_, __, ___) {
|
pageBuilder: (_, __, ___) {
|
||||||
return Container(
|
return NewInventoryInout();
|
||||||
margin: EdgeInsets.symmetric(
|
|
||||||
horizontal: ScreenAdaper.width(100),
|
|
||||||
vertical: ScreenAdaper.height(60)),
|
|
||||||
child: ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(30),
|
|
||||||
child: Material(child: NewInventoryInout())),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
transitionBuilder: (_, anim, __, child) {
|
transitionBuilder: (_, anim, __, child) {
|
||||||
Tween<Offset> tween;
|
Tween<Offset> tween;
|
||||||
|
@ -217,7 +208,7 @@ class InventoryInoutController extends GetxController {
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
).then((value) => Get.delete<NewInventoryInoutController>())
|
)
|
||||||
: showModalBottomSheet(
|
: showModalBottomSheet(
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
|
@ -229,6 +220,14 @@ class InventoryInoutController extends GetxController {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> getInoutHistory() async {
|
||||||
|
final res = await Api.getInventoryInout({});
|
||||||
|
|
||||||
|
// final List<Map<String, Object?>> queryResult =
|
||||||
|
// await dbClient!.query('Tasks');
|
||||||
|
// return queryResult.map((e) => TaskModel.fromMap(e)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
getTasks() async {
|
getTasks() async {
|
||||||
db.getData().then((value) {
|
db.getData().then((value) {
|
||||||
model.value = value;
|
model.value = value;
|
||||||
|
@ -262,14 +261,14 @@ class InventoryInoutController extends GetxController {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMoveNextPage() {
|
onMoveNextPage() {
|
||||||
if (currentIndex.value < 7) {
|
if (currentIndex.value > 0) {
|
||||||
setIndex(currentIndex.value + 1);
|
setIndex(currentIndex.value - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMoveBack() {
|
onMoveBack() {
|
||||||
if (currentIndex.value > 0) {
|
if (currentIndex.value < 20) {
|
||||||
setIndex(currentIndex.value - 1);
|
setIndex(currentIndex.value + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ class LandingPage extends StatelessWidget {
|
||||||
child: Stack(children: [
|
child: Stack(children: [
|
||||||
const BackColors(),
|
const BackColors(),
|
||||||
SafeArea(
|
SafeArea(
|
||||||
|
top: false,
|
||||||
child: Obx(() => Scaffold(
|
child: Obx(() => Scaffold(
|
||||||
floatingActionButtonLocation:
|
floatingActionButtonLocation:
|
||||||
FloatingActionButtonLocation.centerDocked,
|
FloatingActionButtonLocation.centerDocked,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
@ -22,74 +24,32 @@ class NewInventoryInout extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return SafeArea(
|
||||||
height: ScreenAdaper.height(800),
|
top: false, // 设置为false以避免保留顶部状态栏的空间
|
||||||
width: Get.width,
|
child: Scaffold(
|
||||||
|
appBar: PreferredSize(
|
||||||
|
preferredSize: Size.fromHeight(ScreenAdaper.height(
|
||||||
|
kToolbarHeight)), // 这里使用kToolbarHeight,它是不包含状态栏的AppBar的推荐高度
|
||||||
|
child: AppBar(
|
||||||
|
title: const Text('出入库登记'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
resizeToAvoidBottomInset: true,
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
child: Container(
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
child: ClipRRect(
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
topLeft: Radius.circular(
|
|
||||||
ScreenAdaper.sp(30),
|
|
||||||
),
|
|
||||||
topRight: Radius.circular(ScreenAdaper.sp(30))),
|
|
||||||
child: GestureDetector(
|
|
||||||
behavior: HitTestBehavior.translucent,
|
|
||||||
onTap: () {
|
|
||||||
// 点击空白处时收起键盘
|
|
||||||
// FocusScope.of(Get.context!).unfocus();
|
|
||||||
},
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
Positioned.fill(
|
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
children: [
|
||||||
buildTitle(),
|
buildForm(),
|
||||||
SingleChildScrollView(
|
|
||||||
child: buildForm(),
|
|
||||||
),
|
|
||||||
Spacer(),
|
|
||||||
Obx(() => GradientButton(
|
Obx(() => GradientButton(
|
||||||
onPressed: () => {controller.insertTask(context)},
|
onPressed: () => {controller.create()},
|
||||||
isLoading: controller.loading.value,
|
isLoading: controller.loading.value,
|
||||||
))
|
))
|
||||||
],
|
],
|
||||||
))
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
)),
|
))));
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget buildTitle() {
|
|
||||||
return Container(
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
border: Border(bottom: BorderSide(color: AppTheme.dividerColor))),
|
|
||||||
padding: EdgeInsets.symmetric(
|
|
||||||
vertical: ScreenAdaper.height(5), horizontal: ScreenAdaper.width(20)),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
TextEnum.inventoryInOutDialogTitle,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: ScreenAdaper.sp(25),
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Spacer(),
|
|
||||||
IconButton(
|
|
||||||
onPressed: () {
|
|
||||||
Get.back();
|
|
||||||
},
|
|
||||||
icon: Icon(
|
|
||||||
Icons.close,
|
|
||||||
size: ScreenAdaper.sp(30),
|
|
||||||
))
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildForm() {
|
Widget buildForm() {
|
||||||
|
@ -114,25 +74,27 @@ class NewInventoryInout extends StatelessWidget {
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
|
Expanded(flex: 1, child: buildQuantity()),
|
||||||
|
SizedBox(
|
||||||
|
width: ScreenAdaper.width(formHorizontalGap),
|
||||||
|
),
|
||||||
Expanded(flex: 1, child: buildDatePicker()),
|
Expanded(flex: 1, child: buildDatePicker()),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: ScreenAdaper.width(formHorizontalGap),
|
width: ScreenAdaper.width(formHorizontalGap),
|
||||||
),
|
),
|
||||||
Expanded(flex: 1, child: buildQuantity()),
|
Expanded(flex: 1, child: buildAgent()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: ScreenAdaper.height(formVerticalGap),
|
height: ScreenAdaper.height(formVerticalGap),
|
||||||
),
|
),
|
||||||
Row(
|
|
||||||
children: [Expanded(child: buildAgent())],
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: ScreenAdaper.height(formVerticalGap),
|
|
||||||
),
|
|
||||||
Row(
|
Row(
|
||||||
children: [Expanded(child: buildRemark())],
|
children: [Expanded(child: buildRemark())],
|
||||||
),
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: ScreenAdaper.height(formVerticalGap),
|
||||||
|
),
|
||||||
|
buildImageUploadQueue()
|
||||||
];
|
];
|
||||||
|
|
||||||
final child = Column(
|
final child = Column(
|
||||||
|
@ -239,8 +201,120 @@ class NewInventoryInout extends StatelessWidget {
|
||||||
return ZtTextInput(
|
return ZtTextInput(
|
||||||
textController: controller.remarkTextController,
|
textController: controller.remarkTextController,
|
||||||
labelText: '备注',
|
labelText: '备注',
|
||||||
isRequired: true,
|
|
||||||
isTextArea: true,
|
isTextArea: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 照片上传
|
||||||
|
Widget buildImageUploadQueue() {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
vertical: ScreenAdaper.height(20),
|
||||||
|
horizontal: ScreenAdaper.width(20)),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'*请拍照上传产品照片',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: ScreenAdaper.sp(30),
|
||||||
|
color: AppTheme.secondPrimaryColor),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: ScreenAdaper.height(10),
|
||||||
|
),
|
||||||
|
Obx(() => SingleChildScrollView(
|
||||||
|
controller: controller.uploadScrollController,
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
...controller.uploadImgFilesPath
|
||||||
|
.map((String path) => builderImagePreview(path))
|
||||||
|
.toList(),
|
||||||
|
buildImageUploader()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 照片预览队列Item
|
||||||
|
Widget builderImagePreview(String path) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.symmetric(horizontal: ScreenAdaper.width(5)),
|
||||||
|
width: ScreenAdaper.width(200),
|
||||||
|
height: ScreenAdaper.width(200),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
border: Border.all(width: 1.0, color: AppTheme.dividerColor),
|
||||||
|
// color: AppTheme.primaryColor,
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
image: DecorationImage(
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
image: FileImage(File(path)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
top: ScreenAdaper.height(5),
|
||||||
|
right: ScreenAdaper.width(5),
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
controller.uploadImgFilesPath.remove(path);
|
||||||
|
},
|
||||||
|
child: Icon(
|
||||||
|
Icons.close,
|
||||||
|
shadows: [
|
||||||
|
Shadow(
|
||||||
|
color: Colors.black,
|
||||||
|
offset: Offset(1, 1),
|
||||||
|
blurRadius: 3,
|
||||||
|
),
|
||||||
|
Shadow(
|
||||||
|
color: Colors.black,
|
||||||
|
offset: Offset(-1, -1),
|
||||||
|
blurRadius: 3,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
size: ScreenAdaper.sp(40),
|
||||||
|
color: AppTheme.nearlyWhite,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传照片控制器
|
||||||
|
Widget buildImageUploader() {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
controller.photoPicker();
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.symmetric(horizontal: ScreenAdaper.width(5)),
|
||||||
|
width: ScreenAdaper.width(200),
|
||||||
|
height: ScreenAdaper.width(200),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
border: Border.all(width: 1.0, color: AppTheme.dividerColor),
|
||||||
|
// color: AppTheme.primaryColor,
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Icon(
|
||||||
|
Icons.add_a_photo_rounded,
|
||||||
|
size: ScreenAdaper.sp(60),
|
||||||
|
color: AppTheme.primaryColor,
|
||||||
|
))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'package:sk_base_mobile/db_helper/dbHelper.dart';
|
import 'package:sk_base_mobile/db_helper/dbHelper.dart';
|
||||||
import 'package:sk_base_mobile/models/base_response.dart';
|
import 'package:sk_base_mobile/models/base_response.dart';
|
||||||
import 'package:sk_base_mobile/models/product.model.dart';
|
import 'package:sk_base_mobile/models/product.model.dart';
|
||||||
|
@ -10,6 +12,10 @@ import 'package:sk_base_mobile/models/task_model.dart';
|
||||||
import 'package:sk_base_mobile/screens/inventory_inout/inventory_inout_controller.dart';
|
import 'package:sk_base_mobile/screens/inventory_inout/inventory_inout_controller.dart';
|
||||||
import 'package:sk_base_mobile/apis/api.dart' as Api;
|
import 'package:sk_base_mobile/apis/api.dart' as Api;
|
||||||
import 'package:sk_base_mobile/util/date.util.dart';
|
import 'package:sk_base_mobile/util/date.util.dart';
|
||||||
|
import 'package:sk_base_mobile/util/loading_util.dart';
|
||||||
|
import 'package:sk_base_mobile/util/logger_util.dart';
|
||||||
|
import 'package:sk_base_mobile/util/media_util.dart';
|
||||||
|
import 'package:sk_base_mobile/util/photo_picker_util.dart';
|
||||||
import 'package:sk_base_mobile/util/snack_bar.util.dart';
|
import 'package:sk_base_mobile/util/snack_bar.util.dart';
|
||||||
|
|
||||||
class NewInventoryInoutController extends GetxController {
|
class NewInventoryInoutController extends GetxController {
|
||||||
|
@ -38,6 +44,8 @@ class NewInventoryInoutController extends GetxController {
|
||||||
final quantityTextController = TextEditingController();
|
final quantityTextController = TextEditingController();
|
||||||
final agentTextController = TextEditingController();
|
final agentTextController = TextEditingController();
|
||||||
final remarkTextController = TextEditingController();
|
final remarkTextController = TextEditingController();
|
||||||
|
final uploadImgFilesPath = <String>[].obs;
|
||||||
|
final uploadScrollController = ScrollController();
|
||||||
Map<String, dynamic> payload = {};
|
Map<String, dynamic> payload = {};
|
||||||
|
|
||||||
Future<List<ProjectModel>> getProjects({String? keyword}) async {
|
Future<List<ProjectModel>> getProjects({String? keyword}) async {
|
||||||
|
@ -60,6 +68,82 @@ class NewInventoryInoutController extends GetxController {
|
||||||
return products;
|
return products;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
onReady() {
|
||||||
|
super.onReady();
|
||||||
|
dateTextController.text = DateUtil.format(DateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 创建出入库记录
|
||||||
|
create() {
|
||||||
|
if (payload['projectId'] == null) {
|
||||||
|
SnackBarUtil().info(
|
||||||
|
'项目不能为空',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (payload['productId'] == null) {
|
||||||
|
SnackBarUtil().info(
|
||||||
|
'产品不能为空',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (payload['time'] == null) {
|
||||||
|
SnackBarUtil().info(
|
||||||
|
'时间不能为空',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
payload['quantity'] = quantityTextController.text;
|
||||||
|
if (payload['quantity'].isEmpty) {
|
||||||
|
SnackBarUtil().info(
|
||||||
|
'数量不能为空',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
payload['agent'] = agentTextController.text;
|
||||||
|
if (payload['agent'].isEmpty) {
|
||||||
|
SnackBarUtil().info(
|
||||||
|
'经办人不能为空',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LoggerUtil().info(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> photoPicker() async {
|
||||||
|
XFile? pickedFile = await MediaUtil().getImageFromCamera();
|
||||||
|
if (pickedFile != null) {
|
||||||
|
uploadImgFilesPath.add(pickedFile.path);
|
||||||
|
Future.delayed(const Duration(milliseconds: 100), () {
|
||||||
|
// 滚动到最右边
|
||||||
|
uploadScrollController.animateTo(
|
||||||
|
uploadScrollController.position.maxScrollExtent,
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
curve: Curves.easeOut,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// await PhotoPickerUtil().showPicker(callback: (XFile pickedFile) async {
|
||||||
|
// await LoadingUtil.to.show(status: '上传中...');
|
||||||
|
// try {
|
||||||
|
// String? filename = await MediaUtil().uploadImg(File(pickedFile.path));
|
||||||
|
// if (filename.isNotEmpty) {
|
||||||
|
// final res = await Api.updateAvatar(filename);
|
||||||
|
// if (res.data != null) {
|
||||||
|
// SnackBarUtil().success('上传成功');
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // uploadImgFilePath(pickedFile.path);
|
||||||
|
// Get.back();
|
||||||
|
// } catch (e) {
|
||||||
|
// SnackBarUtil().error('上传失败,请重试');
|
||||||
|
// } finally {
|
||||||
|
// await LoadingUtil.to.dismiss();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
picStartTime(BuildContext context) async {
|
picStartTime(BuildContext context) async {
|
||||||
var picker =
|
var picker =
|
||||||
await showTimePicker(context: context, initialTime: TimeOfDay.now());
|
await showTimePicker(context: context, initialTime: TimeOfDay.now());
|
||||||
|
|
|
@ -48,7 +48,14 @@ class WorkBenchPage extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SingleChildScrollView(
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: const SizedBox(),
|
||||||
|
title: const Text(
|
||||||
|
'工作台',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
child: Column(children: [
|
child: Column(children: [
|
||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.all(ScreenAdaper.width(20)),
|
padding: EdgeInsets.all(ScreenAdaper.width(20)),
|
||||||
|
@ -66,7 +73,8 @@ class WorkBenchPage extends StatelessWidget {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
]));
|
])),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildCard(int index) {
|
Widget buildCard(int index) {
|
||||||
|
|
|
@ -7,25 +7,25 @@ import 'package:sk_base_mobile/util/media_util.dart';
|
||||||
import 'package:sk_base_mobile/app_theme.dart';
|
import 'package:sk_base_mobile/app_theme.dart';
|
||||||
|
|
||||||
class PhotoPickerUtil {
|
class PhotoPickerUtil {
|
||||||
showPicker({Function? callback}) async {
|
showPicker({Function? callback, String title = '请选择上传方式'}) async {
|
||||||
return showCupertinoModalPopup(
|
return showCupertinoModalPopup(
|
||||||
context: Get.context!,
|
context: Get.context!,
|
||||||
builder: (BuildContext ctx) {
|
builder: (BuildContext ctx) {
|
||||||
return CupertinoActionSheet(
|
return CupertinoActionSheet(
|
||||||
title: const Text('Change avatar'),
|
title: Text(title),
|
||||||
cancelButton: CupertinoActionSheetAction(
|
cancelButton: CupertinoActionSheetAction(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Get.back();
|
Get.back();
|
||||||
},
|
},
|
||||||
child: const Text(
|
child: const Text(
|
||||||
'Cancel',
|
'取消',
|
||||||
style: TextStyle(color: Color(0xffcdcdcd)),
|
style: TextStyle(color: Color(0xffcdcdcd)),
|
||||||
)),
|
)),
|
||||||
actions: ['Photography', 'Album']
|
actions: ['拍照', '相册']
|
||||||
.map((item) => CupertinoActionSheetAction(
|
.map((item) => CupertinoActionSheetAction(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Get.back();
|
Get.back();
|
||||||
XFile? pickedFile = item == 'Photography'
|
XFile? pickedFile = item == '拍照'
|
||||||
? await MediaUtil().getImageFromCamera()
|
? await MediaUtil().getImageFromCamera()
|
||||||
: await MediaUtil().getImageFromGallery();
|
: await MediaUtil().getImageFromGallery();
|
||||||
if (pickedFile != null) {
|
if (pickedFile != null) {
|
||||||
|
|
|
@ -8,10 +8,15 @@ class ZtDatePicker extends StatelessWidget {
|
||||||
final TextEditingController textController;
|
final TextEditingController textController;
|
||||||
final VoidCallback? onClear;
|
final VoidCallback? onClear;
|
||||||
final Function? onDateSelected;
|
final Function? onDateSelected;
|
||||||
|
final bool isRequired;
|
||||||
|
final String labelText;
|
||||||
|
|
||||||
const ZtDatePicker({
|
const ZtDatePicker({
|
||||||
super.key,
|
super.key,
|
||||||
this.onClear,
|
this.onClear,
|
||||||
this.onDateSelected,
|
this.onDateSelected,
|
||||||
|
this.labelText = '日期',
|
||||||
|
this.isRequired = false,
|
||||||
required this.textController,
|
required this.textController,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -41,16 +46,19 @@ class ZtDatePicker extends StatelessWidget {
|
||||||
)
|
)
|
||||||
: const SizedBox(),
|
: const SizedBox(),
|
||||||
hintText: '请选择',
|
hintText: '请选择',
|
||||||
label: const Row(
|
label: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
|
if (isRequired)
|
||||||
Text(
|
Text(
|
||||||
"*",
|
"*",
|
||||||
style: TextStyle(color: Colors.red),
|
style: TextStyle(
|
||||||
|
color: Colors.red, fontSize: ScreenAdaper.sp(30)),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'日期',
|
labelText,
|
||||||
|
style: TextStyle(fontSize: ScreenAdaper.sp(30)),
|
||||||
),
|
),
|
||||||
])),
|
])),
|
||||||
keyboardType: TextInputType.none,
|
keyboardType: TextInputType.none,
|
||||||
|
@ -63,6 +71,7 @@ class ZtDatePicker extends StatelessWidget {
|
||||||
cancelText: '取消',
|
cancelText: '取消',
|
||||||
firstDate: DateTime(2000, 1, 1),
|
firstDate: DateTime(2000, 1, 1),
|
||||||
lastDate: DateTime.now().add(const Duration(days: 7)));
|
lastDate: DateTime.now().add(const Duration(days: 7)));
|
||||||
|
|
||||||
if (onDateSelected != null) {
|
if (onDateSelected != null) {
|
||||||
onDateSelected!(picker);
|
onDateSelected!(picker);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:sk_base_mobile/util/logger_util.dart';
|
||||||
|
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||||
|
|
||||||
|
class ZtBaseDatePicker extends StatelessWidget {
|
||||||
|
final Function? onDateTimeChanged;
|
||||||
|
final yearController =
|
||||||
|
FixedExtentScrollController(initialItem: DateTime.now().year - 2000);
|
||||||
|
final monthController =
|
||||||
|
FixedExtentScrollController(initialItem: DateTime.now().month - 1);
|
||||||
|
final dayController =
|
||||||
|
FixedExtentScrollController(initialItem: DateTime.now().day - 1);
|
||||||
|
ZtBaseDatePicker({super.key, this.onDateTimeChanged});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
height: ScreenAdaper.height(250),
|
||||||
|
color: Colors.white,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
'取消',
|
||||||
|
style: TextStyle(fontSize: ScreenAdaper.sp(25)),
|
||||||
|
)),
|
||||||
|
const Spacer(),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Get.back();
|
||||||
|
final year = 2000 + yearController.selectedItem;
|
||||||
|
String month = '${monthController.selectedItem + 1}';
|
||||||
|
if (int.parse(month) < 10) {
|
||||||
|
month = '0$month';
|
||||||
|
}
|
||||||
|
final day = dayController.selectedItem + 1;
|
||||||
|
if (onDateTimeChanged != null) {
|
||||||
|
onDateTimeChanged!('$year-$month-$day');
|
||||||
|
}
|
||||||
|
LoggerUtil().info('$year-$month-$day');
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
'确定',
|
||||||
|
style: TextStyle(fontSize: ScreenAdaper.sp(25)),
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: CupertinoPicker(
|
||||||
|
scrollController: yearController,
|
||||||
|
itemExtent: ScreenAdaper.height(60),
|
||||||
|
onSelectedItemChanged: (int index) {
|
||||||
|
// 处理用户选择的年份
|
||||||
|
},
|
||||||
|
children: List<Widget>.generate(DateTime.now().year - 1999,
|
||||||
|
(int index) {
|
||||||
|
return Center(child: Text('${2000 + index}年'));
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: CupertinoPicker(
|
||||||
|
scrollController: monthController,
|
||||||
|
itemExtent: ScreenAdaper.height(60),
|
||||||
|
onSelectedItemChanged: (int index) {
|
||||||
|
// 处理用户选择的月份
|
||||||
|
},
|
||||||
|
children: List<Widget>.generate(12, (int index) {
|
||||||
|
return Center(child: Text('${index + 1}月'));
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: CupertinoPicker(
|
||||||
|
scrollController: dayController,
|
||||||
|
itemExtent: ScreenAdaper.height(60),
|
||||||
|
onSelectedItemChanged: (int index) {
|
||||||
|
// 处理用户选择的日期
|
||||||
|
},
|
||||||
|
children: List<Widget>.generate(31, (int index) {
|
||||||
|
return Center(child: Text('${index + 1}日'));
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:sk_base_mobile/app_theme.dart';
|
import 'package:sk_base_mobile/app_theme.dart';
|
||||||
import 'package:sk_base_mobile/constants/bg_color.dart';
|
import 'package:sk_base_mobile/constants/bg_color.dart';
|
||||||
|
@ -26,20 +27,28 @@ class ZtNumberInput extends StatelessWidget {
|
||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
},
|
},
|
||||||
onTap: onTap ?? () {},
|
onTap: onTap ?? () {},
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(fontSize: ScreenAdaper.sp(30)),
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
|
inputFormatters: <TextInputFormatter>[
|
||||||
|
FilteringTextInputFormatter.digitsOnly // 限制输入内容只能是数字
|
||||||
|
],
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
|
contentPadding: EdgeInsets.symmetric(vertical: ScreenAdaper.height(18)),
|
||||||
floatingLabelBehavior: FloatingLabelBehavior.always,
|
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||||
label: Row(
|
label: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
if (isRequired)
|
if (isRequired)
|
||||||
const Text(
|
Text(
|
||||||
"*",
|
"*",
|
||||||
style: TextStyle(color: Colors.red),
|
style: TextStyle(
|
||||||
|
color: Colors.red, fontSize: ScreenAdaper.sp(30)),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
labelText,
|
labelText,
|
||||||
|
style: TextStyle(fontSize: ScreenAdaper.sp(30)),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
|
|
|
@ -67,12 +67,15 @@ class ZtSearchSelect extends StatelessWidget {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
if (isRequired)
|
if (isRequired)
|
||||||
const Text(
|
Text(
|
||||||
"*",
|
"*",
|
||||||
style: TextStyle(color: Colors.red),
|
style: TextStyle(
|
||||||
|
color: Colors.red,
|
||||||
|
fontSize: ScreenAdaper.sp(30)),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
labelText,
|
labelText,
|
||||||
|
style: TextStyle(fontSize: ScreenAdaper.sp(30)),
|
||||||
),
|
),
|
||||||
])));
|
])));
|
||||||
},
|
},
|
||||||
|
|
|
@ -27,7 +27,7 @@ class ZtTextInput extends StatelessWidget {
|
||||||
onTapOutside: (event) {
|
onTapOutside: (event) {
|
||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
},
|
},
|
||||||
maxLines: isTextArea ? null : 1, // 添加这行代码
|
maxLines: isTextArea ? 3 : 1, // 添加这行代码
|
||||||
onTap: onTap ?? () {},
|
onTap: onTap ?? () {},
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
floatingLabelBehavior: FloatingLabelBehavior.always,
|
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||||
|
@ -36,12 +36,14 @@ class ZtTextInput extends StatelessWidget {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
if (isRequired)
|
if (isRequired)
|
||||||
const Text(
|
Text(
|
||||||
"*",
|
"*",
|
||||||
style: TextStyle(color: Colors.red),
|
style: TextStyle(
|
||||||
|
color: Colors.red, fontSize: ScreenAdaper.sp(30)),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
labelText,
|
labelText,
|
||||||
|
style: TextStyle(fontSize: ScreenAdaper.sp(30)),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
|
|
|
@ -41,7 +41,7 @@ class GradientButton extends StatelessWidget {
|
||||||
: Text(
|
: Text(
|
||||||
buttonText,
|
buttonText,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: AppTheme.nearlyWhite,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: ScreenAdaper.sp(25),
|
fontSize: ScreenAdaper.sp(25),
|
||||||
),
|
),
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
// This is a basic Flutter widget test.
|
||||||
|
//
|
||||||
|
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||||
|
// utility in the flutter_test package. For example, you can send tap and scroll
|
||||||
|
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||||
|
// tree, read text, and verify that the values of widget properties are correct.
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import 'package:sk_base_mobile/main.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||||
|
// Build our app and trigger a frame.
|
||||||
|
await tester.pumpWidget(const MyApp());
|
||||||
|
|
||||||
|
// Verify that our counter starts at 0.
|
||||||
|
expect(find.text('0'), findsOneWidget);
|
||||||
|
expect(find.text('1'), findsNothing);
|
||||||
|
|
||||||
|
// Tap the '+' icon and trigger a frame.
|
||||||
|
await tester.tap(find.byIcon(Icons.add));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
// Verify that our counter has incremented.
|
||||||
|
expect(find.text('0'), findsNothing);
|
||||||
|
expect(find.text('1'), findsOneWidget);
|
||||||
|
});
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 917 B |
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 8.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
|
@ -0,0 +1,59 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
|
||||||
|
The path provided below has to start and end with a slash "/" in order for
|
||||||
|
it to work correctly.
|
||||||
|
|
||||||
|
For more details:
|
||||||
|
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
|
||||||
|
|
||||||
|
This is a placeholder for base href that will be replaced by the value of
|
||||||
|
the `--base-href` argument provided to `flutter build`.
|
||||||
|
-->
|
||||||
|
<base href="$FLUTTER_BASE_HREF">
|
||||||
|
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||||
|
<meta name="description" content="A new Flutter project.">
|
||||||
|
|
||||||
|
<!-- iOS meta tags & icons -->
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
|
<meta name="apple-mobile-web-app-title" content="sk_base_mobile">
|
||||||
|
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||||||
|
|
||||||
|
<!-- Favicon -->
|
||||||
|
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||||
|
|
||||||
|
<title>sk_base_mobile</title>
|
||||||
|
<link rel="manifest" href="manifest.json">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// The value below is injected by flutter build, do not touch.
|
||||||
|
const serviceWorkerVersion = null;
|
||||||
|
</script>
|
||||||
|
<!-- This script adds the flutter initialization JS code -->
|
||||||
|
<script src="flutter.js" defer></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
window.addEventListener('load', function(ev) {
|
||||||
|
// Download main.dart.js
|
||||||
|
_flutter.loader.loadEntrypoint({
|
||||||
|
serviceWorker: {
|
||||||
|
serviceWorkerVersion: serviceWorkerVersion,
|
||||||
|
},
|
||||||
|
onEntrypointLoaded: function(engineInitializer) {
|
||||||
|
engineInitializer.initializeEngine().then(function(appRunner) {
|
||||||
|
appRunner.runApp();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"name": "sk_base_mobile",
|
||||||
|
"short_name": "sk_base_mobile",
|
||||||
|
"start_url": ".",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "#0175C2",
|
||||||
|
"theme_color": "#0175C2",
|
||||||
|
"description": "A new Flutter project.",
|
||||||
|
"orientation": "portrait-primary",
|
||||||
|
"prefer_related_applications": false,
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-maskable-192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-maskable-512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue