diff --git a/docs/superpowers/specs/2026-05-14-purchase-in-pda-scan-design.md b/docs/superpowers/specs/2026-05-14-purchase-in-pda-scan-design.md new file mode 100644 index 0000000..e334576 --- /dev/null +++ b/docs/superpowers/specs/2026-05-14-purchase-in-pda-scan-design.md @@ -0,0 +1,367 @@ +# 采购入库 PDA 扫码页重构设计 + +## 背景 + +当前“扫码采购入库”页面更接近通用表单页,而非工厂仓库现场的扫码作业页。页面在未锁定采购单前就暴露了商品扫码、批次号、库位码、提交等动作,导致流程噪音大、操作节奏不稳定、误操作风险高。 + +本次重构面向工厂仓库出入库场景,明确主使用设备与操作方式: + +- 90% 使用 PDA / 手持终端物理扫码枪 +- 10% 使用手机摄像头扫码 +- 商品扫码主路径为“一枪一件”,每次扫码自动累计 `+1` + +因此页面设计必须优先服务高频、连续、站立式作业,而不是低频表单录入。 + +## 目标 + +重构采购入库扫码页,使其满足以下目标: + +- 先锁采购单,再进入连续扫码作业 +- 商品扫码成功时不打断操作节奏 +- 异常时给出明确、可恢复的处理反馈 +- 始终让操作员看到当前单据、当前仓库、扫码进度、异常数量 +- 降低危险操作误触概率,避免“清空全部”成为高频可见动作 +- 保持与现有 ERP 扫码页代码风格一致,优先复用现有扫描输入、明细列表、提交逻辑能力 + +## 非目标 + +本次设计不包含以下范围: + +- 不重做采购入库后端接口协议 +- 不新增复杂的离线同步机制 +- 不引入多步骤向导页或跨页长流程 +- 不为手机摄像头场景单独做一套交互,只保留备用入口 + +## 设计方向 + +页面采用“作业台式”方案。锁单是进入作业态的前置动作,作业态才是页面主体。 + +相比“单页折叠式”或“全表单式”,作业台式更适合 PDA 连续扫码场景,原因是: + +- 核心视线始终集中在当前单据、扫码输入、最近结果 +- 可以让商品扫码输入框常驻焦点,适应物理扫码枪回车行为 +- 订单上下文与作业进度持续可见,减少扫错单、扫过量、扫混仓的风险 + +## 页面状态 + +页面只允许存在两个一等状态:`锁单态` 与 `作业态`。 + +### 锁单态 + +页面目标只有一件事:确定当前采购单。 + +展示内容: + +- 页面标题:`扫码采购入库` +- 主动作:`扫描采购订单号` +- 次动作:`手动选单` +- 可选辅助文案:说明供应商、仓库、结算账户将在锁单后自动带出 + +锁单态不展示以下内容: + +- 商品扫码输入框 +- 批次号输入框 +- 库位码输入框 +- 入库明细列表 +- 提交采购入库按钮 + +设计理由:未锁单前,商品扫码与提交都不可执行。提前展示只会制造误导。 + +### 作业态 + +选定采购单后进入作业态,页面主体切换为扫码作业台。 + +展示内容: + +- 顶部固定订单信息条 +- 商品扫码输入区 +- 批次号、库位码辅助区 +- 最近扫描记录区 +- 底部主提交区 + +作业态的默认焦点必须回到商品扫码输入框,以适应 PDA 连续扫码。 + +## 页面结构 + +### 1. 顶部固定订单信息条 + +用于持续回答两个问题:当前在扫哪张单,以及还差多少。 + +固定展示字段: + +- `采购单号`:最醒目的主字段,例如 `CG2025001` +- `供应商` +- `仓库` +- `进度`:格式为 `已扫 X / Y` +- `异常数`:格式为 `异常 N` + +规则: + +- 当异常数大于 0 时,使用警示色强调 +- 顶部信息条在明细滚动时仍保持可见 +- 标题可显示为 `采购入库 / CG2025001`,帮助快速确认当前上下文 + +### 2. 商品扫码输入区 + +这是作业态的主操作区。 + +字段与控件: + +- 商品条码输入框:主输入,常驻焦点 +- 批次号输入框:可选 +- 库位码输入框:可选 +- 相机按钮:仅手机摄像头备用 + +规则: + +- 商品扫码成功后自动累计 `+1` +- 默认不依赖手动点击“确认”按钮完成正常扫码 +- 若保留“确认”能力,也仅作为手机手输备用,不应成为 PDA 主路径 +- 商品扫码完成后,焦点自动回到商品条码输入框 + +### 3. 最近扫描记录区 + +该区域不是传统表单明细,而是作业回显区。 + +默认展示: + +- 最近 5 条扫描记录 +- 最新一条置顶 +- 最新成功记录高亮约 2 秒 + +每条记录显示: + +- 商品名称 +- 商品条码 +- 批次号 +- 库位码 +- 当前明细累计数量 +- 当前订单该商品剩余可入库数量 + +合并规则: + +- 同商品、同批次、同库位的重复扫码:合并到同一条明细并数量 `+1` +- 同商品但批次不同:分成新行 +- 同商品但库位不同:分成新行 + +操作规则: + +- 每条记录提供 `撤销` 或 `删除本条` 能力 +- 不提供高频可见的 `清空全部` + +### 4. 底部主提交区 + +底部只保留一个强主动作:`提交采购入库` + +规则: + +- 仅当存在有效明细时可点击 +- 点击后进入 loading,防止重复提交 +- 不将 `清空全部` 与 `提交` 并列摆放 + +## 扫码交互规则 + +### 正常路径 + +锁单后,PDA 连续扫码主路径如下: + +1. 扫描商品条码 +2. 系统匹配当前采购单中的订单行 +3. 若匹配成功,则新增或累计对应明细 +4. 数量自动 `+1` +5. 顶部进度同步刷新 +6. 页面显示成功反馈,例如:`西兰花 +1,已扫 12 / 30` +7. 焦点返回商品扫码输入框,等待下一枪 + +正常路径要求: + +- 不弹窗 +- 不要求人工再次确认 +- 不打断扫码节奏 + +### PDA 行为适配 + +考虑物理扫码枪通常自带输入结束与回车行为,页面需满足: + +- 商品条码输入框支持快速连续触发提交 +- 回车后自动执行匹配与累计 +- 成功后无需额外点击 +- 扫码完成后尽快恢复待扫状态 + +### 手机摄像头备用路径 + +手机端仍保留相机按钮,但定位是备用入口: + +- 适用于无 PDA 或临时补录 +- 交互与 PDA 一致,扫码成功后同样走自动累计逻辑 +- 不单独扩展额外的手机专属页面流程 + +## 异常处理 + +异常处理分为三类。 + +### 1. 不中断型反馈 + +适用于成功扫码。 + +表现: + +- 使用绿色反馈条或高可见状态条 +- 文案直接描述结果,例如:`西兰花 +1,已扫 12 / 30` +- 持续约 0.8 到 1.2 秒后消失 +- 焦点自动回到商品扫码输入框 + +### 2. 中断型异常 + +适用于以下场景: + +- 商品不在当前采购单内 +- 商品剩余可入库数量为 0 +- 扫码后将超出剩余可入库数量 +- 条码命中多个待入库订单行 +- 当前采购单未锁定 + +表现: + +- 使用红色错误条或常驻错误提示 +- 错误文案必须明确原因,不能只写“操作失败” +- 焦点不应伪装成成功回跳 +- 必要时进入人工处理分支 + +推荐错误文案: + +- `商品不在当前采购单内` +- `该商品剩余可入库 0 件` +- `该商品本次扫码后将超出剩余数量` +- `条码命中多个订单行,请人工选择` +- `请先扫描采购订单号` + +### 3. 可恢复型提示 + +适用于非强拦截场景,例如: + +- 批次号为空 +- 库位码为空 + +处理原则: + +- 若业务允许为空,则不拦截扫码 +- 可在记录中标记为空,或在提交前统一提醒 +- 不应影响正常扫码节奏 + +## 危险操作策略 + +仓库扫码场景下,危险操作必须降级。 + +优先提供: + +- `撤销上一笔` +- `删除单条` + +降级隐藏: + +- `清空全部` + +规则: + +- `清空全部` 放入右上角更多菜单或二级操作区 +- 执行前必须二次确认 +- 不能与 `提交采购入库` 同层并列 + +原因:现场最常见修正动作是撤销刚才那一枪,而不是整单清空。 + +## 提交流程 + +### 提交前条件 + +`提交采购入库` 按钮仅在满足以下条件时启用: + +- 已锁定采购单 +- 至少存在 1 条有效明细 + +### 提交前校验 + +提交前统一执行轻校验,检查: + +- 是否已锁单 +- 是否存在有效明细 +- 是否存在未处理异常 +- 是否存在超量或冲突记录 +- 若业务要求,可额外检查是否存在空库位记录 + +### 提交中行为 + +- 提交按钮进入 loading +- 页面避免重复触发提交 +- 不清空当前上下文,直到接口明确成功 + +### 提交成功后 + +成功反馈不能只有“成功”提示,而应给用户明确后续动作: + +- `继续当前单据扫码` +- `返回列表` + +若业务允许同一采购单分批入库,则继续当前单据是高价值动作。 + +### 提交失败后 + +提交失败时必须保留现场: + +- 当前采购单 +- 已扫明细 +- 当前批次号 / 库位码上下文 +- 当前异常状态 + +不能因为接口失败而丢失现场数据,否则会造成重复作业和人工补录。 + +## 数据与组件边界 + +建议将页面逻辑拆分为以下职责单元: + +- `锁单上下文`:负责采购单选择、锁定、切换、上下文字段映射 +- `扫码作业上下文`:负责商品扫码、累计、异常判断、反馈文案 +- `最近扫描记录列表`:负责最近记录展示、合并、撤销 +- `提交控制器`:负责校验、提交、成功/失败收尾 + +实现时应优先复用现有能力: + +- 扫码输入组件 +- ERP 明细展示组件 +- 采购入库现有数据结构与接口 + +避免将全部状态与条件判断继续堆在单个页面文件中。 + +## 错误处理与恢复策略 + +- 切换采购单前,如已有明细,需明确提示并确认 +- 删除或撤销明细后,顶部进度立即回算 +- 发生条码歧义时,进入人工选择而不是静默失败 +- 明细为空时不得允许提交 +- 页面刷新或重新进入时,若未设计暂存机制,则明确回到锁单态 + +## 测试关注点 + +测试应覆盖以下高风险路径: + +- 未锁单时误扫商品 +- 连续多枪同商品累计 +- 同商品不同批次 / 库位分行 +- 超量扫码拦截 +- 条码命中多个订单行 +- 撤销上一笔后进度与剩余数量回算 +- 提交失败后现场状态保留 +- PDA 回车触发下焦点能持续回到主扫码框 + +## 设计结论 + +采购入库扫码页应从“表单页”重构为“PDA 作业台页”: + +- 先锁单,再作业 +- 一枪一件,自动累计 +- 正常路径绝不打断 +- 异常路径明确、可恢复 +- 明细区服务作业反馈,不服务传统录单表单 +- 危险操作降级,提交操作集中 + +该方案优先满足工厂仓库高频扫码场景,同时保留手机摄像头作为备用输入方式。 diff --git a/env/.env b/env/.env index 44d8794..dec65b6 100644 --- a/env/.env +++ b/env/.env @@ -10,8 +10,8 @@ VITE_WX_APPID = 'wx1a832d51073d3a35' VITE_APP_PUBLIC_BASE=/ # 后台请求地址 -VITE_SERVER_BASEURL = 'http://119.96.62.56:7004/admin-api' -VITE_UPLOAD_BASEURL = 'http://localhost:48080/upload' +VITE_SERVER_BASEURL = 'http://192.168.1.20:48080/admin-api' +VITE_UPLOAD_BASEURL = 'http://192.168.1.20:48080/upload' # 备注:如果后台带统一前缀,则也要加到后面,eg: https://ukw0y1.laf.run/api # 注意,如果是微信小程序,还有一套请求地址的配置,根据 develop、trial、release 分别设置上传地址,见 `src/utils/index.ts`。 diff --git a/package.json b/package.json index 97fcc76..a378270 100644 --- a/package.json +++ b/package.json @@ -180,6 +180,9 @@ "pnpm": { "overrides": { "unconfig": "7.3.2" + }, + "patchedDependencies": { + "wot-design-uni@1.13.0": "patches/wot-design-uni@1.13.0.patch" } }, "overrides": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 565b131..ed78561 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,11 @@ overrides: bin-wrapper: npm:bin-wrapper-china unconfig: 7.3.2 +patchedDependencies: + wot-design-uni@1.13.0: + hash: 29ab7840a74d54969d4cbe5b840208d3d4911a82be189ac8581d462190fb5210 + path: patches/wot-design-uni@1.13.0.patch + importers: .: @@ -89,7 +94,7 @@ importers: version: 4.5.1(vue@3.4.21(typescript@5.8.3)) wot-design-uni: specifier: ^1.13.0 - version: 1.13.0(vue@3.4.21(typescript@5.8.3)) + version: 1.13.0(patch_hash=29ab7840a74d54969d4cbe5b840208d3d4911a82be189ac8581d462190fb5210)(vue@3.4.21(typescript@5.8.3)) z-paging: specifier: 2.8.7 version: 2.8.7 @@ -13316,7 +13321,7 @@ snapshots: word-wrap@1.2.5: {} - wot-design-uni@1.13.0(vue@3.4.21(typescript@5.8.3)): + wot-design-uni@1.13.0(patch_hash=29ab7840a74d54969d4cbe5b840208d3d4911a82be189ac8581d462190fb5210)(vue@3.4.21(typescript@5.8.3)): dependencies: vue: 3.4.21(typescript@5.8.3) diff --git a/src/api/erp/purchase-in/index.ts b/src/api/erp/purchase-in/index.ts index 33e1b9c..418029e 100644 --- a/src/api/erp/purchase-in/index.ts +++ b/src/api/erp/purchase-in/index.ts @@ -13,6 +13,8 @@ export interface PurchaseInItem { remark?: string warehouseId?: number warehouseName?: string + batchNo?: string + locationCode?: string productName?: string productBarCode?: string productUnitName?: string diff --git a/src/api/erp/stock-in/index.ts b/src/api/erp/stock-in/index.ts index 4077e04..d8952ac 100644 --- a/src/api/erp/stock-in/index.ts +++ b/src/api/erp/stock-in/index.ts @@ -7,9 +7,11 @@ export interface StockInItem { stockInId?: number warehouseId?: number warehouseName?: string + locationCode?: string productId?: number productName?: string productUnitName?: string + batchNo?: string count?: number productPrice?: number totalPrice?: number diff --git a/src/api/erp/stock-out/index.ts b/src/api/erp/stock-out/index.ts index b41a85d..bf81bbe 100644 --- a/src/api/erp/stock-out/index.ts +++ b/src/api/erp/stock-out/index.ts @@ -7,9 +7,11 @@ export interface StockOutItem { stockOutId?: number warehouseId?: number warehouseName?: string + locationCode?: string productId?: number productName?: string productUnitName?: string + batchNo?: string count?: number productPrice?: number totalPrice?: number diff --git a/src/components/erp-scan/item-list.vue b/src/components/erp-scan/item-list.vue index 7af0295..5e0cbbc 100644 --- a/src/components/erp-scan/item-list.vue +++ b/src/components/erp-scan/item-list.vue @@ -6,7 +6,7 @@ {{ item.productName }} - 删除 + {{ removeText }} 仓库:{{ item.warehouseName || '-' }} @@ -20,6 +20,14 @@ 单价:{{ formatNumber(item.productPrice) }} 库存:{{ formatNumber(item.stockCount) }} + + 目标:{{ formatNumber(item.targetCount) }} + + + 剩余:{{ formatNumber(item.remainCount) }} + 批次:{{ item.batchNo || '-' }} + 库位:{{ item.locationCode || '-' }} + - @@ -42,6 +50,10 @@ export interface ItemCardValue { productUnitName?: string productPrice?: number stockCount?: number + batchNo?: string + locationCode?: string + remainCount?: number + targetCount?: number count: number } @@ -49,9 +61,11 @@ withDefaults( defineProps<{ items: ItemCardValue[] showStock?: boolean + removeText?: string }>(), { showStock: false, + removeText: '删除', }, ) diff --git a/src/components/erp-scan/scan-input.vue b/src/components/erp-scan/scan-input.vue index c467fbc..6776228 100644 --- a/src/components/erp-scan/scan-input.vue +++ b/src/components/erp-scan/scan-input.vue @@ -10,11 +10,18 @@ @input="handleInput" @confirm="handleSubmit" > - @@ -27,12 +34,16 @@ const props = withDefaults( disabled?: boolean loading?: boolean autoFocus?: boolean + showConfirmButton?: boolean + cameraText?: string }>(), { placeholder: '请扫描条码', disabled: false, loading: false, autoFocus: true, + showConfirmButton: true, + cameraText: '相机', }, ) @@ -98,10 +109,12 @@ function handleCameraScan() { } &__button { - width: 128rpx; + min-width: 128rpx; height: 84rpx; + padding: 0 24rpx; line-height: 84rpx; border-radius: 12rpx; + box-sizing: border-box; &--primary { background: #1677ff; diff --git a/src/pages-erp/purchase-in/scan/components/order-context-bar.vue b/src/pages-erp/purchase-in/scan/components/order-context-bar.vue new file mode 100644 index 0000000..6ccdd9b --- /dev/null +++ b/src/pages-erp/purchase-in/scan/components/order-context-bar.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/src/pages-erp/purchase-in/scan/components/recent-scan-list.vue b/src/pages-erp/purchase-in/scan/components/recent-scan-list.vue new file mode 100644 index 0000000..fcd9b90 --- /dev/null +++ b/src/pages-erp/purchase-in/scan/components/recent-scan-list.vue @@ -0,0 +1,187 @@ + + + + + diff --git a/src/pages-erp/purchase-in/scan/components/scan-feedback-bar.vue b/src/pages-erp/purchase-in/scan/components/scan-feedback-bar.vue new file mode 100644 index 0000000..ff15817 --- /dev/null +++ b/src/pages-erp/purchase-in/scan/components/scan-feedback-bar.vue @@ -0,0 +1,43 @@ + + + + + diff --git a/src/pages-erp/purchase-in/scan/index.vue b/src/pages-erp/purchase-in/scan/index.vue new file mode 100644 index 0000000..bfaf896 --- /dev/null +++ b/src/pages-erp/purchase-in/scan/index.vue @@ -0,0 +1,1405 @@ + + + + + diff --git a/src/pages-erp/purchase-order/detail/index.vue b/src/pages-erp/purchase-order/detail/index.vue index 5c7ac5b..3bcd216 100644 --- a/src/pages-erp/purchase-order/detail/index.vue +++ b/src/pages-erp/purchase-order/detail/index.vue @@ -12,6 +12,7 @@ + 扫码录入 + + import type { ProductByBarCode } from '@/api/erp/product' import type { StockIn, StockInItem } from '@/api/erp/stock-in' -import type { SupplierSimple } from '@/api/erp/supplier' import type { Warehouse } from '@/api/erp/warehouse' import type { ItemCardValue } from '@/components/erp-scan/item-list.vue' @@ -82,21 +83,33 @@ interface StockInScanItem extends ItemCardValue { remark?: string } +interface OptionalSupplierOption { + id?: number + name: string +} + const toast = useToast() const scanCode = ref('') const scanLoading = ref(false) const submitting = ref(false) const remark = ref('') const warehouses = ref([]) -const suppliers = ref([]) +const suppliers = ref([]) const selectedWarehouseId = ref() const selectedSupplierId = ref() const items = ref([]) +const batchNo = ref('') +const locationCode = ref('') + +const EMPTY_SUPPLIER_OPTION: OptionalSupplierOption = { + id: undefined, + name: '不选择供应商(可选)', +} const currentWarehouse = computed(() => warehouses.value.find(item => item.id === selectedWarehouseId.value), ) -const currentSupplierName = computed(() => suppliers.value.find(item => item.id === selectedSupplierId.value)?.name || '请选择供应商(可选)') +const currentSupplierName = computed(() => suppliers.value.find(item => item.id === selectedSupplierId.value)?.name || EMPTY_SUPPLIER_OPTION.name) const selectedWarehouseIndex = computed(() => Math.max(warehouses.value.findIndex(item => item.id === selectedWarehouseId.value), 0)) const selectedSupplierIndex = computed(() => { const index = suppliers.value.findIndex(item => item.id === selectedSupplierId.value) @@ -126,7 +139,7 @@ async function loadInitialData() { ]) warehouses.value = warehouseList - suppliers.value = supplierList + suppliers.value = [EMPTY_SUPPLIER_OPTION, ...supplierList] selectedWarehouseId.value = warehouseList.find(item => item.defaultStatus)?.id || warehouseList[0]?.id } @@ -163,12 +176,22 @@ function handleSupplierChange(event: Record) { */ function appendScannedProduct(product: ProductByBarCode) { const warehouseId = selectedWarehouseId.value as number - const targetKey = buildScanMergeKey({ warehouseId, productId: product.id, count: 1 }) + const currentBatchNo = batchNo.value.trim() + const currentLocationCode = locationCode.value.trim() + const targetKey = buildScanMergeKey({ + warehouseId, + productId: product.id, + count: 1, + batchNo: currentBatchNo, + locationCode: currentLocationCode, + }, true) const existedIndex = items.value.findIndex(item => buildScanMergeKey({ warehouseId: item.warehouseId, productId: item.productId, count: item.count, - }) === targetKey) + batchNo: item.batchNo, + locationCode: item.locationCode, + }, true) === targetKey) if (existedIndex >= 0) { items.value[existedIndex].count += 1 @@ -184,6 +207,8 @@ function appendScannedProduct(product: ProductByBarCode) { productSpec: product.standard, productUnitName: product.unitName, productPrice: Number(product.minPrice || 0), + batchNo: currentBatchNo, + locationCode: currentLocationCode, count: 1, }) } @@ -315,8 +340,10 @@ function clearItems() { function buildSubmitItems(): StockInItem[] { return items.value.map(item => ({ warehouseId: item.warehouseId, + locationCode: item.locationCode, productId: item.productId, productPrice: item.productPrice, + batchNo: item.batchNo, count: item.count, remark: item.remark, })) @@ -341,16 +368,20 @@ async function handleSubmit() { submitting.value = true try { const payload: StockIn = { - supplierId: selectedSupplierId.value, inTime: new Date().toISOString(), remark: remark.value, items: buildSubmitItems(), } + if (selectedSupplierId.value !== undefined) { + payload.supplierId = selectedSupplierId.value + } await createStockIn(payload) toast.success('入库成功') clearItems() remark.value = '' + batchNo.value = '' + locationCode.value = '' } finally { submitting.value = false } diff --git a/src/pages-erp/stock-out/detail/index.vue b/src/pages-erp/stock-out/detail/index.vue index 0b1e2d4..531ef0c 100644 --- a/src/pages-erp/stock-out/detail/index.vue +++ b/src/pages-erp/stock-out/detail/index.vue @@ -12,6 +12,7 @@ + @@ -78,6 +79,14 @@ + + 去扫码 + ({}) /** 格式化数量 */ function formatCount(count?: number) { - if (count === undefined || count === null) return '-' + if (count === undefined || count === null) { + return '-' + } return count.toFixed(2) } /** 格式化金额 */ function formatPrice(price?: number) { - if (price === undefined || price === null) return '-' + if (price === undefined || price === null) { + return '-' + } return `¥${price.toFixed(2)}` } /** 格式化日期 */ function formatDate(dateStr?: string) { - if (!dateStr) return '-' + if (!dateStr) { + return '-' + } return dateStr.substring(0, 10) } @@ -158,7 +173,9 @@ function handleBack() { /** 加载详情 */ async function getDetail() { - if (!props.id) return + if (!props.id) { + return + } try { toast.loading('加载中...') detail.value = await getStockOut(props.id) @@ -172,13 +189,20 @@ function handleEdit() { uni.navigateTo({ url: `/pages-erp/stock-out/form/index?id=${props.id}` }) } +/** 去扫码执行 */ +function handleTaskScan() { + uni.navigateTo({ url: `/pages-erp/stock-out/task-scan/index?id=${props.id}` }) +} + /** 审批 */ function handleApprove() { uni.showModal({ title: '提示', content: '确定要审批该出库单吗?', success: async (res) => { - if (!res.confirm) return + if (!res.confirm) { + return + } try { await updateStockOutStatus(props.id, 20) toast.success('审批成功') @@ -196,7 +220,9 @@ function handleReverseApprove() { title: '提示', content: '确定要反审批该出库单吗?', success: async (res) => { - if (!res.confirm) return + if (!res.confirm) { + return + } try { await updateStockOutStatus(props.id, 10) toast.success('反审批成功') @@ -214,7 +240,9 @@ function handleDelete() { title: '提示', content: '确定要删除该出库单吗?', success: async (res) => { - if (!res.confirm) return + if (!res.confirm) { + return + } try { await deleteStockOut([props.id]) toast.success('删除成功') diff --git a/src/pages-erp/stock-out/index.vue b/src/pages-erp/stock-out/index.vue index aff9aa8..9906c66 100644 --- a/src/pages-erp/stock-out/index.vue +++ b/src/pages-erp/stock-out/index.vue @@ -13,18 +13,18 @@ - + {{ tab.label }} @@ -58,7 +58,7 @@ 产品 - {{ item.productNames || '-' }} + {{ item.productNames || '-' }} @@ -71,19 +71,33 @@ {{ item.creatorName || '-' }} - + - {{ formatCount(item.totalCount) }} - 数量 + + {{ formatCount(item.totalCount) }} + + + 数量 + - {{ formatPrice(item.totalPrice) }} - 金额 + + {{ formatPrice(item.totalPrice) }} + + + 金额 + + + 去扫码 + - 出库单号 + + 出库单号 + - 审核状态 + + 审核状态 + - 重置 - 搜索 + + 重置 + + + 搜索 + @@ -213,29 +235,34 @@ const statusOptions = [ /** 搜索条件 placeholder */ const searchPlaceholder = computed(() => { const conditions: string[] = [] - if (searchForm.no) conditions.push(`单号:${searchForm.no}`) + if (searchForm.no) + conditions.push(`单号:${searchForm.no}`) if (searchForm.status !== undefined) { const statusLabel = statusOptions.find(o => o.value === searchForm.status)?.label - if (statusLabel && statusLabel !== '全部') conditions.push(`状态:${statusLabel}`) + if (statusLabel && statusLabel !== '全部') + conditions.push(`状态:${statusLabel}`) } return conditions.length > 0 ? conditions.join(' | ') : '搜索出库单' }) /** 格式化数量 */ function formatCount(count?: number) { - if (count === undefined || count === null) return '-' + if (count === undefined || count === null) + return '-' return count.toFixed(2) } /** 格式化金额 */ function formatPrice(price?: number) { - if (price === undefined || price === null) return '-' + if (price === undefined || price === null) + return '-' return `¥${price.toFixed(2)}` } /** 格式化日期 */ function formatDate(dateStr?: string) { - if (!dateStr) return '-' + if (!dateStr) + return '-' return dateStr.substring(0, 10) } @@ -257,7 +284,8 @@ async function getList() { loadMoreState.value = 'loading' try { const params = { ...queryParams.value } - if (searchForm.no) params.no = searchForm.no + if (searchForm.no) + params.no = searchForm.no const data = await getStockOutPage(params) list.value = [...list.value, ...data.list] total.value = data.total @@ -292,7 +320,8 @@ function handleReset() { /** 加载更多 */ function loadMore() { - if (loadMoreState.value === 'finished') return + if (loadMoreState.value === 'finished') + return queryParams.value.pageNo++ getList() } @@ -307,6 +336,11 @@ function handleEdit(item: StockOut) { uni.navigateTo({ url: `/pages-erp/stock-out/form/index?id=${item.id}` }) } +/** 去扫码执行 */ +function handleTaskScan(item: StockOut) { + uni.navigateTo({ url: `/pages-erp/stock-out/task-scan/index?id=${item.id}` }) +} + /** 详情 */ function handleDetail(item: StockOut) { uni.navigateTo({ url: `/pages-erp/stock-out/detail/index?id=${item.id}` }) @@ -318,7 +352,8 @@ function handleApprove(id: number) { title: '提示', content: '确定要审批该出库单吗?', success: async (res) => { - if (!res.confirm) return + if (!res.confirm) + return try { await updateStockOutStatus(id, 20) toast.success('审批成功') @@ -336,7 +371,8 @@ function handleReverseApprove(id: number) { title: '提示', content: '确定要反审批该出库单吗?', success: async (res) => { - if (!res.confirm) return + if (!res.confirm) + return try { await updateStockOutStatus(id, 10) toast.success('反审批成功') @@ -354,7 +390,8 @@ function handleDelete(id: number) { title: '提示', content: '确定要删除该出库单吗?', success: async (res) => { - if (!res.confirm) return + if (!res.confirm) + return try { await deleteStockOut([id]) toast.success('删除成功') diff --git a/src/pages-erp/stock-out/scan/index.vue b/src/pages-erp/stock-out/scan/index.vue index db25f6e..b3d57ab 100644 --- a/src/pages-erp/stock-out/scan/index.vue +++ b/src/pages-erp/stock-out/scan/index.vue @@ -31,6 +31,8 @@ 扫码录入 + +