feat: enhance boxing module with box mode support and fix Android build
- Add box_mode parameter to box submission API for one-to-one/one-to-many/many-to-one modes - Allow re-scan override in one2one mode without clearing state - Improve duplicate detection messages per boxing mode - Disable Kotlin incremental compilation to fix cross-drive build failure Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
||||||
|
kotlin.incremental=false
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
systemProp.http.proxyHost=127.0.0.1
|
systemProp.http.proxyHost=127.0.0.1
|
||||||
|
|||||||
@@ -155,8 +155,10 @@ class _BoxingPageState extends State<BoxingPage> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 其他模式:等待扫码阶段才处理
|
// 一码一箱:允许覆盖,直接查询新二维码(不提前清空状态,避免闪烁)
|
||||||
if (_phase != _Phase.waiting) return;
|
if (_mode != BoxingMode.one2one && _phase != _Phase.waiting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_queryBoxInfo(zongpai);
|
_queryBoxInfo(zongpai);
|
||||||
}
|
}
|
||||||
@@ -276,11 +278,17 @@ class _BoxingPageState extends State<BoxingPage> {
|
|||||||
|
|
||||||
setState(() => _isSubmitting = true);
|
setState(() => _isSubmitting = true);
|
||||||
|
|
||||||
|
final modeStr = switch (_mode) {
|
||||||
|
BoxingMode.one2one => 'one-to-one',
|
||||||
|
BoxingMode.one2many => 'one-to-many',
|
||||||
|
BoxingMode.many2one => 'many-to-one',
|
||||||
|
};
|
||||||
final result = await _apiService.saveBoxRecord(
|
final result = await _apiService.saveBoxRecord(
|
||||||
baseUrl: baseUrl,
|
baseUrl: baseUrl,
|
||||||
zongpaiNo: _zongpaiNo!,
|
zongpaiNo: _zongpaiNo!,
|
||||||
boxNo: boxNo,
|
boxNo: boxNo,
|
||||||
quantity: quantity,
|
quantity: quantity,
|
||||||
|
boxMode: modeStr,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
@@ -290,10 +298,14 @@ class _BoxingPageState extends State<BoxingPage> {
|
|||||||
if (result.success) {
|
if (result.success) {
|
||||||
_onSubmitSuccess(boxNo, quantity);
|
_onSubmitSuccess(boxNo, quantity);
|
||||||
} else if (result.isDuplicate) {
|
} else if (result.isDuplicate) {
|
||||||
_showFeedback(
|
if (_mode == BoxingMode.one2one) {
|
||||||
'排产号 ${result.paichanNo ?? ""} 下箱号 ${result.boxNo ?? ""} 已存在',
|
_showFeedback('该总排号已绑定箱号 ${result.boxNo ?? "?"},请勿重复装箱', isError: true);
|
||||||
isError: true,
|
} else {
|
||||||
);
|
_showFeedback(
|
||||||
|
'排产号 ${result.paichanNo ?? ""} 下箱号 ${result.boxNo ?? ""} 已存在',
|
||||||
|
isError: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
_showFeedback(result.errorMessage ?? '提交失败', isError: true);
|
_showFeedback(result.errorMessage ?? '提交失败', isError: true);
|
||||||
}
|
}
|
||||||
@@ -305,10 +317,12 @@ class _BoxingPageState extends State<BoxingPage> {
|
|||||||
_lastQuantity = quantity;
|
_lastQuantity = quantity;
|
||||||
// 刷新已有箱号列表(将新记录加入本地列表)
|
// 刷新已有箱号列表(将新记录加入本地列表)
|
||||||
_existingBoxes = List.from(_existingBoxes)
|
_existingBoxes = List.from(_existingBoxes)
|
||||||
..add(BoxDetailData(
|
..add(
|
||||||
boxNo: boxNo,
|
BoxDetailData(
|
||||||
items: [BoxItemData(zongpaiNo: _zongpaiNo!, quantity: quantity)],
|
boxNo: boxNo,
|
||||||
));
|
items: [BoxItemData(zongpaiNo: _zongpaiNo!, quantity: quantity)],
|
||||||
|
),
|
||||||
|
);
|
||||||
_maxBoxNo = _maxBoxNo > boxNo ? _maxBoxNo : boxNo;
|
_maxBoxNo = _maxBoxNo > boxNo ? _maxBoxNo : boxNo;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -440,10 +454,7 @@ class _BoxingPageState extends State<BoxingPage> {
|
|||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
onPressed: _cycleMode,
|
onPressed: _cycleMode,
|
||||||
icon: const Icon(Icons.swap_horiz, size: 18),
|
icon: const Icon(Icons.swap_horiz, size: 18),
|
||||||
label: Text(
|
label: Text(_modeLabel, style: const TextStyle(fontSize: 13)),
|
||||||
_modeLabel,
|
|
||||||
style: const TextStyle(fontSize: 13),
|
|
||||||
),
|
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
foregroundColor: _mode == BoxingMode.many2one
|
foregroundColor: _mode == BoxingMode.many2one
|
||||||
? Colors.orange
|
? Colors.orange
|
||||||
@@ -704,7 +715,9 @@ class _BoxingPageState extends State<BoxingPage> {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: _maxBoxNo > 0 ? Colors.amber.shade800 : Colors.grey,
|
color: _maxBoxNo > 0
|
||||||
|
? Colors.amber.shade800
|
||||||
|
: Colors.grey,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -824,8 +837,9 @@ class _BoxingPageState extends State<BoxingPage> {
|
|||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: _canSubmit ? _submit : null,
|
onPressed: _canSubmit ? _submit : null,
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor:
|
backgroundColor: _canSubmit
|
||||||
_canSubmit ? Theme.of(context).colorScheme.primary : Colors.grey.shade300,
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: Colors.grey.shade300,
|
||||||
foregroundColor: _canSubmit ? Colors.white : Colors.grey.shade600,
|
foregroundColor: _canSubmit ? Colors.white : Colors.grey.shade600,
|
||||||
),
|
),
|
||||||
child: _isSubmitting
|
child: _isSubmitting
|
||||||
|
|||||||
@@ -15,11 +15,14 @@ class RegistrationResult {
|
|||||||
this.duplicateInfo,
|
this.duplicateInfo,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory RegistrationResult.ok() =>
|
factory RegistrationResult.ok() => RegistrationResult(success: true);
|
||||||
RegistrationResult(success: true);
|
|
||||||
|
|
||||||
factory RegistrationResult.duplicate(Map<String, dynamic> info) =>
|
factory RegistrationResult.duplicate(Map<String, dynamic> info) =>
|
||||||
RegistrationResult(success: false, isDuplicate: true, duplicateInfo: info);
|
RegistrationResult(
|
||||||
|
success: false,
|
||||||
|
isDuplicate: true,
|
||||||
|
duplicateInfo: info,
|
||||||
|
);
|
||||||
|
|
||||||
factory RegistrationResult.error(String message) =>
|
factory RegistrationResult.error(String message) =>
|
||||||
RegistrationResult(success: false, errorMessage: message);
|
RegistrationResult(success: false, errorMessage: message);
|
||||||
@@ -50,7 +53,8 @@ class BoxDetailData {
|
|||||||
BoxDetailData({required this.boxNo, required this.items});
|
BoxDetailData({required this.boxNo, required this.items});
|
||||||
|
|
||||||
factory BoxDetailData.fromJson(Map<String, dynamic> json) {
|
factory BoxDetailData.fromJson(Map<String, dynamic> json) {
|
||||||
final items = (json['items'] as List<dynamic>?)
|
final items =
|
||||||
|
(json['items'] as List<dynamic>?)
|
||||||
?.map((i) => BoxItemData.fromJson(i as Map<String, dynamic>))
|
?.map((i) => BoxItemData.fromJson(i as Map<String, dynamic>))
|
||||||
.toList() ??
|
.toList() ??
|
||||||
[];
|
[];
|
||||||
@@ -81,7 +85,8 @@ class BoxInfoResult {
|
|||||||
});
|
});
|
||||||
|
|
||||||
factory BoxInfoResult.ok(Map<String, dynamic> json) {
|
factory BoxInfoResult.ok(Map<String, dynamic> json) {
|
||||||
final boxes = (json['existing_boxes'] as List<dynamic>?)
|
final boxes =
|
||||||
|
(json['existing_boxes'] as List<dynamic>?)
|
||||||
?.map((b) => BoxDetailData.fromJson(b as Map<String, dynamic>))
|
?.map((b) => BoxDetailData.fromJson(b as Map<String, dynamic>))
|
||||||
.toList() ??
|
.toList() ??
|
||||||
[];
|
[];
|
||||||
@@ -144,7 +149,7 @@ class ApiService {
|
|||||||
final Duration timeout;
|
final Duration timeout;
|
||||||
|
|
||||||
ApiService({http.Client? client, this.timeout = const Duration(seconds: 5)})
|
ApiService({http.Client? client, this.timeout = const Duration(seconds: 5)})
|
||||||
: _client = client ?? http.Client();
|
: _client = client ?? http.Client();
|
||||||
|
|
||||||
/// Submit a shelf registration (上架登记).
|
/// Submit a shelf registration (上架登记).
|
||||||
Future<RegistrationResult> registerLocation({
|
Future<RegistrationResult> registerLocation({
|
||||||
@@ -177,7 +182,10 @@ class ApiService {
|
|||||||
return RegistrationResult.duplicate(body);
|
return RegistrationResult.duplicate(body);
|
||||||
default:
|
default:
|
||||||
final body = jsonDecode(response.body) as Map<String, dynamic>;
|
final body = jsonDecode(response.body) as Map<String, dynamic>;
|
||||||
final msg = body['message'] ?? body['error'] ?? 'Unknown error (${response.statusCode})';
|
final msg =
|
||||||
|
body['message'] ??
|
||||||
|
body['error'] ??
|
||||||
|
'Unknown error (${response.statusCode})';
|
||||||
return RegistrationResult.error(msg.toString());
|
return RegistrationResult.error(msg.toString());
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -190,9 +198,9 @@ class ApiService {
|
|||||||
required String baseUrl,
|
required String baseUrl,
|
||||||
required String zongpaiNo,
|
required String zongpaiNo,
|
||||||
}) async {
|
}) async {
|
||||||
final uri = Uri.parse('$baseUrl/CargoTrace/box/info').replace(
|
final uri = Uri.parse(
|
||||||
queryParameters: {'zongpai_no': zongpaiNo},
|
'$baseUrl/CargoTrace/box/info',
|
||||||
);
|
).replace(queryParameters: {'zongpai_no': zongpaiNo});
|
||||||
try {
|
try {
|
||||||
final response = await _client
|
final response = await _client
|
||||||
.get(uri, headers: {'Content-Type': 'application/json'})
|
.get(uri, headers: {'Content-Type': 'application/json'})
|
||||||
@@ -220,6 +228,7 @@ class ApiService {
|
|||||||
required String zongpaiNo,
|
required String zongpaiNo,
|
||||||
required int boxNo,
|
required int boxNo,
|
||||||
required int quantity,
|
required int quantity,
|
||||||
|
required String boxMode,
|
||||||
}) async {
|
}) async {
|
||||||
final uri = Uri.parse('$baseUrl/CargoTrace/box');
|
final uri = Uri.parse('$baseUrl/CargoTrace/box');
|
||||||
try {
|
try {
|
||||||
@@ -231,6 +240,7 @@ class ApiService {
|
|||||||
'zongpai_no': zongpaiNo,
|
'zongpai_no': zongpaiNo,
|
||||||
'box_no': boxNo,
|
'box_no': boxNo,
|
||||||
'quantity': quantity,
|
'quantity': quantity,
|
||||||
|
'box_mode': boxMode,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.timeout(timeout);
|
.timeout(timeout);
|
||||||
|
|||||||
Reference in New Issue
Block a user