22047b725c
出库单新建页桌面端加「扫码枪扫码」框:扫商品二维码 URL → 取其中 的 ?code= → 本地整仓索引精确命中 → 明细自动新增/累加数量(每扫 +1)。本地未命中(大仓库存超前端加载上限 1000)时走服务端按编码 精确查兜底,复用现有库存搜索接口,无需新后端接口。 - 前端 stock_out_form_screen:扫码框 + _onScan + _codeIndex + parseScanCode + 服务端兜底 + 300ms 防抖 + 提示音;桌面专属, 窄屏隐藏。 - 后端 product.go:二维码 URL 路径 /app/product/ → /product/ 统一到 SSR 公开页路由。 - 原型 stock-in.js/html:出库明细头同步加扫码框(design-first)。 - 测试 parse_scan_code_test(8 例)+ 出库表单桌面 golden 重生成。 - 设计/实现计划文档 docs/design/scan-stock-out-*。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bupi8Kdqkfx2N5acFsHTx5
50 lines
1.5 KiB
Dart
50 lines
1.5 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
||
import 'package:jiu_client/screens/stock_out/stock_out_form_screen.dart';
|
||
|
||
/// 扫码出库:从扫码枪内容里取商品编码。
|
||
/// 扫码枪扫二维码得到 URL(形如 …/product/{public_id}?code={code})或纯编码。
|
||
void main() {
|
||
group('parseScanCode', () {
|
||
test('新路径 /product/xxx?code=', () {
|
||
expect(
|
||
parseScanCode('https://jiu.51yanmei.com/product/abc-123?code=P1001'),
|
||
'P1001',
|
||
);
|
||
});
|
||
|
||
test('旧路径 /app/product/xxx?code=(兼容)', () {
|
||
expect(
|
||
parseScanCode('https://jiu.51yanmei.com/app/product/abc?code=P1002'),
|
||
'P1002',
|
||
);
|
||
});
|
||
|
||
test('纯编码直接扫(无 URL)', () {
|
||
expect(parseScanCode('P1003'), 'P1003');
|
||
});
|
||
|
||
test('前后空白被去除', () {
|
||
expect(parseScanCode(' P1004 '), 'P1004');
|
||
});
|
||
|
||
test('code 带 URL 编码字符被解码', () {
|
||
expect(parseScanCode('https://x/product/y?code=P%2D9'), 'P-9');
|
||
});
|
||
|
||
test('多参数里的 code 也能取到', () {
|
||
expect(parseScanCode('https://x/product/y?foo=1&code=P1005&bar=2'), 'P1005');
|
||
});
|
||
|
||
test('空串返回空', () {
|
||
expect(parseScanCode(''), '');
|
||
expect(parseScanCode(' '), '');
|
||
});
|
||
|
||
test('无 code 参数的 URL:整串兜底当编码', () {
|
||
// 无 ?code= 时不误判,返回原串(由上层按编码匹配,匹配不到再报未找到)
|
||
const raw = 'https://x/product/only-public-id';
|
||
expect(parseScanCode(raw), raw);
|
||
});
|
||
});
|
||
}
|