feat(client): 入库/出库加搜索框,入库/出库/库存加刷新按钮
Deploy Client / build-client-web (push) Successful in 42s
Deploy Client / build-windows (push) Successful in 1m53s
Deploy Client / build-macos (push) Successful in 2m10s
Deploy Client / build-android (push) Successful in 1m15s
Deploy Client / build-ios (push) Successful in 2m28s
Deploy Client / release-deploy-client (push) Successful in 1m21s

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
This commit is contained in:
wangjia
2026-06-20 16:03:01 +08:00
parent fb1e637ce4
commit 71ed15b40b
8 changed files with 167 additions and 42 deletions
@@ -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,
],
);
}),