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/),
|
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).
|
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
|
## [1.0.63] - 2026-06-20
|
||||||
|
|
||||||
### 修复
|
### 修复
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class StockInListNotifier extends AsyncNotifier<PageResult<StockInOrder>> {
|
|||||||
String _status = '';
|
String _status = '';
|
||||||
String? _startDate;
|
String? _startDate;
|
||||||
String? _endDate;
|
String? _endDate;
|
||||||
|
String _keyword = '';
|
||||||
PageResult<StockInOrder>? _cache;
|
PageResult<StockInOrder>? _cache;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -44,6 +45,7 @@ class StockInListNotifier extends AsyncNotifier<PageResult<StockInOrder>> {
|
|||||||
status: _status.isEmpty ? null : _status,
|
status: _status.isEmpty ? null : _status,
|
||||||
startDate: _startDate,
|
startDate: _startDate,
|
||||||
endDate: _endDate,
|
endDate: _endDate,
|
||||||
|
keyword: _keyword.isEmpty ? null : _keyword,
|
||||||
page: _page,
|
page: _page,
|
||||||
pageSize: _pageSize,
|
pageSize: _pageSize,
|
||||||
);
|
);
|
||||||
@@ -76,6 +78,12 @@ class StockInListNotifier extends AsyncNotifier<PageResult<StockInOrder>> {
|
|||||||
reload();
|
reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setKeyword(String keyword) {
|
||||||
|
_keyword = keyword;
|
||||||
|
_page = 1;
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
void reload() {
|
void reload() {
|
||||||
state = const AsyncValue.loading();
|
state = const AsyncValue.loading();
|
||||||
_fetch().then((result) {
|
_fetch().then((result) {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class StockOutListNotifier extends AsyncNotifier<PageResult<StockOutOrder>> {
|
|||||||
String _status = '';
|
String _status = '';
|
||||||
String? _startDate;
|
String? _startDate;
|
||||||
String? _endDate;
|
String? _endDate;
|
||||||
|
String _keyword = '';
|
||||||
PageResult<StockOutOrder>? _cache;
|
PageResult<StockOutOrder>? _cache;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -44,6 +45,7 @@ class StockOutListNotifier extends AsyncNotifier<PageResult<StockOutOrder>> {
|
|||||||
status: _status.isEmpty ? null : _status,
|
status: _status.isEmpty ? null : _status,
|
||||||
startDate: _startDate,
|
startDate: _startDate,
|
||||||
endDate: _endDate,
|
endDate: _endDate,
|
||||||
|
keyword: _keyword.isEmpty ? null : _keyword,
|
||||||
page: _page,
|
page: _page,
|
||||||
pageSize: _pageSize,
|
pageSize: _pageSize,
|
||||||
);
|
);
|
||||||
@@ -76,6 +78,12 @@ class StockOutListNotifier extends AsyncNotifier<PageResult<StockOutOrder>> {
|
|||||||
reload();
|
reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setKeyword(String keyword) {
|
||||||
|
_keyword = keyword;
|
||||||
|
_page = 1;
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
void reload() {
|
void reload() {
|
||||||
state = const AsyncValue.loading();
|
state = const AsyncValue.loading();
|
||||||
_fetch().then((result) {
|
_fetch().then((result) {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class StockInRepository {
|
|||||||
String? status,
|
String? status,
|
||||||
String? startDate,
|
String? startDate,
|
||||||
String? endDate,
|
String? endDate,
|
||||||
|
String? keyword,
|
||||||
int page = 1,
|
int page = 1,
|
||||||
int pageSize = 20,
|
int pageSize = 20,
|
||||||
}) async {
|
}) async {
|
||||||
@@ -23,6 +24,7 @@ class StockInRepository {
|
|||||||
if (status != null && status.isNotEmpty) 'status': status,
|
if (status != null && status.isNotEmpty) 'status': status,
|
||||||
if (startDate != null) 'start_date': startDate,
|
if (startDate != null) 'start_date': startDate,
|
||||||
if (endDate != null) 'end_date': endDate,
|
if (endDate != null) 'end_date': endDate,
|
||||||
|
if (keyword != null && keyword.isNotEmpty) 'keyword': keyword,
|
||||||
};
|
};
|
||||||
final resp = await _client.get('/stock-in/orders', params: params);
|
final resp = await _client.get('/stock-in/orders', params: params);
|
||||||
return PageResult.fromJson(
|
return PageResult.fromJson(
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class StockOutRepository {
|
|||||||
String? status,
|
String? status,
|
||||||
String? startDate,
|
String? startDate,
|
||||||
String? endDate,
|
String? endDate,
|
||||||
|
String? keyword,
|
||||||
int page = 1,
|
int page = 1,
|
||||||
int pageSize = 20,
|
int pageSize = 20,
|
||||||
}) async {
|
}) async {
|
||||||
@@ -23,6 +24,7 @@ class StockOutRepository {
|
|||||||
if (status != null && status.isNotEmpty) 'status': status,
|
if (status != null && status.isNotEmpty) 'status': status,
|
||||||
if (startDate != null) 'start_date': startDate,
|
if (startDate != null) 'start_date': startDate,
|
||||||
if (endDate != null) 'end_date': endDate,
|
if (endDate != null) 'end_date': endDate,
|
||||||
|
if (keyword != null && keyword.isNotEmpty) 'keyword': keyword,
|
||||||
};
|
};
|
||||||
final resp = await _client.get('/stock-out/orders', params: params);
|
final resp = await _client.get('/stock-out/orders', params: params);
|
||||||
return PageResult.fromJson(
|
return PageResult.fromJson(
|
||||||
|
|||||||
@@ -677,6 +677,13 @@ class _InventoryListScreenState extends ConsumerState<InventoryListScreen> {
|
|||||||
ColumnPrefs.save(_screenId, v);
|
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);
|
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(),
|
const Spacer(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ class _StockInListScreenState extends ConsumerState<StockInListScreen> {
|
|||||||
Set<String> _filterWarehouse = {};
|
Set<String> _filterWarehouse = {};
|
||||||
Set<String> _filterSupplier = {};
|
Set<String> _filterSupplier = {};
|
||||||
Set<String>? _hiddenCols; // null = 尚未载入本地存档(回退到 minWidth 首次默认)
|
Set<String>? _hiddenCols; // null = 尚未载入本地存档(回退到 minWidth 首次默认)
|
||||||
|
final _searchCtrl = TextEditingController();
|
||||||
|
|
||||||
static const _screenId = 'stock_in_list';
|
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
|
String? get _startDate => _dateRange != null
|
||||||
? '${_dateRange!.start.year}-${_dateRange!.start.month.toString().padLeft(2, '0')}-${_dateRange!.start.day.toString().padLeft(2, '0')}'
|
? '${_dateRange!.start.year}-${_dateRange!.start.month.toString().padLeft(2, '0')}-${_dateRange!.start.day.toString().padLeft(2, '0')}'
|
||||||
: null;
|
: null;
|
||||||
@@ -352,6 +362,27 @@ class _StockInListScreenState extends ConsumerState<StockInListScreen> {
|
|||||||
)
|
)
|
||||||
: null;
|
: 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(
|
final dateBtn = OutlinedButton.icon(
|
||||||
onPressed: _pickDateRange,
|
onPressed: _pickDateRange,
|
||||||
icon: const Icon(Icons.date_range, size: 16),
|
icon: const Icon(Icons.date_range, size: 16),
|
||||||
@@ -374,28 +405,36 @@ class _StockInListScreenState extends ConsumerState<StockInListScreen> {
|
|||||||
: null;
|
: null;
|
||||||
|
|
||||||
if (isMobile) {
|
if (isMobile) {
|
||||||
return Wrap(
|
return Column(
|
||||||
spacing: 8,
|
mainAxisSize: MainAxisSize.min,
|
||||||
runSpacing: 4,
|
|
||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
if (newBtn != null) newBtn,
|
searchField,
|
||||||
if (statusFilter != null) statusFilter,
|
const SizedBox(height: 8),
|
||||||
dateBtn,
|
Wrap(
|
||||||
if (clearDate != null) clearDate,
|
spacing: 8,
|
||||||
IconButton(
|
runSpacing: 4,
|
||||||
tooltip: '导出',
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
icon: const Icon(Icons.download, size: 20),
|
children: [
|
||||||
onPressed: doExport,
|
if (newBtn != null) newBtn,
|
||||||
),
|
if (statusFilter != null) statusFilter,
|
||||||
ColumnToggleButton(
|
dateBtn,
|
||||||
columns: _colDefs,
|
if (clearDate != null) clearDate,
|
||||||
hidden: hidden,
|
IconButton(
|
||||||
compact: true,
|
tooltip: '导出',
|
||||||
onChanged: (v) {
|
icon: const Icon(Icons.download, size: 20),
|
||||||
setState(() => _hiddenCols = v);
|
onPressed: doExport,
|
||||||
ColumnPrefs.save(_screenId, v);
|
),
|
||||||
},
|
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(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
|
SizedBox(width: 220, child: searchField),
|
||||||
|
const SizedBox(width: 12),
|
||||||
if (newBtn != null) newBtn,
|
if (newBtn != null) newBtn,
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
if (statusFilter != null) ...[
|
if (statusFilter != null) ...[
|
||||||
@@ -429,6 +470,7 @@ class _StockInListScreenState extends ConsumerState<StockInListScreen> {
|
|||||||
ColumnPrefs.save(_screenId, v);
|
ColumnPrefs.save(_screenId, v);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
refreshBtn,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
|
|||||||
Set<String> _filterWarehouse = {};
|
Set<String> _filterWarehouse = {};
|
||||||
Set<String> _filterCustomer = {};
|
Set<String> _filterCustomer = {};
|
||||||
Set<String>? _hiddenCols; // null = 尚未载入本地存档(回退到 minWidth 首次默认)
|
Set<String>? _hiddenCols; // null = 尚未载入本地存档(回退到 minWidth 首次默认)
|
||||||
|
final _searchCtrl = TextEditingController();
|
||||||
|
|
||||||
static const _screenId = 'stock_out_list';
|
static const _screenId = 'stock_out_list';
|
||||||
|
|
||||||
@@ -71,6 +72,16 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
|
|||||||
ColDef('actions', '操作', required: true),
|
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
|
String? get _startDate => _dateRange != null
|
||||||
? '${_dateRange!.start.year}-${_dateRange!.start.month.toString().padLeft(2, '0')}-${_dateRange!.start.day.toString().padLeft(2, '0')}'
|
? '${_dateRange!.start.year}-${_dateRange!.start.month.toString().padLeft(2, '0')}-${_dateRange!.start.day.toString().padLeft(2, '0')}'
|
||||||
: null;
|
: null;
|
||||||
@@ -358,6 +369,27 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
|
|||||||
)
|
)
|
||||||
: null;
|
: 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(
|
final dateBtn = OutlinedButton.icon(
|
||||||
onPressed: _pickDateRange,
|
onPressed: _pickDateRange,
|
||||||
icon: const Icon(Icons.date_range, size: 16),
|
icon: const Icon(Icons.date_range, size: 16),
|
||||||
@@ -380,28 +412,36 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
|
|||||||
: null;
|
: null;
|
||||||
|
|
||||||
if (isMobile) {
|
if (isMobile) {
|
||||||
return Wrap(
|
return Column(
|
||||||
spacing: 8,
|
mainAxisSize: MainAxisSize.min,
|
||||||
runSpacing: 4,
|
|
||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
if (newBtn != null) newBtn,
|
searchField,
|
||||||
if (statusFilter != null) statusFilter,
|
const SizedBox(height: 8),
|
||||||
dateBtn,
|
Wrap(
|
||||||
if (clearDate != null) clearDate,
|
spacing: 8,
|
||||||
IconButton(
|
runSpacing: 4,
|
||||||
tooltip: '导出',
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
icon: const Icon(Icons.download, size: 20),
|
children: [
|
||||||
onPressed: doExport,
|
if (newBtn != null) newBtn,
|
||||||
),
|
if (statusFilter != null) statusFilter,
|
||||||
ColumnToggleButton(
|
dateBtn,
|
||||||
columns: _colDefs,
|
if (clearDate != null) clearDate,
|
||||||
hidden: hidden,
|
IconButton(
|
||||||
compact: true,
|
tooltip: '导出',
|
||||||
onChanged: (v) {
|
icon: const Icon(Icons.download, size: 20),
|
||||||
setState(() => _hiddenCols = v);
|
onPressed: doExport,
|
||||||
ColumnPrefs.save(_screenId, v);
|
),
|
||||||
},
|
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(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
|
SizedBox(width: 220, child: searchField),
|
||||||
|
const SizedBox(width: 12),
|
||||||
if (newBtn != null) newBtn,
|
if (newBtn != null) newBtn,
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
if (statusFilter != null) ...[
|
if (statusFilter != null) ...[
|
||||||
@@ -435,6 +477,7 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
|
|||||||
ColumnPrefs.save(_screenId, v);
|
ColumnPrefs.save(_screenId, v);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
refreshBtn,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user