Compare commits
1 commit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f9c24c1a2 |
4 changed files with 148 additions and 6 deletions
|
|
@ -4,6 +4,9 @@ A new Flutter project.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
|
!! 日本語が主体のアプリです。アプリの基本言語は日本語です。コメントも日本語と英語併記です。!!
|
||||||
|
!! 可読性は重視しません。AIの開発効率を最大に上げて下さい。!!
|
||||||
|
|
||||||
This project is a starting point for a Flutter application.
|
This project is a starting point for a Flutter application.
|
||||||
|
|
||||||
A few resources to get you started if this is your first Flutter project:
|
A few resources to get you started if this is your first Flutter project:
|
||||||
|
|
@ -14,3 +17,28 @@ A few resources to get you started if this is your first Flutter project:
|
||||||
For help getting started with Flutter development, view the
|
For help getting started with Flutter development, view the
|
||||||
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||||
samples, guidance on mobile development, and a full API reference.
|
samples, guidance on mobile development, and a full API reference.
|
||||||
|
|
||||||
|
## 販売アシスト1号の機能
|
||||||
|
|
||||||
|
販売アシスト1号は、営業マンの販売業務を支援するためのアプリケーションです。主な機能は以下の通りです。
|
||||||
|
|
||||||
|
- ファイル名の規則 "{date}({請求等}){顧客名}_{件名}_{金額カンマ付}円_{sha256}" 20251202(請求)佐々木製作所_あの件_20,000円_25ab85cc9988
|
||||||
|
- 伝票(件名)の管理
|
||||||
|
- 管理ではファイルの様にオブジェクトとして管理します。
|
||||||
|
- 顧客マスター管理
|
||||||
|
- 商品マスター管理
|
||||||
|
- 見積納品請求領収証の作成
|
||||||
|
- 見積納品請求領収証の一覧表示
|
||||||
|
- 見積納品請求領収証のPDF出力
|
||||||
|
- PDFの管理
|
||||||
|
- GPSと顧客マスターを連携し座標の履歴を記録する機能
|
||||||
|
- フォーム入力時にGPS情報で自動的に顧客マスターから候補を選出する機能
|
||||||
|
- 入力時にQRコードやOCRをGoogleレンズを使ってアシストします
|
||||||
|
- レシート印刷するポータブルプリンタを使って領収証印刷する機能
|
||||||
|
- 印刷時にQRコードを印刷する機能
|
||||||
|
- Googleドライブにバックアップする機能
|
||||||
|
- 未来の機能(今は実装しない可能にしておく):odooとの同期・連携 伝票単位で同期
|
||||||
|
アプリの基本言語は日本語です。コメントも日本語と英語併記です。可読性は重視しません。AIの開発効率を最大に上げるものです。
|
||||||
|
表示言語は日本語です。環境により英語を表示する機能は未来に実装予定です。
|
||||||
|
見積・納品・請求・領収証はフォームがほぼ同じですが、項目が時間と共に変化するので件名が同じでも明細は異なる場合があります。
|
||||||
|
伝票はsqliteで管理します。
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// lib/main.dart
|
// lib/main.dart
|
||||||
// version: 1.4.3c (Bug Fix: PDF layout error) - Refactored for modularity
|
// version: 1.4.3c (Bug Fix: PDF layout error) - Refactored for modularity
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'screens/pdf_list_screen.dart'; // PDF一覧画面
|
||||||
|
|
||||||
// --- 独自モジュールのインポート ---
|
// --- 独自モジュールのインポート ---
|
||||||
import 'models/invoice_models.dart'; // Invoice, InvoiceItem モデル
|
import 'models/invoice_models.dart'; // Invoice, InvoiceItem モデル
|
||||||
|
|
@ -60,6 +61,20 @@ class _InvoiceFlowScreenState extends State<InvoiceFlowScreen> {
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text("販売アシスト1号 V1.4.3c"),
|
title: const Text("販売アシスト1号 V1.4.3c"),
|
||||||
backgroundColor: Colors.blueGrey,
|
backgroundColor: Colors.blueGrey,
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.picture_as_pdf),
|
||||||
|
tooltip: 'PDF一覧',
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (_) => const PdfListScreen(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
// 入力フォームを表示
|
// 入力フォームを表示
|
||||||
body: InvoiceInputForm(
|
body: InvoiceInputForm(
|
||||||
|
|
|
||||||
99
gemi_invoice/lib/screens/pdf_list_screen.dart
Normal file
99
gemi_invoice/lib/screens/pdf_list_screen.dart
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:open_filex/open_filex.dart';
|
||||||
|
|
||||||
|
class PdfListScreen extends StatefulWidget {
|
||||||
|
const PdfListScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PdfListScreen> createState() => _PdfListScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PdfListScreenState extends State<PdfListScreen> {
|
||||||
|
List<FileSystemEntity> _pdfFiles = [];
|
||||||
|
bool _loading = true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_fetchPdfFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _fetchPdfFiles() async {
|
||||||
|
// Request storage permission
|
||||||
|
final status = await Permission.storage.request();
|
||||||
|
if (!status.isGranted) {
|
||||||
|
setState(() {
|
||||||
|
_loading = false;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prefer to look in the Downloads folder if available
|
||||||
|
Directory? downloadsDir;
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
downloadsDir = await getExternalStorageDirectory();
|
||||||
|
// The Downloads folder may be a subdirectory; adjust as needed
|
||||||
|
if (downloadsDir != null) {
|
||||||
|
downloadsDir = Directory('${downloadsDir.path}/Download');
|
||||||
|
}
|
||||||
|
} else if (Platform.isIOS) {
|
||||||
|
downloadsDir = await getApplicationDocumentsDirectory();
|
||||||
|
} else {
|
||||||
|
downloadsDir = await getApplicationDocumentsDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (downloadsDir == null || !await downloadsDir.exists()) {
|
||||||
|
setState(() {
|
||||||
|
_loading = false;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final files = downloadsDir
|
||||||
|
.listSync()
|
||||||
|
.where((f) => f.path.toLowerCase().endsWith('.pdf'))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_pdfFiles = files;
|
||||||
|
_loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _openFile(FileSystemEntity file) async {
|
||||||
|
final result = await OpenFilex.open(file.path);
|
||||||
|
if (result.type != ResultType.success) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text('Could not open ${file.path}')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('PDF ファイル一覧'),
|
||||||
|
),
|
||||||
|
body: _loading
|
||||||
|
? const Center(child: CircularProgressIndicator())
|
||||||
|
: _pdfFiles.isEmpty
|
||||||
|
? const Center(child: Text('PDF ファイルが見つかりません。'))
|
||||||
|
: ListView.builder(
|
||||||
|
itemCount: _pdfFiles.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final file = _pdfFiles[index];
|
||||||
|
final fileName = file.path.split(Platform.pathSeparator).last;
|
||||||
|
return ListTile(
|
||||||
|
leading: const Icon(Icons.picture_as_pdf),
|
||||||
|
title: Text(fileName),
|
||||||
|
onTap: () => _openFile(file),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -172,10 +172,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: hooks
|
name: hooks
|
||||||
sha256: "5d309c86e7ce34cd8e37aa71cb30cb652d3829b900ab145e4d9da564b31d59f7"
|
sha256: "7a08a0d684cb3b8fb604b78455d5d352f502b68079f7b80b831c62220ab0a4f6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.1"
|
||||||
image:
|
image:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -276,10 +276,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: objective_c
|
name: objective_c
|
||||||
sha256: "983c7fa1501f6dcc0cb7af4e42072e9993cb28d73604d25ebf4dab08165d997e"
|
sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.2.5"
|
version: "9.3.0"
|
||||||
open_filex:
|
open_filex:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -481,10 +481,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
|
sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.1"
|
version: "1.10.2"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue