Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 71ed15b40b |
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.0.64] - 2026-06-20
|
||||
|
||||
### 新功能
|
||||
- 入库单 / 出库单列表新增搜索框:输入单号或往来单位名称即可即时筛选,不用再翻页查找
|
||||
- 入库 / 出库 / 库存三个列表均新增刷新按钮:多端并发录入后可一键同步最新数据
|
||||
|
||||
## [1.0.63] - 2026-06-20
|
||||
|
||||
### 修复
|
||||
|
||||
@@ -23,6 +23,7 @@ class StockInListNotifier extends AsyncNotifier<PageResult<StockInOrder>> {
|
||||
String _status = '';
|
||||
String? _startDate;
|
||||
String? _endDate;
|
||||
String _keyword = '';
|
||||
PageResult<StockInOrder>? _cache;
|
||||
|
||||
@override
|
||||
@@ -44,6 +45,7 @@ class StockInListNotifier extends AsyncNotifier<PageResult<StockInOrder>> {
|
||||
status: _status.isEmpty ? null : _status,
|
||||
startDate: _startDate,
|
||||
endDate: _endDate,
|
||||
keyword: _keyword.isEmpty ? null : _keyword,
|
||||
page: _page,
|
||||
pageSize: _pageSize,
|
||||
);
|
||||
@@ -76,6 +78,12 @@ class StockInListNotifier extends AsyncNotifier<PageResult<StockInOrder>> {
|
||||
reload();
|
||||
}
|
||||
|
||||
void setKeyword(String keyword) {
|
||||
_keyword = keyword;
|
||||
_page = 1;
|
||||
reload();
|
||||
}
|
||||
|
||||
void reload() {
|
||||
state = const AsyncValue.loading();
|
||||
_fetch().then((result) {
|
||||
|
||||
@@ -23,6 +23,7 @@ class StockOutListNotifier extends AsyncNotifier<PageResult<StockOutOrder>> {
|
||||
String _status = '';
|
||||
String? _startDate;
|
||||
String? _endDate;
|
||||
String _keyword = '';
|
||||
PageResult<StockOutOrder>? _cache;
|
||||
|
||||
@override
|
||||
@@ -44,6 +45,7 @@ class StockOutListNotifier extends AsyncNotifier<PageResult<StockOutOrder>> {
|
||||
status: _status.isEmpty ? null : _status,
|
||||
startDate: _startDate,
|
||||
endDate: _endDate,
|
||||
keyword: _keyword.isEmpty ? null : _keyword,
|
||||
page: _page,
|
||||
pageSize: _pageSize,
|
||||
);
|
||||
@@ -76,6 +78,12 @@ class StockOutListNotifier extends AsyncNotifier<PageResult<StockOutOrder>> {
|
||||
reload();
|
||||
}
|
||||
|
||||
void setKeyword(String keyword) {
|
||||
_keyword = keyword;
|
||||
_page = 1;
|
||||
reload();
|
||||
}
|
||||
|
||||
void reload() {
|
||||
state = const AsyncValue.loading();
|
||||
_fetch().then((result) {
|
||||
|
||||
@@ -13,6 +13,7 @@ class StockInRepository {
|
||||
String? status,
|
||||
String? startDate,
|
||||
String? endDate,
|
||||
String? keyword,
|
||||
int page = 1,
|
||||
int pageSize = 20,
|
||||
}) async {
|
||||
@@ -23,6 +24,7 @@ class StockInRepository {
|
||||
if (status != null && status.isNotEmpty) 'status': status,
|
||||
if (startDate != null) 'start_date': startDate,
|
||||
if (endDate != null) 'end_date': endDate,
|
||||
if (keyword != null && keyword.isNotEmpty) 'keyword': keyword,
|
||||
};
|
||||
final resp = await _client.get('/stock-in/orders', params: params);
|
||||
return PageResult.fromJson(
|
||||
|
||||
@@ -13,6 +13,7 @@ class StockOutRepository {
|
||||
String? status,
|
||||
String? startDate,
|
||||
String? endDate,
|
||||
String? keyword,
|
||||
int page = 1,
|
||||
int pageSize = 20,
|
||||
}) async {
|
||||
@@ -23,6 +24,7 @@ class StockOutRepository {
|
||||
if (status != null && status.isNotEmpty) 'status': status,
|
||||
if (startDate != null) 'start_date': startDate,
|
||||
if (endDate != null) 'end_date': endDate,
|
||||
if (keyword != null && keyword.isNotEmpty) 'keyword': keyword,
|
||||
};
|
||||
final resp = await _client.get('/stock-out/orders', params: params);
|
||||
return PageResult.fromJson(
|
||||
|
||||
@@ -677,6 +677,13 @@ class _InventoryListScreenState extends ConsumerState<InventoryListScreen> {
|
||||
ColumnPrefs.save(_screenId, v);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
tooltip: '刷新',
|
||||
icon: const Icon(Icons.refresh, size: 20),
|
||||
onPressed: () => ref
|
||||
.read(inventoryListProvider.notifier)
|
||||
.reload(),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
@@ -712,6 +719,13 @@ class _InventoryListScreenState extends ConsumerState<InventoryListScreen> {
|
||||
ColumnPrefs.save(_screenId, v);
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
OutlinedButton.icon(
|
||||
onPressed: () =>
|
||||
ref.read(inventoryListProvider.notifier).reload(),
|
||||
icon: const Icon(Icons.refresh, size: 16),
|
||||
label: const Text('刷新'),
|
||||
),
|
||||
const Spacer(),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -39,6 +39,7 @@ class _StockInListScreenState extends ConsumerState<StockInListScreen> {
|
||||
Set<String> _filterWarehouse = {};
|
||||
Set<String> _filterSupplier = {};
|
||||
Set<String>? _hiddenCols; // null = 尚未载入本地存档(回退到 minWidth 首次默认)
|
||||
final _searchCtrl = TextEditingController();
|
||||
|
||||
static const _screenId = 'stock_in_list';
|
||||
|
||||
@@ -71,6 +72,15 @@ class _StockInListScreenState extends ConsumerState<StockInListScreen> {
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_searchCtrl.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _triggerSearch() =>
|
||||
ref.read(stockInListProvider.notifier).setKeyword(_searchCtrl.text.trim());
|
||||
|
||||
String? get _startDate => _dateRange != null
|
||||
? '${_dateRange!.start.year}-${_dateRange!.start.month.toString().padLeft(2, '0')}-${_dateRange!.start.day.toString().padLeft(2, '0')}'
|
||||
: null;
|
||||
@@ -352,6 +362,27 @@ class _StockInListScreenState extends ConsumerState<StockInListScreen> {
|
||||
)
|
||||
: null;
|
||||
|
||||
final searchField = TextField(
|
||||
controller: _searchCtrl,
|
||||
decoration: InputDecoration(
|
||||
hintText: '单号/往来单位,回车搜索',
|
||||
prefixIcon: const Icon(Icons.search, size: 16),
|
||||
hintStyle: const TextStyle(fontSize: 12),
|
||||
suffixIcon: IconButton(
|
||||
icon: const Icon(Icons.search, size: 16),
|
||||
tooltip: '搜索',
|
||||
onPressed: _triggerSearch,
|
||||
),
|
||||
),
|
||||
onSubmitted: (_) => _triggerSearch(),
|
||||
);
|
||||
|
||||
final refreshBtn = IconButton(
|
||||
tooltip: '刷新',
|
||||
icon: const Icon(Icons.refresh, size: 20),
|
||||
onPressed: () => ref.read(stockInListProvider.notifier).reload(),
|
||||
);
|
||||
|
||||
final dateBtn = OutlinedButton.icon(
|
||||
onPressed: _pickDateRange,
|
||||
icon: const Icon(Icons.date_range, size: 16),
|
||||
@@ -374,28 +405,36 @@ class _StockInListScreenState extends ConsumerState<StockInListScreen> {
|
||||
: null;
|
||||
|
||||
if (isMobile) {
|
||||
return Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 4,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (newBtn != null) newBtn,
|
||||
if (statusFilter != null) statusFilter,
|
||||
dateBtn,
|
||||
if (clearDate != null) clearDate,
|
||||
IconButton(
|
||||
tooltip: '导出',
|
||||
icon: const Icon(Icons.download, size: 20),
|
||||
onPressed: doExport,
|
||||
),
|
||||
ColumnToggleButton(
|
||||
columns: _colDefs,
|
||||
hidden: hidden,
|
||||
compact: true,
|
||||
onChanged: (v) {
|
||||
setState(() => _hiddenCols = v);
|
||||
ColumnPrefs.save(_screenId, v);
|
||||
},
|
||||
searchField,
|
||||
const SizedBox(height: 8),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 4,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
if (newBtn != null) newBtn,
|
||||
if (statusFilter != null) statusFilter,
|
||||
dateBtn,
|
||||
if (clearDate != null) clearDate,
|
||||
IconButton(
|
||||
tooltip: '导出',
|
||||
icon: const Icon(Icons.download, size: 20),
|
||||
onPressed: doExport,
|
||||
),
|
||||
ColumnToggleButton(
|
||||
columns: _colDefs,
|
||||
hidden: hidden,
|
||||
compact: true,
|
||||
onChanged: (v) {
|
||||
setState(() => _hiddenCols = v);
|
||||
ColumnPrefs.save(_screenId, v);
|
||||
},
|
||||
),
|
||||
refreshBtn,
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -403,6 +442,8 @@ class _StockInListScreenState extends ConsumerState<StockInListScreen> {
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
SizedBox(width: 220, child: searchField),
|
||||
const SizedBox(width: 12),
|
||||
if (newBtn != null) newBtn,
|
||||
const Spacer(),
|
||||
if (statusFilter != null) ...[
|
||||
@@ -429,6 +470,7 @@ class _StockInListScreenState extends ConsumerState<StockInListScreen> {
|
||||
ColumnPrefs.save(_screenId, v);
|
||||
},
|
||||
),
|
||||
refreshBtn,
|
||||
],
|
||||
);
|
||||
}),
|
||||
|
||||
@@ -38,6 +38,7 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
|
||||
Set<String> _filterWarehouse = {};
|
||||
Set<String> _filterCustomer = {};
|
||||
Set<String>? _hiddenCols; // null = 尚未载入本地存档(回退到 minWidth 首次默认)
|
||||
final _searchCtrl = TextEditingController();
|
||||
|
||||
static const _screenId = 'stock_out_list';
|
||||
|
||||
@@ -71,6 +72,16 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
|
||||
ColDef('actions', '操作', required: true),
|
||||
];
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_searchCtrl.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _triggerSearch() => ref
|
||||
.read(stockOutListProvider.notifier)
|
||||
.setKeyword(_searchCtrl.text.trim());
|
||||
|
||||
String? get _startDate => _dateRange != null
|
||||
? '${_dateRange!.start.year}-${_dateRange!.start.month.toString().padLeft(2, '0')}-${_dateRange!.start.day.toString().padLeft(2, '0')}'
|
||||
: null;
|
||||
@@ -358,6 +369,27 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
|
||||
)
|
||||
: null;
|
||||
|
||||
final searchField = TextField(
|
||||
controller: _searchCtrl,
|
||||
decoration: InputDecoration(
|
||||
hintText: '单号/往来单位,回车搜索',
|
||||
prefixIcon: const Icon(Icons.search, size: 16),
|
||||
hintStyle: const TextStyle(fontSize: 12),
|
||||
suffixIcon: IconButton(
|
||||
icon: const Icon(Icons.search, size: 16),
|
||||
tooltip: '搜索',
|
||||
onPressed: _triggerSearch,
|
||||
),
|
||||
),
|
||||
onSubmitted: (_) => _triggerSearch(),
|
||||
);
|
||||
|
||||
final refreshBtn = IconButton(
|
||||
tooltip: '刷新',
|
||||
icon: const Icon(Icons.refresh, size: 20),
|
||||
onPressed: () => ref.read(stockOutListProvider.notifier).reload(),
|
||||
);
|
||||
|
||||
final dateBtn = OutlinedButton.icon(
|
||||
onPressed: _pickDateRange,
|
||||
icon: const Icon(Icons.date_range, size: 16),
|
||||
@@ -380,28 +412,36 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
|
||||
: null;
|
||||
|
||||
if (isMobile) {
|
||||
return Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 4,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (newBtn != null) newBtn,
|
||||
if (statusFilter != null) statusFilter,
|
||||
dateBtn,
|
||||
if (clearDate != null) clearDate,
|
||||
IconButton(
|
||||
tooltip: '导出',
|
||||
icon: const Icon(Icons.download, size: 20),
|
||||
onPressed: doExport,
|
||||
),
|
||||
ColumnToggleButton(
|
||||
columns: _colDefs,
|
||||
hidden: hidden,
|
||||
compact: true,
|
||||
onChanged: (v) {
|
||||
setState(() => _hiddenCols = v);
|
||||
ColumnPrefs.save(_screenId, v);
|
||||
},
|
||||
searchField,
|
||||
const SizedBox(height: 8),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 4,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
if (newBtn != null) newBtn,
|
||||
if (statusFilter != null) statusFilter,
|
||||
dateBtn,
|
||||
if (clearDate != null) clearDate,
|
||||
IconButton(
|
||||
tooltip: '导出',
|
||||
icon: const Icon(Icons.download, size: 20),
|
||||
onPressed: doExport,
|
||||
),
|
||||
ColumnToggleButton(
|
||||
columns: _colDefs,
|
||||
hidden: hidden,
|
||||
compact: true,
|
||||
onChanged: (v) {
|
||||
setState(() => _hiddenCols = v);
|
||||
ColumnPrefs.save(_screenId, v);
|
||||
},
|
||||
),
|
||||
refreshBtn,
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -409,6 +449,8 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
SizedBox(width: 220, child: searchField),
|
||||
const SizedBox(width: 12),
|
||||
if (newBtn != null) newBtn,
|
||||
const Spacer(),
|
||||
if (statusFilter != null) ...[
|
||||
@@ -435,6 +477,7 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
|
||||
ColumnPrefs.save(_screenId, v);
|
||||
},
|
||||
),
|
||||
refreshBtn,
|
||||
],
|
||||
);
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user