From e0701ba8235a01e5e8c1686cb694a1ae867dba4d Mon Sep 17 00:00:00 2001 From: quantulr <35954003+quantulr@users.noreply.github.com> Date: Mon, 17 Jun 2024 17:28:54 +0800 Subject: [PATCH] export xlsx --- .env | 7 + lib/logistics.dart | 111 ++++++++++++--- lib/main.dart | 6 +- lib/order_list.dart | 126 +++++++++++++++--- lib/utils/request.dart | 3 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 80 +++++++++++ pubspec.yaml | 2 + 8 files changed, 294 insertions(+), 43 deletions(-) create mode 100644 .env create mode 100644 lib/utils/request.dart diff --git a/.env b/.env new file mode 100644 index 0000000..153f9d9 --- /dev/null +++ b/.env @@ -0,0 +1,7 @@ +# Environment variables declared in this file are automatically made available to Prisma. +# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema + +# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB. +# See the documentation for all the connection string options: https://pris.ly/d/connection-strings + +DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public" \ No newline at end of file diff --git a/lib/logistics.dart b/lib/logistics.dart index d798e78..75e7c1e 100644 --- a/lib/logistics.dart +++ b/lib/logistics.dart @@ -1,5 +1,7 @@ -import 'package:flutter/cupertino.dart'; +import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:logistics_tools/utils/request.dart'; class Logistics extends StatefulWidget { const Logistics({super.key}); @@ -9,6 +11,30 @@ class Logistics extends StatefulWidget { } class _LogisticsState extends State { + List goodsList = []; + + @override + void initState() { + // TODO: implement initState + super.initState(); + } + + Future fetchGoodsList(BuildContext context) async { + String? orderNumber = + GoRouterState.of(context).uri.queryParameters["orderNumber"]; + String? orderPayWay = + GoRouterState.of(context).uri.queryParameters["orderPayWay"]; + print(orderPayWay); + if (orderNumber?.isEmpty ?? true) { + context.pop(); + } + Response response = await dio.get( + "https://www.sanpinhuicai.com/wisdommining/api/order/goodsOfOrder", + queryParameters: {"orderNumber": orderNumber}); + goodsList = response.data["value"]; + return response; + } + @override Widget build(BuildContext context) { return Scaffold( @@ -16,27 +42,68 @@ class _LogisticsState extends State { title: const Text("填写物流信息"), ), body: Container( - padding: const EdgeInsets.all(40), - width: double.infinity, - child: Card( - color: Colors.white, - child: Padding( - padding: EdgeInsets.all(20), - child: Column( - children: [ - Container( - decoration: BoxDecoration( - border: Border.all(), - borderRadius: const BorderRadius.all(Radius.circular(8))), - child: SizedBox( - height: 50, - width: 120, + padding: const EdgeInsets.all(40), + width: double.infinity, + child: FutureBuilder( + future: fetchGoodsList(context), + builder: + (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + return Card( + color: Colors.white, + child: Padding( + padding: const EdgeInsets.all(20), + child: Row( + 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()) + /* + GridView.builder( + gridDelegate: + const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 5, + childAspectRatio: 1.0), + itemCount: goodsList.length, + itemBuilder: (context, index) { + return Icon(Icons.add); + }), + */ + ], + )), + ); + } else if (snapshot.hasError) { + return const Center( + child: Icon( + Icons.error_outline, + color: Colors.red, + size: 60, ), - ) - ], - ), - ), - ), - )); + ); + } else { + return const Center(child: CircularProgressIndicator()); + } + }, + ))); } } diff --git a/lib/main.dart b/lib/main.dart index b863c68..cabc082 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -13,10 +13,14 @@ class MyApp extends StatelessWidget { final _router = GoRouter( routes: [ GoRoute( + name: "order_list", path: '/', builder: (context, state) => const OrderList(), ), - GoRoute(path: '/logistics', builder: (context, state) => const Logistics()) + GoRoute( + path: '/logistics', + name: "logistics", + builder: (context, state) => const Logistics()) ], ); diff --git a/lib/order_list.dart b/lib/order_list.dart index 726c6a6..a740652 100644 --- a/lib/order_list.dart +++ b/lib/order_list.dart @@ -3,7 +3,9 @@ import 'dart:io'; import 'package:excel/excel.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; import 'package:go_router/go_router.dart'; +import 'package:path_provider/path_provider.dart'; class OrderList extends StatefulWidget { const OrderList({super.key}); @@ -16,8 +18,10 @@ class _OrderListState extends State { final List lst = []; List headers = []; List> data = []; - + late Excel _excel; ScrollController scrollController = ScrollController(); + final TextEditingController _logComController = + TextEditingController(text: ""); @override Widget build(BuildContext context) { @@ -31,7 +35,11 @@ class _OrderListState extends State { importExcelFile(); }, icon: const Icon(Icons.add_circle)), - IconButton(onPressed: () {}, icon: const Icon(Icons.output)) + IconButton( + onPressed: () { + exportExcelFile(); + }, + icon: const Icon(Icons.output)) ], ), body: Container( @@ -55,11 +63,11 @@ class _OrderListState extends State { columns: headers.map((el) { return DataColumn(label: Text(el)); }).toList(), - rows: data.map((row) { + rows: data.asMap().entries.map((row) { return DataRow( - cells: row.asMap().entries.map((col) { - String col_title = headers[col.key]; - return DataCell(col_title == "物流名称" + cells: row.value.asMap().entries.map((col) { + String colTitle = headers[col.key]; + return DataCell(colTitle == "物流名称" ? Row( children: [ Text("${col.value}"), @@ -67,7 +75,9 @@ class _OrderListState extends State { // padding: EdgeInsets.all(2), iconSize: 12, onPressed: () { - // Dialog() + _logComController.text = + data[row.key][col.key] + .toString(); showDialog( context: context, builder: (BuildContext @@ -76,25 +86,52 @@ class _OrderListState extends State { // icon: const Icon(Icons.edit), title: const Text( "填写物流公司"), - content: const Column( + content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( decoration: - InputDecoration( + const InputDecoration( labelText: "物流公司"), + controller: + _logComController, ) ], ), actions: [ ElevatedButton( - onPressed: () {}, + onPressed: () { + context.pop(); + }, child: const Text( "取消")), ElevatedButton( - onPressed: () {}, + onPressed: () { + String + logisticsCom = + _logComController + .text; + if (logisticsCom + .isEmpty) { + ScaffoldMessenger.of( + context) + .showSnackBar(const SnackBar( + content: + Text("请输入物流公司"))); + return; + } + final _data = + data; + data[row.key][col + .key] = + logisticsCom; + setState(() { + data = _data; + }); + context.pop(); + }, child: const Text( "确认")), ], @@ -103,10 +140,29 @@ class _OrderListState extends State { icon: const Icon(Icons.edit)) ], ) - : col_title == "物流信息" + : colTitle == "物流信息" ? ElevatedButton( onPressed: () { - context.push("/logistics"); + String orderNumber = + data[row.key][2].toString(); + String orderPayWay = + 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(), + }); }, child: const Text("填写"), ) @@ -130,18 +186,22 @@ class _OrderListState extends State { File file = File(result.files.single.path!); var bytes = file.readAsBytesSync(); Excel excel = Excel.decodeBytes(bytes); + _excel = excel; String tableKey = excel.tables.keys.first; List _headers = excel.tables[tableKey]?.rows.first.map((el) { return el?.value.toString() ?? ""; }).toList() ?? []; - List> _data = - excel.tables[tableKey]?.rows.sublist(1).map((row) { - return row.map((col) { - return col?.value ?? ""; - }).toList(); - }).toList() ?? - []; + List> _data = excel.tables[tableKey]?.rows + .where((el) => (el.first?.value?.toString() ?? "").isNotEmpty) + .toList() + .sublist(1) + .map((row) { + return row.map((col) { + return col?.value ?? ""; + }).toList(); + }).toList() ?? + []; setState(() { headers = _headers; data = _data; @@ -151,4 +211,30 @@ class _OrderListState extends State { } return ""; } + + exportExcelFile() async { + data.asMap().entries.forEach((row) { + row.value.asMap().entries.forEach((col) { + int rowIndex = row.key + 1; + int colIndex = col.key; + if (colIndex == 11 || colIndex == 12) { + _excel.updateCell( + "订单列表", + CellIndex.indexByColumnRow( + columnIndex: colIndex, rowIndex: rowIndex), + TextCellValue(col.value.toString())); + } + }); + }); + var fileBytes = _excel.save(); + // var directory = await getApplicationDocumentsDirectory(); + File( + "C:\\Users\\ayaya\\Desktop\\导出订单${DateTime.now().millisecondsSinceEpoch}.xlsx") + ..createSync(recursive: true) + ..writeAsBytesSync(fileBytes!); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text("导出文件成功"), + backgroundColor: Colors.green, + )); + } } diff --git a/lib/utils/request.dart b/lib/utils/request.dart new file mode 100644 index 0000000..206c331 --- /dev/null +++ b/lib/utils/request.dart @@ -0,0 +1,3 @@ +import 'package:dio/dio.dart'; + +final dio = Dio(); diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index cccf817..e777c67 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,8 @@ import FlutterMacOS import Foundation +import path_provider_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 339e631..50aa833 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -81,6 +81,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + dio: + dependency: "direct main" + description: + name: dio + sha256: "11e40df547d418cc0c4900a9318b26304e665da6fa4755399a9ff9efd09034b5" + url: "https://pub.dev" + source: hosted + version: "5.4.3+1" equatable: dependency: transitive description: @@ -160,6 +168,14 @@ packages: url: "https://pub.dev" source: hosted version: "14.2.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" js: dependency: transitive description: @@ -240,6 +256,54 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.0" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 + url: "https://pub.dev" + source: hosted + version: "2.1.3" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "9c96da072b421e98183f9ea7464898428e764bc0ce5567f27ec8693442e72514" + url: "https://pub.dev" + source: hosted + version: "2.2.5" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + url: "https://pub.dev" + source: hosted + version: "2.4.0" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + url: "https://pub.dev" + source: hosted + version: "2.2.1" petitparser: dependency: transitive description: @@ -248,6 +312,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.2" + platform: + dependency: transitive + description: + name: platform + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + url: "https://pub.dev" + source: hosted + version: "3.1.5" plugin_platform_interface: dependency: transitive description: @@ -357,6 +429,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.5.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + url: "https://pub.dev" + source: hosted + version: "1.0.4" xml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a22e497..804292d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,6 +38,8 @@ dependencies: excel: ^4.0.3 file_picker: ^8.0.5 go_router: ^14.2.0 + dio: ^5.4.3+1 + path_provider: ^2.1.3 dev_dependencies: flutter_test: