发货
This commit is contained in:
@ -1,7 +1,12 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:async/async.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:logistics_tools/utils/request.dart';
|
import 'package:logistics_tools/utils/request.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class Logistics extends StatefulWidget {
|
class Logistics extends StatefulWidget {
|
||||||
const Logistics({super.key});
|
const Logistics({super.key});
|
||||||
@ -12,11 +17,25 @@ class Logistics extends StatefulWidget {
|
|||||||
|
|
||||||
class _LogisticsState extends State<Logistics> {
|
class _LogisticsState extends State<Logistics> {
|
||||||
List<dynamic> goodsList = [];
|
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
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
// TODO: implement initState
|
// TODO: implement initState
|
||||||
super.initState();
|
super.initState();
|
||||||
|
setState(() {
|
||||||
|
_packages = [
|
||||||
|
{"id": const Uuid().v4(), "logisticsNumber": "", "goods": []}
|
||||||
|
];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Response> fetchGoodsList(BuildContext context) async {
|
Future<Response> fetchGoodsList(BuildContext context) async {
|
||||||
@ -24,13 +43,16 @@ class _LogisticsState extends State<Logistics> {
|
|||||||
GoRouterState.of(context).uri.queryParameters["orderNumber"];
|
GoRouterState.of(context).uri.queryParameters["orderNumber"];
|
||||||
String? orderPayWay =
|
String? orderPayWay =
|
||||||
GoRouterState.of(context).uri.queryParameters["orderPayWay"];
|
GoRouterState.of(context).uri.queryParameters["orderPayWay"];
|
||||||
print(orderPayWay);
|
_orderPayWay = orderPayWay!;
|
||||||
|
|
||||||
if (orderNumber?.isEmpty ?? true) {
|
if (orderNumber?.isEmpty ?? true) {
|
||||||
context.pop();
|
context.pop();
|
||||||
}
|
}
|
||||||
Response response = await dio.get(
|
Response response = await _memoizer.runOnce(() async {
|
||||||
"https://www.sanpinhuicai.com/wisdommining/api/order/goodsOfOrder",
|
return await dio.get(
|
||||||
queryParameters: {"orderNumber": orderNumber});
|
"https://www.sanpinhuicai.com/wisdommining/api/order/goodsOfOrder",
|
||||||
|
queryParameters: {"orderNumber": orderNumber});
|
||||||
|
});
|
||||||
goodsList = response.data["value"];
|
goodsList = response.data["value"];
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
@ -39,15 +61,55 @@ class _LogisticsState extends State<Logistics> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
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(
|
body: Container(
|
||||||
padding: const EdgeInsets.all(40),
|
padding: const EdgeInsets.all(40),
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: FutureBuilder(
|
child: FutureBuilder(
|
||||||
future: fetchGoodsList(context),
|
future: fetchGoodsList(context),
|
||||||
builder:
|
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
|
||||||
(BuildContext context, AsyncSnapshot<Response> snapshot) {
|
|
||||||
if (snapshot.hasData) {
|
if (snapshot.hasData) {
|
||||||
return Card(
|
return Card(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
@ -57,27 +119,338 @@ class _LogisticsState extends State<Logistics> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 1,
|
flex: 1,
|
||||||
child: ListView.builder(
|
child: _orderPayWay == "套餐商品"
|
||||||
itemCount: goodsList.length,
|
? Column(
|
||||||
itemBuilder: (context, index) {
|
children: [
|
||||||
final goods = goodsList[index];
|
Card(
|
||||||
return ListTile(
|
color: Colors.white70,
|
||||||
trailing: IconButton(
|
child: Row(
|
||||||
icon: const Icon(Icons.add),
|
children: [
|
||||||
onPressed: () {},
|
Image.network(
|
||||||
),
|
width: 80,
|
||||||
leading: Image.network(
|
height: 80,
|
||||||
goods["goodsPhoto"],
|
goodsList[0]["goodsPhoto"]),
|
||||||
width: 100,
|
const SizedBox(
|
||||||
height: 100,
|
width: 16,
|
||||||
),
|
),
|
||||||
title: Text(
|
Text(
|
||||||
"${goods["goodsName"]} - ${goods?["wisdGoodsSpec"]?["specName"] ?? ''}"),
|
"${goodsList[0]["goodsName"]}")
|
||||||
subtitle:
|
],
|
||||||
Text("数量 : ${goods?["goodsNum"]}"),
|
),
|
||||||
);
|
),
|
||||||
})),
|
const SizedBox(
|
||||||
const Expanded(flex: 1, child: Placeholder())
|
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(
|
GridView.builder(
|
||||||
gridDelegate:
|
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,
|
||||||
|
)*/
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,10 +2,9 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:excel/excel.dart';
|
import 'package:excel/excel.dart';
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
|
||||||
|
|
||||||
class OrderList extends StatefulWidget {
|
class OrderList extends StatefulWidget {
|
||||||
const OrderList({super.key});
|
const OrderList({super.key});
|
||||||
@ -16,8 +15,8 @@ class OrderList extends StatefulWidget {
|
|||||||
|
|
||||||
class _OrderListState extends State<OrderList> {
|
class _OrderListState extends State<OrderList> {
|
||||||
final List lst = [];
|
final List lst = [];
|
||||||
List<String> headers = [];
|
List<String> _headers = [];
|
||||||
List<List<dynamic>> data = [];
|
List<List<dynamic>> _data = [];
|
||||||
late Excel _excel;
|
late Excel _excel;
|
||||||
ScrollController scrollController = ScrollController();
|
ScrollController scrollController = ScrollController();
|
||||||
final TextEditingController _logComController =
|
final TextEditingController _logComController =
|
||||||
@ -28,45 +27,54 @@ class _OrderListState extends State<OrderList> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
title: const Text("test"),
|
title: const Text("订单列表"),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
importExcelFile();
|
importExcelFile();
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.add_circle)),
|
child: const Row(
|
||||||
IconButton(
|
children: [Icon(Icons.add_circle), Text("导入")],
|
||||||
|
)),
|
||||||
|
const SizedBox(
|
||||||
|
width: 4,
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
exportExcelFile();
|
exportExcelFile();
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.output))
|
child: const Row(
|
||||||
|
children: [Icon(CupertinoIcons.download_circle), Text("导出")],
|
||||||
|
)),
|
||||||
|
const SizedBox(
|
||||||
|
width: 4,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: Container(
|
body: Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
// color: Colors.white,
|
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
child: Column(
|
child: _headers.isNotEmpty
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
? Column(
|
||||||
children: [
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
Card(
|
children: [
|
||||||
color: Colors.white,
|
Card(
|
||||||
margin: EdgeInsets.zero,
|
color: Colors.white,
|
||||||
child: headers.isNotEmpty
|
margin: EdgeInsets.zero,
|
||||||
? /*Scrollbar(
|
child: /*Scrollbar(
|
||||||
// controller: scrollController,
|
// controller: scrollController,
|
||||||
child:*/
|
child:*/
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
padding: const EdgeInsets.all(12.0),
|
padding: const EdgeInsets.all(12.0),
|
||||||
child: DataTable(
|
child: DataTable(
|
||||||
columns: headers.map((el) {
|
columns: _headers.map((el) {
|
||||||
return DataColumn(label: Text(el));
|
return DataColumn(label: Text(el));
|
||||||
}).toList(),
|
}).toList(),
|
||||||
rows: data.asMap().entries.map((row) {
|
rows: _data.asMap().entries.map((row) {
|
||||||
return DataRow(
|
return DataRow(
|
||||||
cells: row.value.asMap().entries.map((col) {
|
cells: row.value.asMap().entries.map((col) {
|
||||||
String colTitle = headers[col.key];
|
String colTitle = _headers[col.key];
|
||||||
return DataCell(colTitle == "物流名称"
|
return DataCell(colTitle == "物流名称"
|
||||||
? Row(
|
? Row(
|
||||||
children: [
|
children: [
|
||||||
@ -76,7 +84,7 @@ class _OrderListState extends State<OrderList> {
|
|||||||
iconSize: 12,
|
iconSize: 12,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_logComController.text =
|
_logComController.text =
|
||||||
data[row.key][col.key]
|
_data[row.key][col.key]
|
||||||
.toString();
|
.toString();
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@ -122,13 +130,13 @@ class _OrderListState extends State<OrderList> {
|
|||||||
Text("请输入物流公司")));
|
Text("请输入物流公司")));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final _data =
|
final data =
|
||||||
data;
|
_data;
|
||||||
data[row.key][col
|
_data[row.key][
|
||||||
.key] =
|
col.key] =
|
||||||
logisticsCom;
|
logisticsCom;
|
||||||
setState(() {
|
setState(() {
|
||||||
data = _data;
|
_data = data;
|
||||||
});
|
});
|
||||||
context.pop();
|
context.pop();
|
||||||
},
|
},
|
||||||
@ -141,58 +149,91 @@ class _OrderListState extends State<OrderList> {
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
: colTitle == "物流信息"
|
: colTitle == "物流信息"
|
||||||
? ElevatedButton(
|
? Row(
|
||||||
onPressed: () {
|
children: [
|
||||||
String orderNumber =
|
_data[row.key][col.key]
|
||||||
data[row.key][2].toString();
|
.toString()
|
||||||
String orderPayWay =
|
.isNotEmpty
|
||||||
data[row.key][15].toString();
|
? SizedBox(
|
||||||
if (orderPayWay.isEmpty ||
|
width: 120,
|
||||||
orderNumber.isEmpty) {
|
child: Text(
|
||||||
ScaffoldMessenger.of(context)
|
_data[row.key][col.key].toString(),
|
||||||
.showSnackBar(const SnackBar(
|
overflow:
|
||||||
content: Text("该行数据有误")));
|
TextOverflow.ellipsis,
|
||||||
return;
|
),
|
||||||
}
|
)
|
||||||
context.pushNamed("logistics",
|
: const SizedBox(),
|
||||||
queryParameters: {
|
ElevatedButton(
|
||||||
"orderNumber": data[row.key]
|
onPressed: () {
|
||||||
[2]
|
String orderNumber =
|
||||||
.toString(),
|
_data[row.key][2]
|
||||||
"orderPayWay": data[row.key]
|
.toString();
|
||||||
[15]
|
String orderPayWay =
|
||||||
.toString(),
|
_data[row.key][15]
|
||||||
|
.toString();
|
||||||
|
if (orderPayWay.isEmpty ||
|
||||||
|
orderNumber.isEmpty) {
|
||||||
|
ScaffoldMessenger.of(context)
|
||||||
|
.showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text(
|
||||||
|
"该行数据有误")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
context.pushNamed("logistics",
|
||||||
|
queryParameters: {
|
||||||
|
"orderNumber":
|
||||||
|
_data[row.key][2]
|
||||||
|
.toString(),
|
||||||
|
"orderPayWay":
|
||||||
|
_data[row.key][15]
|
||||||
|
.toString(),
|
||||||
|
}).then((value) {
|
||||||
|
if (value != null) {
|
||||||
|
var newData = _data;
|
||||||
|
newData[row.key][col.key] =
|
||||||
|
value;
|
||||||
|
setState(() {
|
||||||
|
_data = newData;
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: const Text("填写"),
|
child: const Text("填写"),
|
||||||
|
)
|
||||||
|
],
|
||||||
)
|
)
|
||||||
: Text("${col.value}"));
|
: Text("${col.value}"));
|
||||||
}).toList());
|
}).toList());
|
||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
/*)*/
|
/*)*/
|
||||||
: const Text("empty"),
|
,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
)
|
||||||
|
: const Center(
|
||||||
|
child: Icon(CupertinoIcons.cloud_upload),
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> importExcelFile() async {
|
Future<String> importExcelFile() async {
|
||||||
FilePickerResult? result = await FilePicker.platform
|
FilePickerResult? result = await FilePicker.platform
|
||||||
.pickFiles(type: FileType.custom, allowedExtensions: ["xlsx", "xls"]);
|
.pickFiles(type: FileType.custom, allowedExtensions: ["xlsx", "xls"]);
|
||||||
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
File file = File(result.files.single.path!);
|
File file = File(result.files.single.path!);
|
||||||
var bytes = file.readAsBytesSync();
|
var bytes = file.readAsBytesSync();
|
||||||
Excel excel = Excel.decodeBytes(bytes);
|
Excel excel = Excel.decodeBytes(bytes);
|
||||||
_excel = excel;
|
_excel = excel;
|
||||||
String tableKey = excel.tables.keys.first;
|
String tableKey = excel.tables.keys.first;
|
||||||
List<String> _headers = excel.tables[tableKey]?.rows.first.map((el) {
|
List<String> headers = excel.tables[tableKey]?.rows.first.map((el) {
|
||||||
return el?.value.toString() ?? "";
|
return el?.value.toString() ?? "";
|
||||||
}).toList() ??
|
}).toList() ??
|
||||||
[];
|
[];
|
||||||
List<List<dynamic>> _data = excel.tables[tableKey]?.rows
|
List<List<dynamic>> data = excel.tables[tableKey]?.rows
|
||||||
.where((el) => (el.first?.value?.toString() ?? "").isNotEmpty)
|
.where((el) => (el.first?.value?.toString() ?? "").isNotEmpty)
|
||||||
.toList()
|
.toList()
|
||||||
.sublist(1)
|
.sublist(1)
|
||||||
@ -203,8 +244,8 @@ class _OrderListState extends State<OrderList> {
|
|||||||
}).toList() ??
|
}).toList() ??
|
||||||
[];
|
[];
|
||||||
setState(() {
|
setState(() {
|
||||||
headers = _headers;
|
_headers = headers;
|
||||||
data = _data;
|
_data = data;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 取消选择
|
// 取消选择
|
||||||
@ -213,7 +254,7 @@ class _OrderListState extends State<OrderList> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
exportExcelFile() async {
|
exportExcelFile() async {
|
||||||
data.asMap().entries.forEach((row) {
|
_data.asMap().entries.forEach((row) {
|
||||||
row.value.asMap().entries.forEach((col) {
|
row.value.asMap().entries.forEach((col) {
|
||||||
int rowIndex = row.key + 1;
|
int rowIndex = row.key + 1;
|
||||||
int colIndex = col.key;
|
int colIndex = col.key;
|
||||||
@ -227,14 +268,19 @@ class _OrderListState extends State<OrderList> {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
var fileBytes = _excel.save();
|
var fileBytes = _excel.save();
|
||||||
// var directory = await getApplicationDocumentsDirectory();
|
String? directory =
|
||||||
File(
|
await FilePicker.platform.getDirectoryPath(dialogTitle: "选择保存位置");
|
||||||
"C:\\Users\\ayaya\\Desktop\\导出订单${DateTime.now().millisecondsSinceEpoch}.xlsx")
|
if (directory == null || directory.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
File("$directory\\导出订单${DateTime.now().millisecondsSinceEpoch}.xlsx")
|
||||||
..createSync(recursive: true)
|
..createSync(recursive: true)
|
||||||
..writeAsBytesSync(fileBytes!);
|
..writeAsBytesSync(fileBytes!);
|
||||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
if (mounted) {
|
||||||
content: Text("导出文件成功"),
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
backgroundColor: Colors.green,
|
content: Text("导出文件成功"),
|
||||||
));
|
backgroundColor: Colors.green,
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
30
pubspec.lock
30
pubspec.lock
@ -10,7 +10,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.4.9"
|
version: "3.4.9"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: async
|
name: async
|
||||||
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
||||||
@ -129,6 +129,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.0.5"
|
version: "8.0.5"
|
||||||
|
fixnum:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fixnum
|
||||||
|
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -268,10 +276,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_android
|
name: path_provider_android
|
||||||
sha256: "9c96da072b421e98183f9ea7464898428e764bc0ce5567f27ec8693442e72514"
|
sha256: bca87b0165ffd7cdb9cad8edd22d18d2201e886d9a9f19b4fb3452ea7df3a72a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.5"
|
version: "2.2.6"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -349,6 +357,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.0"
|
version: "1.10.0"
|
||||||
|
sprintf:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sprintf
|
||||||
|
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.0"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -397,6 +413,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.2"
|
version: "1.3.2"
|
||||||
|
uuid:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: uuid
|
||||||
|
sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.4.0"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -40,6 +40,8 @@ dependencies:
|
|||||||
go_router: ^14.2.0
|
go_router: ^14.2.0
|
||||||
dio: ^5.4.3+1
|
dio: ^5.4.3+1
|
||||||
path_provider: ^2.1.3
|
path_provider: ^2.1.3
|
||||||
|
uuid: ^4.4.0
|
||||||
|
async: ^2.11.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Reference in New Issue
Block a user