chore: release client-v1.0.71
Deploy Client / build-client-web (push) Successful in 47s
Deploy Client / build-macos (push) Successful in 2m11s
Deploy Client / build-android (push) Successful in 1m11s
Deploy Client / build-ios (push) Successful in 2m29s
Deploy Client / build-windows (push) Successful in 2m27s
Deploy Client / release-deploy-client (push) Successful in 1m27s
Deploy Client / build-client-web (push) Successful in 47s
Deploy Client / build-macos (push) Successful in 2m11s
Deploy Client / build-android (push) Successful in 1m11s
Deploy Client / build-ios (push) Successful in 2m29s
Deploy Client / build-windows (push) Successful in 2m27s
Deploy Client / release-deploy-client (push) Successful in 1m27s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
This commit is contained in:
@@ -25,6 +25,7 @@ import '../../providers/finance_provider.dart' show financeRepositoryProvider;
|
||||
import '../../providers/shop_provider.dart' show shopInfoProvider;
|
||||
import '../../widgets/write_guard.dart';
|
||||
import '../../widgets/order_row_actions.dart';
|
||||
import '../../widgets/order_return_dialog.dart';
|
||||
import '../../core/auth/auth_state.dart'
|
||||
show isAdminProvider, currentUserIdProvider;
|
||||
|
||||
@@ -268,7 +269,11 @@ class _StockInListScreenState extends ConsumerState<StockInListScreen> {
|
||||
? '¥${o.totalAmount!.toStringAsFixed(2)}'
|
||||
: '-'));
|
||||
case 'status':
|
||||
return DataCell(StatusBadge(_apiStatusToEnum(o.status)));
|
||||
final rb = returnStateBadge(o.returnState);
|
||||
return DataCell(Row(mainAxisSize: MainAxisSize.min, children: [
|
||||
StatusBadge(_apiStatusToEnum(o.status)),
|
||||
if (rb != null) ...[const SizedBox(width: 4), rb],
|
||||
]));
|
||||
case 'date':
|
||||
return DataCell(Text(o.orderDate?.substring(0, 10) ?? '-'));
|
||||
case 'operator':
|
||||
@@ -531,6 +536,9 @@ class _StockInListScreenState extends ConsumerState<StockInListScreen> {
|
||||
onApprove: () => _confirmApprove(context, o),
|
||||
onReject: () => _confirmReject(context, o),
|
||||
onWithdraw: () => _confirmWithdraw(context, o),
|
||||
// 入库退单:仅管理员/超管
|
||||
canReturn: ref.watch(isAdminProvider),
|
||||
onReturn: () => _confirmReturn(context, o),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -540,7 +548,13 @@ class _StockInListScreenState extends ConsumerState<StockInListScreen> {
|
||||
onTap: () => _showDetail(context, o.id),
|
||||
title: Text(o.orderNo,
|
||||
style: const TextStyle(fontFamily: 'monospace', fontSize: 14)),
|
||||
trailing: StatusBadge(_apiStatusToEnum(o.status)),
|
||||
trailing: Row(mainAxisSize: MainAxisSize.min, children: [
|
||||
StatusBadge(_apiStatusToEnum(o.status)),
|
||||
if (returnStateBadge(o.returnState) != null) ...[
|
||||
const SizedBox(width: 4),
|
||||
returnStateBadge(o.returnState)!,
|
||||
],
|
||||
]),
|
||||
fields: [
|
||||
MobileCardField('供应商', o.partnerName ?? '-'),
|
||||
MobileCardField('仓库', o.warehouseName ?? '-'),
|
||||
@@ -797,6 +811,68 @@ class _StockInListScreenState extends ConsumerState<StockInListScreen> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _confirmReturn(BuildContext context, StockInOrder o) async {
|
||||
final go = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: const Text('退单'),
|
||||
content: Text('确认对已审核入库单「${o.orderNo}」发起退单?将打开退单明细窗口选择要退的商品。'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(false),
|
||||
child: const Text('取消')),
|
||||
ElevatedButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(true),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppTheme.danger, foregroundColor: Colors.white),
|
||||
child: const Text('确认'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
if (go != true || !mounted) return;
|
||||
final StockInOrder full;
|
||||
try {
|
||||
full = await ref.read(stockInRepositoryProvider).get(o.id);
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('加载明细失败:$e'), backgroundColor: AppTheme.danger));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!mounted) return;
|
||||
final lines = full.items
|
||||
.where((it) => it.id != null)
|
||||
.map((it) => ReturnLine(
|
||||
itemId: it.id!,
|
||||
code: it.productCode ?? '',
|
||||
name: it.productName ?? '',
|
||||
series: it.productSeries ?? '',
|
||||
spec: it.productSpec ?? '',
|
||||
quantity: it.quantity,
|
||||
unitPrice: it.unitPrice,
|
||||
totalPrice: it.totalPrice,
|
||||
alreadyReturned: it.isReturned,
|
||||
))
|
||||
.toList();
|
||||
await showOrderReturnDialog(
|
||||
context: context,
|
||||
title: '入库单退单 — ${o.orderNo}',
|
||||
isOut: false,
|
||||
meta: [
|
||||
('供应商', o.partnerName ?? '-'),
|
||||
('仓库', o.warehouseName ?? '-'),
|
||||
('入库日期', o.orderDate != null && o.orderDate!.length >= 10
|
||||
? o.orderDate!.substring(0, 10)
|
||||
: (o.orderDate ?? '-')),
|
||||
],
|
||||
lines: lines,
|
||||
onSubmit: (ids) =>
|
||||
ref.read(stockInListProvider.notifier).returnItems(o.id, ids),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Detail dialog — fetches full order with items
|
||||
|
||||
@@ -23,6 +23,7 @@ import '../../providers/product_provider.dart';
|
||||
import '../../providers/finance_provider.dart' show financeRepositoryProvider;
|
||||
import '../../widgets/write_guard.dart';
|
||||
import '../../widgets/order_row_actions.dart';
|
||||
import '../../widgets/order_return_dialog.dart';
|
||||
import '../../core/auth/auth_state.dart'
|
||||
show isAdminProvider, currentUserIdProvider;
|
||||
|
||||
@@ -269,7 +270,11 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
|
||||
? '¥${o.totalAmount!.toStringAsFixed(2)}'
|
||||
: '-'));
|
||||
case 'status':
|
||||
return DataCell(StatusBadge(_apiStatusToEnum(o.status)));
|
||||
final rb = returnStateBadge(o.returnState);
|
||||
return DataCell(Row(mainAxisSize: MainAxisSize.min, children: [
|
||||
StatusBadge(_apiStatusToEnum(o.status)),
|
||||
if (rb != null) ...[const SizedBox(width: 4), rb],
|
||||
]));
|
||||
case 'date':
|
||||
return DataCell(Text(o.orderDate?.substring(0, 10) ?? '-'));
|
||||
case 'created_at':
|
||||
@@ -505,6 +510,11 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
|
||||
onApprove: () => _confirmApprove(context, o),
|
||||
onReject: () => _confirmReject(context, o),
|
||||
onWithdraw: () => _confirmWithdraw(context, o),
|
||||
// 出库退单:管理员/超管 或 本人单
|
||||
canReturn: ref.watch(isAdminProvider) ||
|
||||
(o.operatorId != null &&
|
||||
o.operatorId == ref.watch(currentUserIdProvider)),
|
||||
onReturn: () => _confirmReturn(context, o),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -514,7 +524,13 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
|
||||
onTap: () => _showDetail(context, o.id),
|
||||
title: Text(o.orderNo,
|
||||
style: const TextStyle(fontFamily: 'monospace', fontSize: 14)),
|
||||
trailing: StatusBadge(_apiStatusToEnum(o.status)),
|
||||
trailing: Row(mainAxisSize: MainAxisSize.min, children: [
|
||||
StatusBadge(_apiStatusToEnum(o.status)),
|
||||
if (returnStateBadge(o.returnState) != null) ...[
|
||||
const SizedBox(width: 4),
|
||||
returnStateBadge(o.returnState)!,
|
||||
],
|
||||
]),
|
||||
fields: [
|
||||
MobileCardField('客户', o.partnerName ?? '-'),
|
||||
MobileCardField('仓库', o.warehouseName ?? '-'),
|
||||
@@ -776,6 +792,68 @@ class _StockOutListScreenState extends ConsumerState<StockOutListScreen> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _confirmReturn(BuildContext context, StockOutOrder o) async {
|
||||
final go = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: const Text('退单'),
|
||||
content: Text('确认对已审核出库单「${o.orderNo}」发起退单?将打开退单明细窗口选择要退的商品。'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(false),
|
||||
child: const Text('取消')),
|
||||
ElevatedButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(true),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppTheme.danger, foregroundColor: Colors.white),
|
||||
child: const Text('确认'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
if (go != true || !mounted) return;
|
||||
final StockOutOrder full;
|
||||
try {
|
||||
full = await ref.read(stockOutRepositoryProvider).get(o.id);
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('加载明细失败:$e'), backgroundColor: AppTheme.danger));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!mounted) return;
|
||||
final lines = full.items
|
||||
.where((it) => it.id != null)
|
||||
.map((it) => ReturnLine(
|
||||
itemId: it.id!,
|
||||
code: it.productCode ?? '',
|
||||
name: it.productName ?? '',
|
||||
series: it.productSeries ?? '',
|
||||
spec: it.productSpec ?? '',
|
||||
quantity: it.quantity,
|
||||
unitPrice: it.unitPrice,
|
||||
totalPrice: it.totalPrice,
|
||||
alreadyReturned: it.isReturned,
|
||||
))
|
||||
.toList();
|
||||
await showOrderReturnDialog(
|
||||
context: context,
|
||||
title: '出库单退单 — ${o.orderNo}',
|
||||
isOut: true,
|
||||
meta: [
|
||||
('客户', o.partnerName ?? '-'),
|
||||
('仓库', o.warehouseName ?? '-'),
|
||||
('出库日期', o.orderDate != null && o.orderDate!.length >= 10
|
||||
? o.orderDate!.substring(0, 10)
|
||||
: (o.orderDate ?? '-')),
|
||||
],
|
||||
lines: lines,
|
||||
onSubmit: (ids) =>
|
||||
ref.read(stockOutListProvider.notifier).returnItems(o.id, ids),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Detail dialog — fetches full order with items
|
||||
|
||||
Reference in New Issue
Block a user