Files
jiu/client/lib/providers/inventory_provider.dart
T
wangjia eac3e8825c feat(client): 库存查询新增规格/系列/入库时间;筛选组件支持搜索+滚动+标签
- 库存查询加规格、系列服务端筛选(后端 IN 条件,前端从 product-options API 加载全量选项)
- 库存查询新增「入库时间」列,导出 Excel 同步带上
- 入库单商品明细:隐藏商品编码列,生产日期从选填折叠区移至主行常显
- 筛选弹窗重构:顶部搜索框实时过滤 + 滚动列表(ConstrainedBox maxHeight)根治溢出
- 已选项以 Chip 标签置顶展示,每个标签带 × 可单独取消
- FilterableColumnHeader 筛选图标改为常驻,不再需要 hover 才显示

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 11:15:43 +08:00

158 lines
3.6 KiB
Dart

import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../core/api/api_client.dart';
import '../core/auth/auth_state.dart';
import '../core/models/page_result.dart';
import '../models/inventory.dart';
import '../repositories/inventory_repository.dart';
import 'connectivity_provider.dart';
final inventoryRepositoryProvider = Provider<InventoryRepository>((ref) {
return InventoryRepository(ref.watch(apiClientProvider));
});
final inventoryListProvider =
AsyncNotifierProvider<InventoryListNotifier, PageResult<Inventory>>(
InventoryListNotifier.new,
);
class InventoryListNotifier extends AsyncNotifier<PageResult<Inventory>> {
int _page = 1;
int _pageSize = 20;
int? _warehouseId;
String _keyword = '';
List<String> _series = [];
List<String> _spec = [];
PageResult<Inventory>? _cache;
@override
Future<PageResult<Inventory>> build() async {
ref.watch(authStateProvider.select((s) => s.user?.shopId));
ref.watch(networkRecoveryCountProvider); // 网络恢复时自动刷新
try {
final result = await _fetch();
_cache = result;
return result;
} catch (_) {
if (_cache != null) return _cache!;
rethrow;
}
}
Future<PageResult<Inventory>> _fetch() {
return ref.read(inventoryRepositoryProvider).listInventory(
warehouseId: _warehouseId,
keyword: _keyword.isEmpty ? null : _keyword,
series: _series.isEmpty ? null : _series,
spec: _spec.isEmpty ? null : _spec,
page: _page,
pageSize: _pageSize,
);
}
void setPage(int page) {
_page = page;
reload();
}
void setPageSize(int pageSize) {
_pageSize = pageSize;
_page = 1;
reload();
}
void setWarehouseId(int? id) {
_warehouseId = id;
_page = 1;
reload();
}
void setKeyword(String keyword) {
_keyword = keyword;
_page = 1;
reload();
}
void setSeries(List<String> series) {
_series = series;
_page = 1;
reload();
}
void setSpec(List<String> spec) {
_spec = spec;
_page = 1;
reload();
}
void reload() {
state = const AsyncValue.loading();
_fetch().then((result) {
_cache = result;
state = AsyncValue.data(result);
}, onError: (e, st) {
if (_cache != null) {
state = AsyncValue.data(_cache!);
} else {
state = AsyncValue.error(e, st);
}
});
}
}
final inventoryLogProvider =
AsyncNotifierProvider<InventoryLogNotifier, PageResult<InventoryLog>>(
InventoryLogNotifier.new,
);
class InventoryLogNotifier extends AsyncNotifier<PageResult<InventoryLog>> {
int _page = 1;
int _pageSize = 20;
PageResult<InventoryLog>? _cache;
@override
Future<PageResult<InventoryLog>> build() async {
ref.watch(authStateProvider.select((s) => s.user?.shopId));
ref.watch(networkRecoveryCountProvider);
try {
final result = await _fetch();
_cache = result;
return result;
} catch (_) {
if (_cache != null) return _cache!;
rethrow;
}
}
Future<PageResult<InventoryLog>> _fetch() {
return ref.read(inventoryRepositoryProvider).listLogs(
page: _page,
pageSize: _pageSize,
);
}
void setPage(int page) {
_page = page;
reload();
}
void setPageSize(int pageSize) {
_pageSize = pageSize;
_page = 1;
reload();
}
void reload() {
state = const AsyncValue.loading();
_fetch().then((result) {
_cache = result;
state = AsyncValue.data(result);
}, onError: (e, st) {
if (_cache != null) {
state = AsyncValue.data(_cache!);
} else {
state = AsyncValue.error(e, st);
}
});
}
}