2024-04-03 13:45:34 +08:00
|
|
|
|
import 'dart:ffi';
|
|
|
|
|
|
2024-04-01 14:27:44 +08:00
|
|
|
|
import 'package:collection/collection.dart';
|
2024-04-01 08:41:52 +08:00
|
|
|
|
import 'package:flutter/material.dart';
|
2024-04-01 14:27:44 +08:00
|
|
|
|
import 'package:flutter_slidable/flutter_slidable.dart';
|
2024-04-01 11:38:10 +08:00
|
|
|
|
import 'package:get/get.dart';
|
|
|
|
|
import 'package:sk_base_mobile/app_theme.dart';
|
2024-04-01 17:35:34 +08:00
|
|
|
|
import 'package:sk_base_mobile/models/sale_quotation.model.dart';
|
2024-04-03 13:45:34 +08:00
|
|
|
|
import 'package:sk_base_mobile/screens/sale_quotation/components/sale_quotation_drawer.dart';
|
2024-04-01 17:35:34 +08:00
|
|
|
|
import 'package:sk_base_mobile/screens/sale_quotation/sale_quotation.controller.dart';
|
2024-04-01 11:38:10 +08:00
|
|
|
|
import 'package:sk_base_mobile/util/modal.util.dart';
|
|
|
|
|
import 'package:sk_base_mobile/util/screen_adaper_util.dart';
|
2024-04-03 13:45:34 +08:00
|
|
|
|
import 'package:sk_base_mobile/util/snack_bar.util.dart';
|
2024-04-01 17:35:34 +08:00
|
|
|
|
import 'package:sk_base_mobile/widgets/core/sk_number_input.dart';
|
|
|
|
|
import 'package:sk_base_mobile/widgets/core/sk_text_input.dart';
|
2024-04-02 12:24:08 +08:00
|
|
|
|
import 'package:sk_base_mobile/widgets/empty.dart';
|
2024-04-01 08:41:52 +08:00
|
|
|
|
import 'package:sk_base_mobile/widgets/sk_appbar.dart';
|
2024-04-01 11:38:10 +08:00
|
|
|
|
import 'package:flutter_sticky_header/flutter_sticky_header.dart';
|
2024-04-03 13:45:34 +08:00
|
|
|
|
import 'package:math_expressions/math_expressions.dart';
|
|
|
|
|
import 'dart:math' as math;
|
2024-04-01 08:41:52 +08:00
|
|
|
|
|
|
|
|
|
class SaleQuotationPage extends StatelessWidget {
|
2024-04-01 11:38:10 +08:00
|
|
|
|
SaleQuotationPage({super.key});
|
|
|
|
|
final controller = Get.put(SaleQuotationController());
|
2024-04-03 13:45:34 +08:00
|
|
|
|
final quantityWidth = 140.0;
|
|
|
|
|
final unitPriceWidth = 140.0;
|
|
|
|
|
final amountWidth = 140.0;
|
2024-04-01 11:38:10 +08:00
|
|
|
|
final headerTitleStyle = TextStyle(
|
2024-04-01 17:35:34 +08:00
|
|
|
|
fontSize: ScreenAdaper.height(30),
|
2024-04-01 11:38:10 +08:00
|
|
|
|
fontWeight: FontWeight.w600,
|
2024-04-01 14:27:44 +08:00
|
|
|
|
color: AppTheme.nearlyBlack);
|
2024-04-03 13:45:34 +08:00
|
|
|
|
final headerBgcolor = const Color.fromARGB(255, 238, 238, 238);
|
2024-04-01 17:35:34 +08:00
|
|
|
|
|
2024-04-01 08:41:52 +08:00
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
return Scaffold(
|
2024-04-03 13:45:34 +08:00
|
|
|
|
key: controller.scaffoldKey,
|
|
|
|
|
endDrawer: Drawer(
|
|
|
|
|
// 从右到左出现
|
|
|
|
|
child: SaleQuotationEndDrawer(),
|
2024-04-02 12:24:08 +08:00
|
|
|
|
),
|
2024-04-01 14:27:44 +08:00
|
|
|
|
appBar: SkAppbar(
|
|
|
|
|
title: '报价计算',
|
|
|
|
|
action: [
|
2024-04-03 13:45:34 +08:00
|
|
|
|
IconButton(
|
|
|
|
|
onPressed: () {
|
|
|
|
|
controller.scaffoldKey.currentState?.openEndDrawer();
|
|
|
|
|
},
|
|
|
|
|
icon: const Icon(Icons.more_horiz_outlined, color: AppTheme.white),
|
|
|
|
|
)
|
2024-04-01 14:27:44 +08:00
|
|
|
|
],
|
|
|
|
|
),
|
2024-04-01 14:59:20 +08:00
|
|
|
|
body: SafeArea(
|
|
|
|
|
bottom: ScreenAdaper.isLandspace() ? false : true,
|
2024-04-03 13:45:34 +08:00
|
|
|
|
child: Stack(children: [
|
|
|
|
|
Column(
|
|
|
|
|
children: [
|
|
|
|
|
builderHeader(),
|
|
|
|
|
Expanded(
|
|
|
|
|
child: Obx(() => controller.groups.isEmpty
|
|
|
|
|
? Empty(text: '请先添加分组')
|
|
|
|
|
: CustomScrollView(
|
|
|
|
|
slivers: controller.groups
|
|
|
|
|
.mapIndexed<Widget>(
|
|
|
|
|
(index, e) => buildBody(index))
|
|
|
|
|
.toList(),
|
|
|
|
|
))),
|
|
|
|
|
SizedBox(
|
|
|
|
|
height: ScreenAdaper.height(100),
|
|
|
|
|
child: buildTotalCostRow(),
|
|
|
|
|
),
|
|
|
|
|
SizedBox(
|
|
|
|
|
height: ScreenAdaper.height(100),
|
|
|
|
|
child: buildTotalSalesPriceRow(),
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
// Positioned(
|
|
|
|
|
// bottom: ScreenAdaper.height(10),
|
|
|
|
|
// right: ScreenAdaper.height(10),
|
|
|
|
|
// child: IconButton(
|
|
|
|
|
// padding: EdgeInsets.all(ScreenAdaper.height(20)),
|
|
|
|
|
// style: ButtonStyle(
|
|
|
|
|
// backgroundColor: MaterialStateProperty.all<Color>(
|
|
|
|
|
// AppTheme.primaryColorLight)),
|
|
|
|
|
// onPressed: () {
|
|
|
|
|
// controller.addGroup();
|
|
|
|
|
// },
|
|
|
|
|
// icon: Icon(
|
|
|
|
|
// Icons.add,
|
|
|
|
|
// size: ScreenAdaper.height(40),
|
|
|
|
|
// ),
|
|
|
|
|
// ))
|
|
|
|
|
]),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget buildTotalSalesPriceRow() {
|
|
|
|
|
final formulaController =
|
|
|
|
|
TextEditingController(text: controller.formula.value);
|
|
|
|
|
return Container(
|
|
|
|
|
padding: EdgeInsets.symmetric(
|
|
|
|
|
horizontal: ScreenAdaper.width(20),
|
|
|
|
|
vertical: ScreenAdaper.height(10)),
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
border: Border(
|
|
|
|
|
top: BorderSide(width: 1, color: Colors.grey[200]!),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
child: Row(
|
|
|
|
|
children: [
|
|
|
|
|
Text(
|
|
|
|
|
'合计',
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
fontSize: ScreenAdaper.height(30), fontWeight: FontWeight.w600),
|
|
|
|
|
),
|
|
|
|
|
Expanded(
|
|
|
|
|
child: Obx(
|
|
|
|
|
() => Container(
|
|
|
|
|
alignment: Alignment.centerLeft,
|
|
|
|
|
padding:
|
|
|
|
|
EdgeInsets.symmetric(horizontal: ScreenAdaper.width(10)),
|
|
|
|
|
height: ScreenAdaper.height(100),
|
|
|
|
|
width: ScreenAdaper.width(100),
|
|
|
|
|
child: controller.isFormulaEditing.value
|
|
|
|
|
? SkTextInput(
|
|
|
|
|
hint: '',
|
|
|
|
|
isDense: true,
|
|
|
|
|
autoFocus: true,
|
|
|
|
|
onFieldSubmitted: (value) {
|
|
|
|
|
controller.formula.value = value;
|
|
|
|
|
controller.isFormulaEditing.value = false;
|
|
|
|
|
},
|
|
|
|
|
validator: (String? value) {
|
|
|
|
|
if (value == null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
Parser p = Parser();
|
|
|
|
|
Expression exp = p.parse(value);
|
|
|
|
|
Variable x = Variable('成本');
|
|
|
|
|
ContextModel cm = ContextModel()
|
|
|
|
|
..bindVariable(
|
|
|
|
|
x, Number(controller.totalCost.value));
|
|
|
|
|
exp.evaluate(EvaluationType.REAL, cm);
|
|
|
|
|
return null;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
return '公式错误';
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
onChanged: (String formula) {
|
|
|
|
|
try {
|
|
|
|
|
controller.calculateTotal(newFormula: formula);
|
|
|
|
|
} catch (e) {}
|
|
|
|
|
},
|
|
|
|
|
onTapOutside: (String value) {
|
|
|
|
|
controller.formula.value = value;
|
|
|
|
|
controller.isFormulaEditing.value = false;
|
|
|
|
|
},
|
|
|
|
|
contentPadding: EdgeInsets.symmetric(
|
|
|
|
|
horizontal: ScreenAdaper.width(20),
|
|
|
|
|
vertical: ScreenAdaper.height(10)),
|
|
|
|
|
textController: formulaController)
|
|
|
|
|
: InkWell(
|
|
|
|
|
onTap: () {
|
|
|
|
|
controller.isFormulaEditing.value = true;
|
|
|
|
|
},
|
|
|
|
|
child: Text('(${controller.formula})',
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
fontSize: ScreenAdaper.height(30),
|
|
|
|
|
color: AppTheme.grey)),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
// IconButton(
|
|
|
|
|
// onPressed: () {
|
|
|
|
|
// controller.isFormulaEditing.value =
|
|
|
|
|
// !controller.isFormulaEditing.value;
|
|
|
|
|
// },
|
|
|
|
|
// icon: Icon(Icons.edit, size: ScreenAdaper.height(30)),
|
|
|
|
|
// ),
|
|
|
|
|
Obx(
|
|
|
|
|
() => Text(
|
|
|
|
|
'¥${controller.totalPrice.value}',
|
|
|
|
|
textAlign: TextAlign.right,
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
fontSize: ScreenAdaper.height(30),
|
|
|
|
|
fontWeight: FontWeight.w600),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget buildTotalCostRow() {
|
|
|
|
|
return Container(
|
|
|
|
|
padding: EdgeInsets.symmetric(
|
|
|
|
|
horizontal: ScreenAdaper.width(20),
|
|
|
|
|
vertical: ScreenAdaper.height(10)),
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
border: Border(
|
|
|
|
|
top: BorderSide(width: 1, color: Colors.grey[200]!),
|
2024-04-01 14:59:20 +08:00
|
|
|
|
),
|
2024-04-01 11:38:10 +08:00
|
|
|
|
),
|
2024-04-03 13:45:34 +08:00
|
|
|
|
child: Row(
|
|
|
|
|
children: [
|
|
|
|
|
Text(
|
|
|
|
|
'成本',
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
fontSize: ScreenAdaper.height(30), fontWeight: FontWeight.w600),
|
|
|
|
|
),
|
|
|
|
|
const Spacer(),
|
|
|
|
|
Obx(
|
|
|
|
|
() => Text(
|
|
|
|
|
'¥${controller.totalCost.value}',
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
fontSize: ScreenAdaper.height(30),
|
|
|
|
|
fontWeight: FontWeight.w600),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
),
|
2024-04-01 08:41:52 +08:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-02 12:24:08 +08:00
|
|
|
|
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,
|
2024-04-03 13:45:34 +08:00
|
|
|
|
width: ScreenAdaper.width(quantityWidth),
|
2024-04-02 12:24:08 +08:00
|
|
|
|
// constraints: BoxConstraints(minWidth: quantityWidth),
|
|
|
|
|
child: Text(
|
|
|
|
|
'数量',
|
|
|
|
|
style: headerTitleStyle,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
Container(
|
|
|
|
|
alignment: Alignment.center,
|
2024-04-03 13:45:34 +08:00
|
|
|
|
width: ScreenAdaper.width(unitPriceWidth),
|
|
|
|
|
// constraints: BoxConstraints(minWidth: ScreenAdaper.width(unitPriceWidth)),
|
2024-04-02 12:24:08 +08:00
|
|
|
|
child: Text(
|
|
|
|
|
'单价',
|
|
|
|
|
style: headerTitleStyle,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
Container(
|
|
|
|
|
alignment: Alignment.center,
|
2024-04-03 13:45:34 +08:00
|
|
|
|
width: ScreenAdaper.width(amountWidth),
|
2024-04-02 12:24:08 +08:00
|
|
|
|
child: Text(
|
|
|
|
|
'总价',
|
|
|
|
|
style: headerTitleStyle,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-03 13:45:34 +08:00
|
|
|
|
Widget buildBody(int groupIndex) {
|
2024-04-01 11:38:10 +08:00
|
|
|
|
return SliverStickyHeader.builder(
|
2024-04-03 13:45:34 +08:00
|
|
|
|
builder: (context, state) => buildGroupHeader(groupIndex, state),
|
2024-04-02 16:22:21 +08:00
|
|
|
|
sliver: Obx(() => !controller.groups[groupIndex].isExpanded.value
|
2024-04-01 14:27:44 +08:00
|
|
|
|
? SliverList(
|
|
|
|
|
delegate: SliverChildBuilderDelegate(
|
2024-04-03 13:45:34 +08:00
|
|
|
|
(context, i) => const SizedBox(),
|
2024-04-01 14:27:44 +08:00
|
|
|
|
childCount: 0,
|
|
|
|
|
))
|
|
|
|
|
: SliverList(
|
|
|
|
|
delegate: SliverChildBuilderDelegate(
|
2024-04-03 13:45:34 +08:00
|
|
|
|
(context, int i) => buildRow(groupIndex, i),
|
|
|
|
|
childCount: !controller.groups[groupIndex].isExpanded.value
|
|
|
|
|
? 0
|
|
|
|
|
: controller.groups[groupIndex].items.length,
|
|
|
|
|
),
|
|
|
|
|
)),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget buildGroupHeader(int groupIndex, SliverStickyHeaderState state) {
|
|
|
|
|
final titleStyle = TextStyle(
|
|
|
|
|
fontSize: ScreenAdaper.height(30),
|
|
|
|
|
color: AppTheme.nearlyBlack,
|
|
|
|
|
fontWeight: FontWeight.w600);
|
|
|
|
|
return Container(
|
|
|
|
|
height: ScreenAdaper.height(80),
|
|
|
|
|
color: headerBgcolor.withOpacity(1.0 - state.scrollPercentage),
|
|
|
|
|
alignment: Alignment.centerLeft,
|
|
|
|
|
child: InkWell(
|
|
|
|
|
onTap: () {
|
|
|
|
|
controller.groups[groupIndex].isExpanded.value =
|
|
|
|
|
!controller.groups[groupIndex].isExpanded.value;
|
|
|
|
|
},
|
|
|
|
|
child: Row(
|
|
|
|
|
children: [
|
|
|
|
|
Obx(() => controller.groups[groupIndex].isExpanded.value
|
|
|
|
|
? IconButton(
|
2024-04-01 14:27:44 +08:00
|
|
|
|
padding: EdgeInsets.zero,
|
2024-04-03 13:45:34 +08:00
|
|
|
|
onPressed: () {
|
|
|
|
|
controller.groups[groupIndex].isExpanded.value =
|
|
|
|
|
false;
|
2024-04-02 16:22:21 +08:00
|
|
|
|
},
|
2024-04-03 13:45:34 +08:00
|
|
|
|
icon: const Icon(
|
|
|
|
|
Icons.expand_more,
|
|
|
|
|
color: AppTheme.nearlyBlack,
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
: IconButton(
|
|
|
|
|
padding: EdgeInsets.zero,
|
|
|
|
|
onPressed: () {
|
|
|
|
|
controller.groups[groupIndex].isExpanded.value = true;
|
|
|
|
|
},
|
|
|
|
|
icon: const Icon(
|
|
|
|
|
Icons.chevron_right,
|
|
|
|
|
color: AppTheme.nearlyBlack,
|
|
|
|
|
),
|
|
|
|
|
)),
|
|
|
|
|
Text(
|
|
|
|
|
controller.groups[groupIndex].name,
|
|
|
|
|
style: titleStyle,
|
|
|
|
|
),
|
|
|
|
|
const Spacer(),
|
|
|
|
|
IconButton(
|
|
|
|
|
onPressed: () {
|
|
|
|
|
ModalUtil.confirm(
|
|
|
|
|
title: '确定要删除此组吗?',
|
|
|
|
|
onConfirm: () {
|
|
|
|
|
controller.removeGroup(groupIndex);
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
icon: const Icon(
|
|
|
|
|
Icons.delete_outline,
|
|
|
|
|
color: AppTheme.nearlyBlack,
|
|
|
|
|
)),
|
|
|
|
|
IconButton(
|
|
|
|
|
onPressed: () {
|
|
|
|
|
controller.addItems(groupIndex);
|
|
|
|
|
},
|
|
|
|
|
icon: const Icon(
|
|
|
|
|
Icons.add,
|
|
|
|
|
color: AppTheme.nearlyBlack,
|
|
|
|
|
)),
|
|
|
|
|
],
|
|
|
|
|
)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget buildRow(int groupIndex, int rowIndex) {
|
|
|
|
|
final subTextStyle =
|
|
|
|
|
TextStyle(color: AppTheme.grey, fontSize: ScreenAdaper.height(25));
|
|
|
|
|
return Slidable(
|
|
|
|
|
key: UniqueKey(),
|
|
|
|
|
endActionPane: ActionPane(
|
|
|
|
|
extentRatio: 0.2,
|
|
|
|
|
motion: const DrawerMotion(),
|
|
|
|
|
children: [
|
|
|
|
|
SlidableAction(
|
|
|
|
|
padding: EdgeInsets.zero,
|
|
|
|
|
onPressed: (_) {
|
|
|
|
|
controller.removeItem(groupIndex, rowIndex);
|
|
|
|
|
},
|
|
|
|
|
backgroundColor: AppTheme.dangerColor,
|
|
|
|
|
foregroundColor: Colors.white,
|
|
|
|
|
icon: Icons.delete,
|
|
|
|
|
label: '删除',
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
child: Container(
|
|
|
|
|
padding: EdgeInsets.only(
|
|
|
|
|
left: ScreenAdaper.width(20),
|
|
|
|
|
top: ScreenAdaper.height(15),
|
|
|
|
|
bottom: ScreenAdaper.height(15),
|
|
|
|
|
),
|
|
|
|
|
constraints: BoxConstraints(minHeight: ScreenAdaper.height(100)),
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
border: Border(
|
|
|
|
|
bottom: BorderSide(width: 1, color: Colors.grey[200]!),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
child: Row(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
|
|
|
children: [
|
|
|
|
|
Expanded(
|
|
|
|
|
child: Column(
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
Row(
|
|
|
|
|
children: [
|
|
|
|
|
Expanded(
|
|
|
|
|
child: Text(
|
|
|
|
|
controller.groups[groupIndex].items[rowIndex].name,
|
|
|
|
|
style: TextStyle(
|
|
|
|
|
fontWeight: FontWeight.w600,
|
|
|
|
|
fontSize: ScreenAdaper.height(30)),
|
|
|
|
|
),
|
2024-04-01 14:27:44 +08:00
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
2024-04-03 13:45:34 +08:00
|
|
|
|
if (controller.groups[groupIndex].items[rowIndex].spec !=
|
|
|
|
|
null)
|
|
|
|
|
Row(
|
|
|
|
|
children: [
|
|
|
|
|
Text(
|
|
|
|
|
'规格、型号: ',
|
|
|
|
|
style: subTextStyle,
|
|
|
|
|
),
|
|
|
|
|
Text(
|
|
|
|
|
controller.groups[groupIndex].items[rowIndex].spec ??
|
|
|
|
|
'',
|
|
|
|
|
style: subTextStyle,
|
|
|
|
|
),
|
|
|
|
|
],
|
2024-04-01 14:27:44 +08:00
|
|
|
|
),
|
2024-04-03 13:45:34 +08:00
|
|
|
|
if (controller.groups[groupIndex].items[rowIndex].unit !=
|
|
|
|
|
null)
|
|
|
|
|
Row(
|
|
|
|
|
children: [
|
|
|
|
|
Text(
|
|
|
|
|
'单位: ',
|
|
|
|
|
style: subTextStyle,
|
|
|
|
|
),
|
|
|
|
|
Text(
|
|
|
|
|
controller.groups[groupIndex].items[rowIndex].unit ??
|
|
|
|
|
'',
|
|
|
|
|
style: subTextStyle,
|
|
|
|
|
),
|
|
|
|
|
],
|
2024-04-01 14:27:44 +08:00
|
|
|
|
),
|
2024-04-03 13:45:34 +08:00
|
|
|
|
if (controller.groups[groupIndex].items[rowIndex].remark !=
|
|
|
|
|
null)
|
|
|
|
|
Row(
|
2024-04-01 14:27:44 +08:00
|
|
|
|
children: [
|
2024-04-03 13:45:34 +08:00
|
|
|
|
Text(
|
|
|
|
|
'备注: ',
|
|
|
|
|
style: subTextStyle,
|
|
|
|
|
),
|
2024-04-01 14:27:44 +08:00
|
|
|
|
Expanded(
|
2024-04-03 13:45:34 +08:00
|
|
|
|
child: Text(
|
|
|
|
|
'${controller.groups[groupIndex].items[rowIndex].remark ?? ''}${controller.groups[groupIndex].items[rowIndex].remark ?? ''}${controller.products[rowIndex].remark ?? ''}',
|
|
|
|
|
overflow: TextOverflow.ellipsis,
|
|
|
|
|
style: subTextStyle,
|
2024-04-01 11:38:10 +08:00
|
|
|
|
),
|
2024-04-01 14:27:44 +08:00
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
2024-04-03 13:45:34 +08:00
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
VerticalDivider(),
|
|
|
|
|
buildEditCell<int>(
|
|
|
|
|
Container(
|
|
|
|
|
alignment: Alignment.center,
|
|
|
|
|
width: ScreenAdaper.width(quantityWidth),
|
|
|
|
|
child: Text(
|
|
|
|
|
'${controller.groups[groupIndex].items[rowIndex].quantity}',
|
|
|
|
|
style: TextStyle(fontSize: ScreenAdaper.height(25)),
|
2024-04-01 14:27:44 +08:00
|
|
|
|
),
|
2024-04-01 11:38:10 +08:00
|
|
|
|
),
|
2024-04-03 13:45:34 +08:00
|
|
|
|
groupIndex: groupIndex,
|
|
|
|
|
rowIndex: rowIndex,
|
|
|
|
|
field: 'quantity',
|
|
|
|
|
inputWidth: ScreenAdaper.width(quantityWidth),
|
|
|
|
|
value: controller.groups[groupIndex].items[rowIndex].quantity,
|
|
|
|
|
func: (value) {
|
|
|
|
|
// 取消失去焦点,并且弹窗警告
|
|
|
|
|
bool isValid = value > 0;
|
|
|
|
|
if (!isValid) {
|
|
|
|
|
SnackBarUtil().error('数量必须>0,若想删除产品0,请左滑');
|
|
|
|
|
}
|
|
|
|
|
return isValid;
|
|
|
|
|
}),
|
|
|
|
|
buildEditCell<int>(
|
|
|
|
|
Container(
|
|
|
|
|
alignment: Alignment.center,
|
|
|
|
|
width: ScreenAdaper.width(unitPriceWidth),
|
|
|
|
|
child: Text(
|
|
|
|
|
'${controller.groups[groupIndex].items[rowIndex].cost}',
|
|
|
|
|
style: TextStyle(fontSize: ScreenAdaper.height(25)),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
groupIndex: groupIndex,
|
|
|
|
|
rowIndex: rowIndex,
|
|
|
|
|
field: 'cost',
|
|
|
|
|
inputWidth: ScreenAdaper.width(unitPriceWidth),
|
|
|
|
|
value: controller.groups[groupIndex].items[rowIndex].cost),
|
|
|
|
|
buildEditCell<int>(
|
|
|
|
|
Container(
|
|
|
|
|
alignment: Alignment.center,
|
|
|
|
|
width: ScreenAdaper.width(amountWidth),
|
|
|
|
|
child: Text(
|
|
|
|
|
'${controller.groups[groupIndex].items[rowIndex].amount}',
|
|
|
|
|
style: TextStyle(fontSize: ScreenAdaper.height(25)),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
groupIndex: groupIndex,
|
|
|
|
|
rowIndex: rowIndex,
|
|
|
|
|
field: 'amount',
|
|
|
|
|
inputWidth: ScreenAdaper.width(amountWidth),
|
|
|
|
|
value: controller.groups[groupIndex].items[rowIndex].amount),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
2024-04-01 11:38:10 +08:00
|
|
|
|
);
|
2024-04-01 08:41:52 +08:00
|
|
|
|
}
|
2024-04-01 14:27:44 +08:00
|
|
|
|
|
2024-04-03 13:45:34 +08:00
|
|
|
|
Widget buildEditCell<T>(
|
|
|
|
|
Widget content, {
|
|
|
|
|
required int groupIndex,
|
|
|
|
|
required int rowIndex,
|
|
|
|
|
required String field,
|
|
|
|
|
required double inputWidth,
|
|
|
|
|
required dynamic value,
|
|
|
|
|
Function(dynamic)? func,
|
|
|
|
|
}) {
|
2024-04-01 17:35:34 +08:00
|
|
|
|
return Obx(() => controller.editingcell[0] == groupIndex &&
|
|
|
|
|
controller.editingcell[1] == rowIndex &&
|
|
|
|
|
controller.editingcell[2] == field
|
2024-04-03 13:45:34 +08:00
|
|
|
|
? SizedBox(
|
2024-04-01 17:35:34 +08:00
|
|
|
|
width: inputWidth,
|
2024-04-03 13:45:34 +08:00
|
|
|
|
child: SkNumberInput<T>(
|
2024-04-01 17:35:34 +08:00
|
|
|
|
hint: '',
|
|
|
|
|
isDense: true,
|
|
|
|
|
autoFocus: true,
|
2024-04-03 13:45:34 +08:00
|
|
|
|
validator: func,
|
|
|
|
|
onFieldSubmitted: (value) {
|
|
|
|
|
final editingData =
|
|
|
|
|
controller.groups[groupIndex].items[rowIndex].toJson();
|
|
|
|
|
editingData[field] = value as T;
|
|
|
|
|
controller.saveChanges(groupIndex, rowIndex,
|
|
|
|
|
SaleQuotationItemModel.fromJson(editingData), field);
|
|
|
|
|
},
|
|
|
|
|
onTapOutside: (dynamic value) {
|
|
|
|
|
final editingData =
|
|
|
|
|
controller.groups[groupIndex].items[rowIndex].toJson();
|
|
|
|
|
editingData[field] = value as T;
|
|
|
|
|
controller.saveChanges(groupIndex, rowIndex,
|
|
|
|
|
SaleQuotationItemModel.fromJson(editingData), field);
|
|
|
|
|
},
|
2024-04-01 17:35:34 +08:00
|
|
|
|
contentPadding: EdgeInsets.symmetric(
|
|
|
|
|
horizontal: ScreenAdaper.width(20),
|
|
|
|
|
vertical: ScreenAdaper.height(10)),
|
2024-04-03 13:45:34 +08:00
|
|
|
|
textController:
|
|
|
|
|
TextEditingController(text: '${value == 0 ? '' : value}')),
|
2024-04-01 17:35:34 +08:00
|
|
|
|
)
|
|
|
|
|
: InkWell(
|
|
|
|
|
onTap: () {
|
|
|
|
|
controller.editingcell.value = [groupIndex, rowIndex, field];
|
|
|
|
|
},
|
|
|
|
|
child: content,
|
|
|
|
|
));
|
2024-04-01 14:27:44 +08:00
|
|
|
|
}
|
2024-04-01 11:38:10 +08:00
|
|
|
|
}
|