feat: single search more
This commit is contained in:
parent
bb93b1ad63
commit
1a3f57ce0e
|
@ -47,6 +47,9 @@ final theme = ThemeData(
|
||||||
foregroundColor:
|
foregroundColor:
|
||||||
MaterialStateProperty.all<Color>(AppTheme.primaryColor), // 设置文本颜色为红色
|
MaterialStateProperty.all<Color>(AppTheme.primaryColor), // 设置文本颜色为红色
|
||||||
)),
|
)),
|
||||||
|
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
||||||
|
backgroundColor: AppTheme.primaryColorLight,
|
||||||
|
),
|
||||||
datePickerTheme: DatePickerThemeData(
|
datePickerTheme: DatePickerThemeData(
|
||||||
confirmButtonStyle: ButtonStyle(
|
confirmButtonStyle: ButtonStyle(
|
||||||
textStyle: MaterialStateProperty.resolveWith<TextStyle?>(
|
textStyle: MaterialStateProperty.resolveWith<TextStyle?>(
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get_rx/src/rx_types/rx_types.dart';
|
||||||
|
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||||
|
|
||||||
|
mixin BaseSearchMore<T> {
|
||||||
|
RxList<T> list = RxList([]);
|
||||||
|
RxString searchKey = ''.obs;
|
||||||
|
final searchBarTextConroller = TextEditingController();
|
||||||
|
RefreshController refreshController = RefreshController(initialRefresh: true);
|
||||||
|
int page = 1;
|
||||||
|
int limit = 15;
|
||||||
|
int total = 0;
|
||||||
|
getData({bool isRefresh = false}) {}
|
||||||
|
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,11 +32,14 @@ class InventoryInoutViewItem extends StatelessWidget {
|
||||||
|
|
||||||
class Grid extends StatelessWidget {
|
class Grid extends StatelessWidget {
|
||||||
final int columnNum;
|
final int columnNum;
|
||||||
final int ind;
|
int ind;
|
||||||
final controller = Get.find<InventoryInoutController>();
|
final controller = Get.find<InventoryInoutController>();
|
||||||
Grid({super.key, required this.columnNum, required this.ind});
|
Grid({super.key, required this.columnNum, required this.ind});
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
if (controller.currentIndex.value != ind) {
|
||||||
|
ind = controller.currentIndex.value;
|
||||||
|
}
|
||||||
return Obx(
|
return Obx(
|
||||||
() => controller.loading.value
|
() => controller.loading.value
|
||||||
? const LoadingIndicator(common: true)
|
? const LoadingIndicator(common: true)
|
||||||
|
|
|
@ -347,27 +347,16 @@ class NewInventoryInout extends StatelessWidget {
|
||||||
floatingLabelBehavior: FloatingLabelBehavior.always),
|
floatingLabelBehavior: FloatingLabelBehavior.always),
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (inOrOut == InventoryInOrOutEnum.In) {
|
ModalUtil.showGeneralDialog(
|
||||||
ModalUtil.showGeneralDialog(content: AgentSearch(
|
content: AgentSearch(
|
||||||
onSelected: (UserInfoModel userInfo) {
|
onSelected: (UserInfoModel userInfo) {
|
||||||
Get.back();
|
Get.back();
|
||||||
controller.payload['agent'] = userInfo.nickname;
|
controller.payload['agent'] = userInfo.nickname;
|
||||||
controller.agentTextController.text = userInfo.nickname!;
|
controller.agentTextController.text = userInfo.nickname!;
|
||||||
},
|
},
|
||||||
));
|
),
|
||||||
} else {
|
width: Get.width - ScreenAdaper.width(50))
|
||||||
ModalUtil.showGeneralDialog(
|
.then((value) => Get.delete<AgentSearchController>());
|
||||||
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>());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,210 @@
|
||||||
|
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/sale_quotation.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 SaleQuotationGroupSearch extends StatelessWidget {
|
||||||
|
final Function(SaleQuotationModel)? onSelected;
|
||||||
|
final Function(SaleQuotationModel)? beforeSelectedCheck;
|
||||||
|
SaleQuotationGroupSearch(
|
||||||
|
{super.key, this.onSelected, this.beforeSelectedCheck});
|
||||||
|
final controller = Get.put(GroupSearchController());
|
||||||
|
final listTitleTextStyle =
|
||||||
|
TextStyle(fontSize: ScreenAdaper.height(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() {
|
||||||
|
return Obx(() => SmartRefresher(
|
||||||
|
enablePullDown: true,
|
||||||
|
enablePullUp: true,
|
||||||
|
controller: controller.refreshController,
|
||||||
|
onLoading: controller.onLoading,
|
||||||
|
onRefresh: controller.onRefresh,
|
||||||
|
child: controller.refreshController.isLoading
|
||||||
|
? const SizedBox()
|
||||||
|
: controller.list.isEmpty
|
||||||
|
? const Center(
|
||||||
|
child: Empty(text: '暂无数据'),
|
||||||
|
)
|
||||||
|
: ListView.separated(
|
||||||
|
separatorBuilder: (context, index) => const 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].name}',
|
||||||
|
style: TextStyle(fontSize: ScreenAdaper.height(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 GroupSearchController extends GetxController {
|
||||||
|
RxList<SaleQuotationModel> list = RxList([]);
|
||||||
|
RxString searchKey = ''.obs;
|
||||||
|
final searchBarTextConroller = TextEditingController();
|
||||||
|
RefreshController refreshController = RefreshController(initialRefresh: true);
|
||||||
|
int page = 1;
|
||||||
|
int limit = 15;
|
||||||
|
int total = 0;
|
||||||
|
Future<List<SaleQuotationModel>> 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);
|
||||||
|
|
||||||
|
List<SaleQuotationModel> newList = [
|
||||||
|
SaleQuotationModel(name: '中间过渡架电控部分', items: []),
|
||||||
|
SaleQuotationModel(name: '端头架电控部分', items: []),
|
||||||
|
SaleQuotationModel(name: '主阀部分', items: []),
|
||||||
|
SaleQuotationModel(name: '自动反冲洗过滤器部分', items: []),
|
||||||
|
SaleQuotationModel(name: '位移测量部分', items: []),
|
||||||
|
SaleQuotationModel(name: '压力检测部分', items: []),
|
||||||
|
SaleQuotationModel(name: '煤机定位部分', items: []),
|
||||||
|
SaleQuotationModel(name: '姿态检测部分', items: []),
|
||||||
|
];
|
||||||
|
list.assignAll(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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,12 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||||
|
import 'package:sk_base_mobile/models/base_search_more.dart';
|
||||||
import 'package:sk_base_mobile/models/sale_quotation.model.dart';
|
import 'package:sk_base_mobile/models/sale_quotation.model.dart';
|
||||||
|
import 'package:sk_base_mobile/screens/sale_quotation/components/sale_quotation_group_search.dart';
|
||||||
|
import 'package:sk_base_mobile/widgets/core/sk_single_search_more.dart';
|
||||||
|
import 'package:sk_base_mobile/util/modal.util.dart';
|
||||||
|
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
||||||
|
|
||||||
class SaleQuotationController extends GetxController {
|
class SaleQuotationController extends GetxController {
|
||||||
static SaleQuotationController get to => Get.find();
|
static SaleQuotationController get to => Get.find();
|
||||||
|
@ -27,19 +34,149 @@ class SaleQuotationController extends GetxController {
|
||||||
SaleQuotationItemModel(name: '各类安装附件'),
|
SaleQuotationItemModel(name: '各类安装附件'),
|
||||||
]);
|
]);
|
||||||
RxList<SaleQuotationModel> groups = RxList<SaleQuotationModel>([]);
|
RxList<SaleQuotationModel> groups = RxList<SaleQuotationModel>([]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onReady() {
|
void onReady() {
|
||||||
groups.assignAll([
|
// groups.assignAll();
|
||||||
SaleQuotationModel(name: '中间过渡架电控部分', items: products),
|
// SaleQuotationModel(name: '中间过渡架电控部分', items: products),
|
||||||
SaleQuotationModel(name: '端头架电控部分', items: products),
|
// SaleQuotationModel(name: '端头架电控部分', items: products),
|
||||||
SaleQuotationModel(name: '主阀部分', items: products),
|
// SaleQuotationModel(name: '主阀部分', items: products),
|
||||||
SaleQuotationModel(name: '自动反冲洗过滤器部分', items: products),
|
// SaleQuotationModel(name: '自动反冲洗过滤器部分', items: products),
|
||||||
SaleQuotationModel(name: '位移测量部分', items: products),
|
// SaleQuotationModel(name: '位移测量部分', items: products),
|
||||||
SaleQuotationModel(name: '压力检测部分', items: products),
|
// SaleQuotationModel(name: '压力检测部分', items: products),
|
||||||
SaleQuotationModel(name: '煤机定位部分', items: products),
|
// SaleQuotationModel(name: '煤机定位部分', items: products),
|
||||||
SaleQuotationModel(name: '姿态检测部分', items: products),
|
// SaleQuotationModel(name: '姿态检测部分', items: products),
|
||||||
]);
|
|
||||||
|
|
||||||
super.onReady();
|
super.onReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> addGroup() async {
|
||||||
|
final controller = Get.put(GroupSearchMoreController());
|
||||||
|
// 选择组件 选择分组
|
||||||
|
ModalUtil.showGeneralDialog(
|
||||||
|
content: SkSingleSearchMore<SaleQuotationModel>(
|
||||||
|
controller: controller,
|
||||||
|
enablePullUp: false,
|
||||||
|
enablePullDown: true,
|
||||||
|
itemBuilder: (_, index) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: () {
|
||||||
|
Get.back();
|
||||||
|
groups.add(controller.list[index]);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: ScreenAdaper.width(5),
|
||||||
|
vertical: ScreenAdaper.height(10)),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
controller.list[index].name,
|
||||||
|
style: TextStyle(fontSize: ScreenAdaper.height(25)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
width: Get.width - ScreenAdaper.width(50))
|
||||||
|
.then((value) => Get.delete<GroupSearchController>());
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> removeGroup(int index) async {
|
||||||
|
groups.removeAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> addItems() async {
|
||||||
|
final controller = Get.put(ItemSearchMoreController());
|
||||||
|
// 选择产品
|
||||||
|
ModalUtil.showGeneralDialog(
|
||||||
|
content: SkSingleSearchMore<SaleQuotationItemModel>(
|
||||||
|
controller: controller,
|
||||||
|
enablePullUp: false,
|
||||||
|
enablePullDown: true,
|
||||||
|
isDialog: true,
|
||||||
|
itemBuilder: (_, index) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: () {
|
||||||
|
Get.back();
|
||||||
|
// 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: [
|
||||||
|
Text(
|
||||||
|
controller.list[index].name,
|
||||||
|
style: TextStyle(fontSize: ScreenAdaper.height(25)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
// onSelected: (SaleQuotationItemModel info) {
|
||||||
|
// Get.back();
|
||||||
|
// // groups.add(info);
|
||||||
|
// },
|
||||||
|
),
|
||||||
|
width: Get.width - ScreenAdaper.width(50))
|
||||||
|
.then((value) => Get.delete<ItemSearchMoreController>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GroupSearchMoreController extends GetxController
|
||||||
|
with BaseSearchMore<SaleQuotationModel> {
|
||||||
|
@override
|
||||||
|
Future<List<SaleQuotationModel>> getData({bool isRefresh = false}) async {
|
||||||
|
List<SaleQuotationModel> newList = [
|
||||||
|
SaleQuotationModel(name: '中间过渡架电控部分', items: []),
|
||||||
|
SaleQuotationModel(name: '端头架电控部分', items: []),
|
||||||
|
SaleQuotationModel(name: '主阀部分', items: []),
|
||||||
|
SaleQuotationModel(name: '自动反冲洗过滤器部分', items: []),
|
||||||
|
SaleQuotationModel(name: '位移测量部分', items: []),
|
||||||
|
SaleQuotationModel(name: '压力检测部分', items: []),
|
||||||
|
SaleQuotationModel(name: '煤机定位部分', items: []),
|
||||||
|
SaleQuotationModel(name: '姿态检测部分', items: []),
|
||||||
|
];
|
||||||
|
list.assignAll(newList);
|
||||||
|
return newList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ItemSearchMoreController extends GetxController
|
||||||
|
with BaseSearchMore<SaleQuotationItemModel> {
|
||||||
|
@override
|
||||||
|
Future<List<SaleQuotationItemModel>> getData({bool isRefresh = false}) async {
|
||||||
|
List<SaleQuotationItemModel> newList = [
|
||||||
|
SaleQuotationItemModel(name: '矿用本安型支架控制器', unit: '台', spec: 'ZDYZ-Z'),
|
||||||
|
SaleQuotationItemModel(name: '矿用本安型电磁阀驱动器'),
|
||||||
|
SaleQuotationItemModel(name: '矿用隔爆兼本安型电源'),
|
||||||
|
SaleQuotationItemModel(name: '矿用本安型隔离耦合器'),
|
||||||
|
SaleQuotationItemModel(name: '钢丝编织橡胶护套连接器'),
|
||||||
|
SaleQuotationItemModel(name: '钢丝编织橡胶护套连接器', remark: '控制器-控制器'),
|
||||||
|
SaleQuotationItemModel(name: '钢丝编织橡胶护套连接器', remark: '控制器-驱动器'),
|
||||||
|
SaleQuotationItemModel(name: '钢丝编织橡胶护套连接器', remark: '控制器-隔离耦合器'),
|
||||||
|
SaleQuotationItemModel(name: '矿用本安型支架无线遥控器'),
|
||||||
|
SaleQuotationItemModel(name: '矿用隔爆兼本安型电源'),
|
||||||
|
SaleQuotationItemModel(name: '电液换向阀(10功能10接口)', remark: '中间过渡架主阀组'),
|
||||||
|
SaleQuotationItemModel(name: '电液换向阀(20功能20接口)', remark: '端头架主阀组'),
|
||||||
|
SaleQuotationItemModel(name: '自动反冲洗过滤装置', remark: '流量:900L/min,过滤精度25μm'),
|
||||||
|
SaleQuotationItemModel(name: '全自动反冲洗过滤器电缆', remark: '控制器-自动反冲洗'),
|
||||||
|
SaleQuotationItemModel(name: '矿用本安型位移传感器'),
|
||||||
|
SaleQuotationItemModel(name: '矿用本安型压力传感器'),
|
||||||
|
SaleQuotationItemModel(name: '矿用本安型红外发射器'),
|
||||||
|
SaleQuotationItemModel(name: '矿用本安型LED信号灯'),
|
||||||
|
SaleQuotationItemModel(name: '倾角传感器'),
|
||||||
|
SaleQuotationItemModel(name: '各类安装附件'),
|
||||||
|
];
|
||||||
|
list.assignAll(newList);
|
||||||
|
return newList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ 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/widgets/core/sk_number_input.dart';
|
import 'package:sk_base_mobile/widgets/core/sk_number_input.dart';
|
||||||
import 'package:sk_base_mobile/widgets/core/sk_text_input.dart';
|
import 'package:sk_base_mobile/widgets/core/sk_text_input.dart';
|
||||||
|
import 'package:sk_base_mobile/widgets/empty.dart';
|
||||||
import 'package:sk_base_mobile/widgets/sk_appbar.dart';
|
import 'package:sk_base_mobile/widgets/sk_appbar.dart';
|
||||||
import 'package:flutter_sticky_header/flutter_sticky_header.dart';
|
import 'package:flutter_sticky_header/flutter_sticky_header.dart';
|
||||||
|
|
||||||
|
@ -28,16 +29,28 @@ class SaleQuotationPage extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
|
||||||
|
floatingActionButton: FloatingActionButton(
|
||||||
|
onPressed: () {
|
||||||
|
controller.addGroup();
|
||||||
|
},
|
||||||
|
child: const Icon(Icons.add),
|
||||||
|
),
|
||||||
appBar: SkAppbar(
|
appBar: SkAppbar(
|
||||||
title: '报价计算',
|
title: '报价计算',
|
||||||
action: [
|
action: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {},
|
onPressed: () {
|
||||||
|
controller.addGroup();
|
||||||
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.add, color: AppTheme.white),
|
Icon(Icons.save, color: AppTheme.white),
|
||||||
|
SizedBox(
|
||||||
|
width: ScreenAdaper.width(10),
|
||||||
|
),
|
||||||
Text(
|
Text(
|
||||||
'添加组',
|
'保存',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppTheme.white,
|
color: AppTheme.white,
|
||||||
fontSize: ScreenAdaper.height(25),
|
fontSize: ScreenAdaper.height(25),
|
||||||
|
@ -51,63 +64,70 @@ class SaleQuotationPage extends StatelessWidget {
|
||||||
bottom: ScreenAdaper.isLandspace() ? false : true,
|
bottom: ScreenAdaper.isLandspace() ? false : true,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
builderHeader(),
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: headerBgcolor,
|
|
||||||
border: Border(
|
|
||||||
bottom: BorderSide(
|
|
||||||
color: AppTheme.nearlyBlack.withOpacity(0.5)))),
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
left: ScreenAdaper.width(20),
|
|
||||||
top: ScreenAdaper.height(10),
|
|
||||||
bottom: ScreenAdaper.height(10)),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'名称',
|
|
||||||
style: headerTitleStyle,
|
|
||||||
),
|
|
||||||
const Spacer(),
|
|
||||||
Container(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
width: quantityWidth,
|
|
||||||
// constraints: BoxConstraints(minWidth: quantityWidth),
|
|
||||||
child: Text(
|
|
||||||
'数量',
|
|
||||||
style: headerTitleStyle,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
width: unitPriceWidth,
|
|
||||||
// constraints: BoxConstraints(minWidth: unitPriceWidth),
|
|
||||||
child: Text(
|
|
||||||
'单价',
|
|
||||||
style: headerTitleStyle,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
width: amountWidth,
|
|
||||||
child: Text(
|
|
||||||
'总价',
|
|
||||||
style: headerTitleStyle,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Obx(() => CustomScrollView(
|
child: Obx(() => controller.groups.isEmpty
|
||||||
slivers: controller.groups
|
? Empty(text: '请先添加分组')
|
||||||
.mapIndexed<Widget>((index, e) => buildBody(e, index))
|
: CustomScrollView(
|
||||||
.toList(),
|
slivers: controller.groups
|
||||||
))),
|
.mapIndexed<Widget>(
|
||||||
|
(index, e) => buildBody(e, index))
|
||||||
|
.toList(),
|
||||||
|
))),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget builderHeader() {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: headerBgcolor,
|
||||||
|
border: Border(
|
||||||
|
bottom:
|
||||||
|
BorderSide(color: AppTheme.nearlyBlack.withOpacity(0.5)))),
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
left: ScreenAdaper.width(20),
|
||||||
|
top: ScreenAdaper.height(10),
|
||||||
|
bottom: ScreenAdaper.height(10)),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'名称',
|
||||||
|
style: headerTitleStyle,
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
width: quantityWidth,
|
||||||
|
// constraints: BoxConstraints(minWidth: quantityWidth),
|
||||||
|
child: Text(
|
||||||
|
'数量',
|
||||||
|
style: headerTitleStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
width: unitPriceWidth,
|
||||||
|
// constraints: BoxConstraints(minWidth: unitPriceWidth),
|
||||||
|
child: Text(
|
||||||
|
'单价',
|
||||||
|
style: headerTitleStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
width: amountWidth,
|
||||||
|
child: Text(
|
||||||
|
'总价',
|
||||||
|
style: headerTitleStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
Widget buildBody(SaleQuotationModel group, int index) {
|
Widget buildBody(SaleQuotationModel group, int index) {
|
||||||
final titleStyle = TextStyle(
|
final titleStyle = TextStyle(
|
||||||
fontSize: ScreenAdaper.height(30),
|
fontSize: ScreenAdaper.height(30),
|
||||||
|
@ -156,14 +176,20 @@ class SaleQuotationPage extends StatelessWidget {
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ModalUtil.confirm(title: '确定要删除此组吗?', onConfirm: () {});
|
ModalUtil.confirm(
|
||||||
|
title: '确定要删除此组吗?',
|
||||||
|
onConfirm: () {
|
||||||
|
controller.removeGroup(index);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.remove_circle_outline_outlined,
|
Icons.remove_circle_outline_outlined,
|
||||||
color: AppTheme.nearlyBlack,
|
color: AppTheme.nearlyBlack,
|
||||||
)),
|
)),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {},
|
onPressed: () {
|
||||||
|
controller.addItems();
|
||||||
|
},
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.add_circle_outline,
|
Icons.add_circle_outline,
|
||||||
color: AppTheme.nearlyBlack,
|
color: AppTheme.nearlyBlack,
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||||
|
import 'package:sk_base_mobile/app_theme.dart';
|
||||||
|
import 'package:sk_base_mobile/constants/bg_color.dart';
|
||||||
|
import 'package:sk_base_mobile/models/base_search_more.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';
|
||||||
|
|
||||||
|
class SkSingleSearchMore<T> extends StatelessWidget {
|
||||||
|
final Function(T)? onSelected;
|
||||||
|
final Function(T)? beforeSelectedCheck;
|
||||||
|
// ignore: prefer_typing_uninitialized_variables
|
||||||
|
final BaseSearchMore controller;
|
||||||
|
final bool enablePullUp;
|
||||||
|
final bool enablePullDown;
|
||||||
|
final bool isDialog;
|
||||||
|
|
||||||
|
final Function(BuildContext, int)? itemBuilder;
|
||||||
|
SkSingleSearchMore(
|
||||||
|
{super.key,
|
||||||
|
required this.controller,
|
||||||
|
this.onSelected,
|
||||||
|
this.isDialog = true,
|
||||||
|
this.beforeSelectedCheck,
|
||||||
|
this.itemBuilder,
|
||||||
|
this.enablePullDown = true,
|
||||||
|
this.enablePullUp = true});
|
||||||
|
final listTitleTextStyle =
|
||||||
|
TextStyle(fontSize: ScreenAdaper.height(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: [
|
||||||
|
Container(
|
||||||
|
height: ScreenAdaper.height(60),
|
||||||
|
padding: EdgeInsets.only(bottom: ScreenAdaper.height(15)),
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Center(
|
||||||
|
child: Text(
|
||||||
|
'请选择',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: ScreenAdaper.height(30),
|
||||||
|
fontWeight: FontWeight.w600),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
right: 0,
|
||||||
|
child:
|
||||||
|
GestureDetector(onTap: () {}, child: Icon(Icons.close)))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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() {
|
||||||
|
return Obx(() => SmartRefresher(
|
||||||
|
enablePullDown: enablePullDown,
|
||||||
|
enablePullUp: enablePullUp,
|
||||||
|
controller: controller.refreshController,
|
||||||
|
onLoading: controller.onLoading,
|
||||||
|
onRefresh: controller.onRefresh,
|
||||||
|
child: controller.refreshController.isLoading
|
||||||
|
? const SizedBox()
|
||||||
|
: controller.list.isEmpty
|
||||||
|
? const Center(
|
||||||
|
child: Empty(text: '暂无数据'),
|
||||||
|
)
|
||||||
|
: ListView.separated(
|
||||||
|
separatorBuilder: (context, index) => const Divider(
|
||||||
|
color: AppTheme.dividerColor,
|
||||||
|
),
|
||||||
|
itemCount: controller.list.length,
|
||||||
|
itemBuilder: (_, index) => itemBuilder != null
|
||||||
|
? 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].name}',
|
||||||
|
style: TextStyle(fontSize: ScreenAdaper.height(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}'),
|
||||||
|
// )
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,15 +9,17 @@ class Empty extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Center(
|
return Center(
|
||||||
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
|
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||||
// Center(
|
Center(
|
||||||
// child: Image(
|
child: Icon(Icons.error_outline,
|
||||||
// height: ScreenAdaper.height(130),
|
size: ScreenAdaper.height(40), color: Colors.red)),
|
||||||
// image: const AssetImage('assets/images/empty_icon.png'))),
|
SizedBox(
|
||||||
|
width: ScreenAdaper.width(10),
|
||||||
|
),
|
||||||
Text(
|
Text(
|
||||||
text ?? '',
|
text ?? '',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(fontSize: ScreenAdaper.height(30)),
|
style: TextStyle(fontSize: ScreenAdaper.height(35)),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
358
pubspec.lock
358
pubspec.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue