发货
This commit is contained in:
@ -1,7 +1,12 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:async/async.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:logistics_tools/utils/request.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
class Logistics extends StatefulWidget {
|
||||
const Logistics({super.key});
|
||||
@ -12,11 +17,25 @@ class Logistics extends StatefulWidget {
|
||||
|
||||
class _LogisticsState extends State<Logistics> {
|
||||
List<dynamic> goodsList = [];
|
||||
String _orderPayWay = "";
|
||||
List _packages = [];
|
||||
int _activePackage = 0;
|
||||
final TextEditingController _goodsNameController =
|
||||
TextEditingController(text: "");
|
||||
final TextEditingController _goodsSpecController =
|
||||
TextEditingController(text: "");
|
||||
final TextEditingController _goodsNumController = TextEditingController();
|
||||
final _memoizer = AsyncMemoizer();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
// TODO: implement initState
|
||||
super.initState();
|
||||
setState(() {
|
||||
_packages = [
|
||||
{"id": const Uuid().v4(), "logisticsNumber": "", "goods": []}
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
Future<Response> fetchGoodsList(BuildContext context) async {
|
||||
@ -24,13 +43,16 @@ class _LogisticsState extends State<Logistics> {
|
||||
GoRouterState.of(context).uri.queryParameters["orderNumber"];
|
||||
String? orderPayWay =
|
||||
GoRouterState.of(context).uri.queryParameters["orderPayWay"];
|
||||
print(orderPayWay);
|
||||
_orderPayWay = orderPayWay!;
|
||||
|
||||
if (orderNumber?.isEmpty ?? true) {
|
||||
context.pop();
|
||||
}
|
||||
Response response = await dio.get(
|
||||
"https://www.sanpinhuicai.com/wisdommining/api/order/goodsOfOrder",
|
||||
queryParameters: {"orderNumber": orderNumber});
|
||||
Response response = await _memoizer.runOnce(() async {
|
||||
return await dio.get(
|
||||
"https://www.sanpinhuicai.com/wisdommining/api/order/goodsOfOrder",
|
||||
queryParameters: {"orderNumber": orderNumber});
|
||||
});
|
||||
goodsList = response.data["value"];
|
||||
return response;
|
||||
}
|
||||
@ -39,15 +61,55 @@ class _LogisticsState extends State<Logistics> {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text("填写物流信息"),
|
||||
title: Text(
|
||||
"填写物流信息 (${GoRouterState.of(context).uri.queryParameters["orderPayWay"]})"),
|
||||
actions: [
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
// 数据验证
|
||||
if (_orderPayWay != "套餐商品") {
|
||||
bool hasUnAddedGoods =
|
||||
goodsList.every((el) => el["goodsNum"] > 0);
|
||||
if (hasUnAddedGoods) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||
content: Text("有未添加至包裹的商品"),
|
||||
backgroundColor: Colors.redAccent,
|
||||
));
|
||||
return;
|
||||
}
|
||||
}
|
||||
bool result = _packages.every((package) {
|
||||
return package["logisticsNumber"].toString().isNotEmpty &&
|
||||
package["goods"].length > 0 &&
|
||||
package["goods"].every((goods) {
|
||||
return goods["name"].toString().isNotEmpty &&
|
||||
goods["num"].toString().isNotEmpty &&
|
||||
goods["spec"].toString().isNotEmpty;
|
||||
});
|
||||
});
|
||||
if (!result) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||
backgroundColor: Colors.redAccent,
|
||||
content: Text("有未填写的数据")));
|
||||
return;
|
||||
}
|
||||
String logisticsJson = jsonEncode(_packages);
|
||||
context.pop(logisticsJson);
|
||||
},
|
||||
child: const Row(
|
||||
children: [Text("保存"), Icon(Icons.save)],
|
||||
)),
|
||||
const SizedBox(
|
||||
width: 4,
|
||||
)
|
||||
],
|
||||
),
|
||||
body: Container(
|
||||
padding: const EdgeInsets.all(40),
|
||||
width: double.infinity,
|
||||
child: FutureBuilder(
|
||||
future: fetchGoodsList(context),
|
||||
builder:
|
||||
(BuildContext context, AsyncSnapshot<Response> snapshot) {
|
||||
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return Card(
|
||||
color: Colors.white,
|
||||
@ -57,27 +119,338 @@ class _LogisticsState extends State<Logistics> {
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: ListView.builder(
|
||||
itemCount: goodsList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final goods = goodsList[index];
|
||||
return ListTile(
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Icons.add),
|
||||
onPressed: () {},
|
||||
),
|
||||
leading: Image.network(
|
||||
goods["goodsPhoto"],
|
||||
width: 100,
|
||||
height: 100,
|
||||
),
|
||||
title: Text(
|
||||
"${goods["goodsName"]} - ${goods?["wisdGoodsSpec"]?["specName"] ?? ''}"),
|
||||
subtitle:
|
||||
Text("数量 : ${goods?["goodsNum"]}"),
|
||||
);
|
||||
})),
|
||||
const Expanded(flex: 1, child: Placeholder())
|
||||
child: _orderPayWay == "套餐商品"
|
||||
? Column(
|
||||
children: [
|
||||
Card(
|
||||
color: Colors.white70,
|
||||
child: Row(
|
||||
children: [
|
||||
Image.network(
|
||||
width: 80,
|
||||
height: 80,
|
||||
goodsList[0]["goodsPhoto"]),
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
Text(
|
||||
"${goodsList[0]["goodsName"]}")
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
TextField(
|
||||
controller: _goodsNameController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: "商品名称",
|
||||
border: OutlineInputBorder()),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
TextField(
|
||||
controller: _goodsSpecController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: "商品规格",
|
||||
border: OutlineInputBorder()),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
TextField(
|
||||
controller: _goodsNumController,
|
||||
keyboardType: TextInputType.number,
|
||||
inputFormatters: <TextInputFormatter>[
|
||||
FilteringTextInputFormatter
|
||||
.digitsOnly
|
||||
],
|
||||
decoration: const InputDecoration(
|
||||
labelText: "商品数量",
|
||||
border: OutlineInputBorder()),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
if (_goodsNumController
|
||||
.text.isEmpty ||
|
||||
_goodsNameController
|
||||
.text.isEmpty ||
|
||||
_goodsSpecController
|
||||
.text.isEmpty) {
|
||||
ScaffoldMessenger.of(context)
|
||||
.showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text(
|
||||
"请填写完整商品信息")));
|
||||
return;
|
||||
}
|
||||
int goodsNum = int.parse(
|
||||
_goodsNumController.text);
|
||||
String goodsName =
|
||||
_goodsNameController.text;
|
||||
String goodsSpec =
|
||||
_goodsSpecController.text;
|
||||
var goods = {
|
||||
"id": const Uuid().v4(),
|
||||
"name": goodsName,
|
||||
"num": goodsNum,
|
||||
"specId": const Uuid().v4(),
|
||||
"spec": goodsSpec
|
||||
};
|
||||
var packagesList = _packages;
|
||||
|
||||
packagesList[_activePackage]
|
||||
["goods"]
|
||||
.add(goods);
|
||||
setState(() {
|
||||
_packages = packagesList;
|
||||
});
|
||||
_goodsNumController.clear();
|
||||
_goodsNameController.clear();
|
||||
_goodsSpecController.clear();
|
||||
},
|
||||
child: const Text("添加到包裹"))
|
||||
],
|
||||
)
|
||||
: ListView.builder(
|
||||
itemCount: goodsList
|
||||
.where((el) => el["goodsNum"] > 0)
|
||||
.length,
|
||||
itemBuilder: (context, index) {
|
||||
final goods = goodsList
|
||||
.where((el) => el["goodsNum"] > 0)
|
||||
.toList()[index];
|
||||
return ListTile(
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Icons.add),
|
||||
onPressed: () {
|
||||
// 检查商品及规格是否已存在于目标包裹
|
||||
int targetIndex = _packages[
|
||||
_activePackage]["goods"]
|
||||
.indexWhere((el) =>
|
||||
el["id"] ==
|
||||
goods["id"] &&
|
||||
goods["wisdGoodsSpec"]
|
||||
["id"] ==
|
||||
el["specId"]);
|
||||
if (targetIndex != -1) {
|
||||
setState(() {
|
||||
_packages[_activePackage]
|
||||
["goods"]
|
||||
[targetIndex]
|
||||
["num"] += 1;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_packages[_activePackage]
|
||||
["goods"]
|
||||
.add({
|
||||
"id": goods["id"],
|
||||
"specId":
|
||||
goods["wisdGoodsSpec"]
|
||||
["id"],
|
||||
"name":
|
||||
goods["goodsName"],
|
||||
"spec":
|
||||
goods?["wisdGoodsSpec"]
|
||||
?[
|
||||
"specName"] ??
|
||||
"",
|
||||
"num": 1
|
||||
});
|
||||
});
|
||||
}
|
||||
var curGoods =
|
||||
goodsList.firstWhere(
|
||||
(el) =>
|
||||
el["id"] ==
|
||||
goods["id"],
|
||||
orElse: () => -1);
|
||||
|
||||
setState(() {
|
||||
curGoods["goodsNum"] -= 1;
|
||||
});
|
||||
},
|
||||
),
|
||||
leading: Image.network(
|
||||
goods["goodsPhoto"],
|
||||
width: 100,
|
||||
height: 100,
|
||||
),
|
||||
title: Text(
|
||||
"${goods["goodsName"]} - ${goods?["wisdGoodsSpec"]?["specName"] ?? ''}"),
|
||||
subtitle: Text(
|
||||
"数量 : ${goods?["goodsNum"]}"),
|
||||
);
|
||||
})),
|
||||
const SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: _packages.length,
|
||||
itemBuilder:
|
||||
(BuildContext context, int index) {
|
||||
return PackageCard(
|
||||
onLogisticsChanged: (value) {
|
||||
_packages[index]
|
||||
["logisticsNumber"] =
|
||||
value;
|
||||
},
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_activePackage = index;
|
||||
});
|
||||
},
|
||||
isActive:
|
||||
_activePackage == index,
|
||||
package: _packages[index],
|
||||
index: index)
|
||||
/*GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_activePackage = index;
|
||||
});
|
||||
},
|
||||
child: Card(
|
||||
elevation: _activePackage == index
|
||||
? 5
|
||||
: null,
|
||||
shape: _activePackage == index
|
||||
? RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.circular(
|
||||
12.0),
|
||||
side: const BorderSide(
|
||||
color: Colors.blue,
|
||||
width: 1.0,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
child: Stack(
|
||||
// clipBehavior: Clip.none,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 100,
|
||||
),
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.fromLTRB(
|
||||
20, 30, 20, 20),
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment
|
||||
.stretch,
|
||||
children: [
|
||||
TextField(
|
||||
decoration:
|
||||
const InputDecoration(
|
||||
border:
|
||||
OutlineInputBorder(),
|
||||
labelText:
|
||||
"物流单号"),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
DataTable(columns: const [
|
||||
DataColumn(
|
||||
label: Text("名称")),
|
||||
DataColumn(
|
||||
label: Text("规格")),
|
||||
DataColumn(
|
||||
label: Text("数量"))
|
||||
], rows: [
|
||||
for (var goodsItem
|
||||
in _packages[index]
|
||||
["goods"])
|
||||
DataRow(cells: [
|
||||
DataCell(Text(
|
||||
"${goodsItem["name"]}")),
|
||||
DataCell(Text(
|
||||
"${goodsItem["spec"]}")),
|
||||
DataCell(Text(
|
||||
"${goodsItem["num"]}")),
|
||||
])
|
||||
]),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 20,
|
||||
top: 2,
|
||||
child: Text("包裹${index + 1}"),
|
||||
),
|
||||
_packages.length > 1
|
||||
? Positioned(
|
||||
top: 2,
|
||||
right: 2,
|
||||
child: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: IconButton(
|
||||
color: Colors
|
||||
.redAccent,
|
||||
iconSize: 20,
|
||||
padding:
|
||||
EdgeInsets.zero,
|
||||
icon: const Icon(
|
||||
Icons.close),
|
||||
onPressed: () {
|
||||
var curId =
|
||||
_packages[
|
||||
index]
|
||||
["id"];
|
||||
setState(() {
|
||||
_activePackage =
|
||||
_activePackage >=
|
||||
index
|
||||
? _activePackage -
|
||||
1
|
||||
: _activePackage;
|
||||
_packages = _packages
|
||||
.where((el) =>
|
||||
el["id"] !=
|
||||
curId)
|
||||
.toList();
|
||||
});
|
||||
},
|
||||
),
|
||||
))
|
||||
: const SizedBox(
|
||||
width: 0,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)*/
|
||||
;
|
||||
},
|
||||
)),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_packages = [
|
||||
..._packages,
|
||||
{
|
||||
"logisticsNumber": "",
|
||||
"id": const Uuid().v4(),
|
||||
"goods": []
|
||||
}
|
||||
];
|
||||
});
|
||||
},
|
||||
child: const Text("添加包裹"))
|
||||
],
|
||||
))
|
||||
/*
|
||||
GridView.builder(
|
||||
gridDelegate:
|
||||
@ -107,3 +480,118 @@ class _LogisticsState extends State<Logistics> {
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
class PackageCard extends StatefulWidget {
|
||||
const PackageCard({
|
||||
super.key,
|
||||
required this.onTap,
|
||||
required this.isActive,
|
||||
required this.package,
|
||||
required this.index,
|
||||
required this.onLogisticsChanged,
|
||||
});
|
||||
|
||||
final bool isActive;
|
||||
final Function() onTap;
|
||||
final Map<String, dynamic> package;
|
||||
final int index;
|
||||
final Function(String) onLogisticsChanged;
|
||||
|
||||
@override
|
||||
State<PackageCard> createState() => _PackageCardState();
|
||||
}
|
||||
|
||||
class _PackageCardState extends State<PackageCard> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: widget.onTap,
|
||||
/* () {
|
||||
setState(() {
|
||||
_activePackage = index;
|
||||
});
|
||||
},*/
|
||||
child: Card(
|
||||
elevation: widget.isActive ? 5 : null,
|
||||
shape: widget.isActive
|
||||
? RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12.0),
|
||||
side: const BorderSide(
|
||||
color: Colors.blue,
|
||||
width: 1.0,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
child: Stack(
|
||||
// clipBehavior: Clip.none,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 100,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 30, 20, 20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
TextField(
|
||||
onChanged: widget.onLogisticsChanged,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(), labelText: "物流单号"),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
DataTable(columns: const [
|
||||
DataColumn(label: Text("名称")),
|
||||
DataColumn(label: Text("规格")),
|
||||
DataColumn(label: Text("数量"))
|
||||
], rows: [
|
||||
for (var goodsItem in widget.package["goods"])
|
||||
DataRow(cells: [
|
||||
DataCell(Text("${goodsItem["name"]}")),
|
||||
DataCell(Text("${goodsItem["spec"]}")),
|
||||
DataCell(Text("${goodsItem["num"]}")),
|
||||
])
|
||||
]),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 20,
|
||||
top: 2,
|
||||
child: Text("包裹${widget.index + 1}"),
|
||||
),
|
||||
/* _packages.length > 1
|
||||
? Positioned(
|
||||
top: 2,
|
||||
right: 2,
|
||||
child: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: IconButton(
|
||||
color: Colors.redAccent,
|
||||
iconSize: 20,
|
||||
padding: EdgeInsets.zero,
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: () {
|
||||
var curId = _packages[index]["id"];
|
||||
setState(() {
|
||||
_activePackage = _activePackage >= index
|
||||
? _activePackage - 1
|
||||
: _activePackage;
|
||||
_packages = _packages
|
||||
.where((el) => el["id"] != curId)
|
||||
.toList();
|
||||
});
|
||||
},
|
||||
),
|
||||
))
|
||||
: const SizedBox(
|
||||
width: 0,
|
||||
)*/
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user