From b96359b0f95c765dab49bf65a898b4367c6c4d5c Mon Sep 17 00:00:00 2001
From: zhongwenkai <3478244299@qq.com>
Date: Thu, 18 Jun 2026 15:31:48 +0800
Subject: [PATCH] =?UTF-8?q?style:=20=E5=A4=87=E4=BB=B6=E5=87=BA=E5=85=A5?=
=?UTF-8?q?=E5=BA=93=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/api/mes/sparepart.js | 20 ++-
.../pages/sparepartInbound/create.vue | 6 +-
.../sparepartInbound/sparepartConfirm.vue | 86 +++++------
.../sparepartInbound/sparepartSelect.vue | 1 -
.../pages/sparepartInventory/index.vue | 36 -----
.../pages/sparepartOutbound/create.vue | 5 +-
.../sparepartOutbound/sparepartConfirm.vue | 139 +++++++++++-------
7 files changed, 152 insertions(+), 141 deletions(-)
diff --git a/src/api/mes/sparepart.js b/src/api/mes/sparepart.js
index 896e9ee..546c95b 100644
--- a/src/api/mes/sparepart.js
+++ b/src/api/mes/sparepart.js
@@ -1,13 +1,14 @@
import request from '@/utils/request'
-// 备件列表(分页查询全部产品,前端按 categoryType=5 过滤备件)
+// 备件列表(分页查询,后端按 categoryType=3 过滤备件)
export function getSparepartSimpleList(pageNo = 1) {
return request({
url: '/admin-api/erp/product/page',
method: 'get',
params: {
pageNo,
- pageSize: 100
+ pageSize: 100,
+ categoryType: 3
}
})
}
@@ -21,7 +22,7 @@ export function getSparepartDetail(id) {
})
}
-// 备件库存数量
+// 备件总库存数量(返回数字)
export function getSparepartStockCount(productId) {
return request({
url: '/admin-api/erp/stock/get-count',
@@ -30,6 +31,19 @@ export function getSparepartStockCount(productId) {
})
}
+// 备件库存详情(带 warehouseId、areaId 查指定仓库库区库存,返回对象)
+export function getSparepartStock(productId, warehouseId, areaId) {
+ return request({
+ url: '/admin-api/erp/stock/get',
+ method: 'get',
+ params: {
+ productId,
+ warehouseId: warehouseId || undefined,
+ areaId: areaId || undefined
+ }
+ })
+}
+
// 备件库存查询(分页)
export function getSparepartInventoryPage(params) {
return request({
diff --git a/src/pages_function/pages/sparepartInbound/create.vue b/src/pages_function/pages/sparepartInbound/create.vue
index b3d3b64..2b5f1c1 100644
--- a/src/pages_function/pages/sparepartInbound/create.vue
+++ b/src/pages_function/pages/sparepartInbound/create.vue
@@ -357,9 +357,13 @@ async function handleSubmit() {
}
})
+ const now = new Date()
+ const [y, m, d] = inboundDate.value.split('-').map(Number)
+ const inTime = new Date(y, m - 1, d, now.getHours(), now.getMinutes(), now.getSeconds()).getTime()
+
const submitData = {
isCode: true,
- inTime: inboundDate.value ? new Date(inboundDate.value.replace(/-/g, '/')).getTime() : Date.now(),
+ inTime: inTime,
stockUserId: String(selectedOperatorId.value),
supplierId: itemList.value[0]?.supplierId,
status: 0,
diff --git a/src/pages_function/pages/sparepartInbound/sparepartConfirm.vue b/src/pages_function/pages/sparepartInbound/sparepartConfirm.vue
index d3fdcda..4937bef 100644
--- a/src/pages_function/pages/sparepartInbound/sparepartConfirm.vue
+++ b/src/pages_function/pages/sparepartInbound/sparepartConfirm.vue
@@ -31,7 +31,7 @@
{{ textValue(sparepart.standard || sparepart.deviceSpec) }}
- 当前库存:
+ 当前总库存:
{{ sparepart.count != null ? sparepart.count : 0 }}{{ textUnit(sparepart.unitName || sparepart.minStockUnitName || '个') }}
@@ -54,45 +54,6 @@
-
-
-
- 入库数量
-
-
-
- 入库数量
-
- 单位:{{ textValue(sparepart.purchaseUnitName) }}
-
-
- 折算后库存数量:
- {{ calculatedStock }}
- {{ stockUnitLabel(sparepart) }}
-
-
- {{ inboundQty || 0 }}{{ textValue(sparepart.purchaseUnitName) }} × {{ textValue(sparepart.purchaseUnitConvertQuantity) }}{{ stockUnitLabel(sparepart) }} = {{ calculatedStock }}{{ stockUnitLabel(sparepart) }}
-
-
-
-
-
-
- 供应商
-
-
-
-
- {{ defaultSupplierName || '未配置默认供应商' }}
-
-
-
-
@@ -154,6 +115,45 @@
+
+
+
+
+ 入库数量
+
+
+
+ 入库数量
+
+ 单位:{{ textValue(sparepart.purchaseUnitName) }}
+
+
+ 折算后库存数量:
+ {{ calculatedStock }}
+ {{ stockUnitLabel(sparepart) }}
+
+
+ {{ inboundQty || 0 }}{{ textValue(sparepart.purchaseUnitName) }} × {{ textValue(sparepart.purchaseUnitConvertQuantity) }}{{ stockUnitLabel(sparepart) }} = {{ calculatedStock }}{{ stockUnitLabel(sparepart) }}
+
+
+
+
+
+
+ 供应商
+
+
+
+
+ {{ defaultSupplierName || '未配置默认供应商' }}
+
+
+
@@ -369,8 +369,7 @@ async function loadStockCount() {
if (!id) return
try {
const res = await getSparepartStockCount(id)
- const count = res?.data ?? res
- sparepart.value.count = (count != null) ? Number(count) : 0
+ sparepart.value.count = (res?.data ?? res) != null ? Number(res?.data ?? res) : 0
} catch (e) {
console.error('获取库存失败:', e)
sparepart.value.count = 0
@@ -413,7 +412,8 @@ onHide(() => {
.info-item { display: flex; align-items: center; margin-bottom: 8rpx; }
.info-label { font-size: 26rpx; color: #6b7280; flex-shrink: 0; }
.info-name { font-size: 30rpx; font-weight: 700; color: #0f172a; }
-.info-value { font-size: 26rpx; color: #374151; &.stock-highlight { color: #2563eb; font-weight: 500; } }
+.info-value { font-size: 26rpx; color: #374151; }
+.stock-highlight { font-size: 30rpx; font-weight: 700; color: #1f2937; }
.card-bottom { margin-top: 20rpx; padding-top: 20rpx; border-top: 1rpx solid #f0f0f0; }
.detail-row { display: flex; align-items: center; margin-bottom: 14rpx;
diff --git a/src/pages_function/pages/sparepartInbound/sparepartSelect.vue b/src/pages_function/pages/sparepartInbound/sparepartSelect.vue
index c451d98..e22b1a3 100644
--- a/src/pages_function/pages/sparepartInbound/sparepartSelect.vue
+++ b/src/pages_function/pages/sparepartInbound/sparepartSelect.vue
@@ -147,7 +147,6 @@ function handleConfirm() {
// 存入 globalData 后跳转到对应确认页
getApp().globalData._sparepartBeforeConfirm = item
const from = getApp().globalData._sparepartSelectFrom || 'inbound'
- getApp().globalData._sparepartSelectFrom = null
const url = from === 'outbound'
? '/pages_function/pages/sparepartOutbound/sparepartConfirm'
: '/pages_function/pages/sparepartInbound/sparepartConfirm'
diff --git a/src/pages_function/pages/sparepartInventory/index.vue b/src/pages_function/pages/sparepartInventory/index.vue
index 5f4d9bf..8cc570e 100644
--- a/src/pages_function/pages/sparepartInventory/index.vue
+++ b/src/pages_function/pages/sparepartInventory/index.vue
@@ -25,8 +25,6 @@
@@ -83,10 +81,6 @@
-
- ↑
-
-
@@ -132,8 +126,6 @@ const pageSize = ref(10)
const total = ref(0)
const searchKeyword = ref('')
const selectedWarehouse = ref('')
-const scrollTop = ref(0)
-const showGoTop = ref(false)
const warehouseOptions = ref([])
@@ -313,15 +305,6 @@ async function loadMore() {
await fetchList(false)
}
-function handleScroll(e) {
- const top = e?.detail?.scrollTop || 0
- showGoTop.value = top > 600
-}
-
-function goTop() {
- scrollTop.value = 0
-}
-
function textValue(value) {
if (value === 0) return '0'
if (value === false) return t('functionCommon.no')
@@ -516,25 +499,6 @@ function formatDateTime(value) {
padding-top: 160rpx;
}
-.go-top-btn {
- position: fixed;
- right: 32rpx;
- bottom: calc(56rpx + env(safe-area-inset-bottom));
- display: flex;
- align-items: center;
- justify-content: center;
- width: 92rpx;
- height: 92rpx;
- border-radius: 46rpx;
- background: rgba(31, 75, 121, 0.84);
- box-shadow: 0 14rpx 30rpx rgba(24, 63, 108, 0.24);
-}
-
-.go-top-icon {
- color: #ffffff;
- font-size: 32rpx;
-}
-
.picker-content {
padding: 24rpx 24rpx 36rpx;
border-radius: 28rpx 28rpx 0 0;
diff --git a/src/pages_function/pages/sparepartOutbound/create.vue b/src/pages_function/pages/sparepartOutbound/create.vue
index d4c7bd0..7339308 100644
--- a/src/pages_function/pages/sparepartOutbound/create.vue
+++ b/src/pages_function/pages/sparepartOutbound/create.vue
@@ -219,8 +219,9 @@ async function handleSubmit() {
if (!outboundDate.value) { uni.showToast({ title: '请选择出库时间', icon: 'none' }); return }
if (!selectedOperatorId.value) { uni.showToast({ title: '请选择经办人', icon: 'none' }); return }
- // 完全对齐 Web 端格式:13位毫秒时间戳 + stockUserId
- const outTime = outboundDate.value ? new Date(outboundDate.value.replace(/-/g, '/')).getTime() : Date.now()
+ const now = new Date()
+ const [y, m, d] = outboundDate.value.split('-').map(Number)
+ const outTime = new Date(y, m - 1, d, now.getHours(), now.getMinutes(), now.getSeconds()).getTime()
let totalCount = 0
const items = itemList.value.map(item => {
diff --git a/src/pages_function/pages/sparepartOutbound/sparepartConfirm.vue b/src/pages_function/pages/sparepartOutbound/sparepartConfirm.vue
index f04fea5..17e45f3 100644
--- a/src/pages_function/pages/sparepartOutbound/sparepartConfirm.vue
+++ b/src/pages_function/pages/sparepartOutbound/sparepartConfirm.vue
@@ -16,7 +16,7 @@
备件名称:{{ textValue(sparepart.name) }}
规格:{{ textValue(sparepart.standard || sparepart.deviceSpec) }}
- 当前库存:{{ sparepart.count != null ? sparepart.count : 0 }}{{ textUnit(sparepart.unitName || sparepart.minStockUnitName || '个') }}
+ 当前总库存:{{ sparepart.count != null ? sparepart.count : 0 }}{{ textUnit(sparepart.unitName || sparepart.minStockUnitName || '个') }}
@@ -94,43 +94,6 @@
-
-
- 出库数量
-
-
-
- 出库数量
-
- 单位:{{ textValue(sparepart.purchaseUnitName) }}
-
-
- 出库后剩余库存:
- {{ remainingStock }}
- {{ stockUnitLabel(sparepart) }}
-
- {{ currentStockText }}
- {{ outboundQty || 0 }}{{ textValue(sparepart.purchaseUnitName) }} × {{ textValue(sparepart.purchaseUnitConvertQuantity) }}{{ stockUnitLabel(sparepart) }} = {{ calculatedStock }}{{ stockUnitLabel(sparepart) }}
-
- ⚠
-
- 当前库存不足,不能出库
- 当前库存:{{ stockCount }}{{ stockUnitLabel(sparepart) }}({{ stockPackText }})
- 本次出库:{{ calculatedStock }}{{ stockUnitLabel(sparepart) }}({{ outboundPackText }})
-
-
-
-
-
-
- 供应商
-
-
-
- {{ defaultSupplierName || '未配置默认供应商' }}
-
-
-
仓库/库区
@@ -173,6 +136,44 @@
+
+
+
+ 出库数量
+
+
+
+ 出库数量
+
+ 单位:{{ textValue(sparepart.purchaseUnitName) }}
+
+ 请先选择仓库与库区,选择后可查看当前库存
+
+ 出库后当前仓库/库区的剩余库存:
+ {{ remainingStock }}
+ {{ stockUnitLabel(sparepart) }}
+
+ {{ currentStockText }}
+ {{ outboundQty || 0 }}{{ textValue(sparepart.purchaseUnitName) }} × {{ textValue(sparepart.purchaseUnitConvertQuantity) }}{{ stockUnitLabel(sparepart) }} = {{ calculatedStock }}{{ stockUnitLabel(sparepart) }}
+
+ ⚠
+
+ 当前仓库/库区的库存不足,不能出库
+ 当前仓库/库区的库存:{{ stockCount }}{{ stockUnitLabel(sparepart) }}({{ stockPackText }})
+ 本次出库:{{ calculatedStock }}{{ stockUnitLabel(sparepart) }}({{ outboundPackText }})
+
+
+
+
+
+
+ 供应商
+
+
+
+ {{ defaultSupplierName || '未配置默认供应商' }}
+
+
@@ -190,12 +191,14 @@ import { getDeviceLedgerList } from '@/api/mes/moldoperate'
import { getWarehouseSimpleList, getWarehouseAreaSimpleList } from '@/api/mes/moldget'
import { getEquipmentRepairListByDeviceId, getMaintenanceTicketPage } from '@/api/mes/equipment'
import { getDvRepairPage } from '@/api/mes/dvrepair'
-import { getSparepartDetail, getSparepartStockCount } from '@/api/mes/sparepart'
+import { getSparepartDetail, getSparepartStock, getSparepartStockCount } from '@/api/mes/sparepart'
const sparepart = ref({})
const outboundQty = ref(null)
const selectedPurpose = ref('repair')
+const hasWarehouseArea = computed(() => selectedWarehouse.value && selectedArea.value)
+
function setPurpose(value) {
selectedPurpose.value = value
selectedDevice.value = null
@@ -237,17 +240,24 @@ const sparepartImage = computed(() => {
if (Array.isArray(images)) return String(images[0] || '')
return String(images).split(',')[0]?.trim() || ''
})
-const stockCount = computed(() => sparepart.value.count ?? 0)
+// 选中仓库/库区的库存量,未选则为 0
+const warehouseAreaStockCount = ref(0)
+const stockCount = computed(() => warehouseAreaStockCount.value)
const calculatedStock = computed(() => {
const qty = Number(outboundQty.value) || 0
const ratio = Number(sparepart.value.purchaseUnitConvertQuantity) || 1
- return qty * ratio
+ const result = qty * ratio
+ return Number.isFinite(result) ? result : 0
})
const remainingStock = computed(() => {
- return Math.max(stockCount.value - calculatedStock.value, 0)
+ const sc = Number.isFinite(stockCount.value) ? stockCount.value : 0
+ const cs = Number.isFinite(calculatedStock.value) ? calculatedStock.value : 0
+ return Math.max(sc - cs, 0)
})
const stockExceeded = computed(() => {
- return outboundQty.value > 0 && calculatedStock.value > stockCount.value
+ const sc = Number.isFinite(stockCount.value) ? stockCount.value : 0
+ const cs = Number.isFinite(calculatedStock.value) ? calculatedStock.value : 0
+ return outboundQty.value > 0 && cs > sc
})
function formatStockPack(count) {
@@ -263,7 +273,7 @@ function formatStockPack(count) {
const currentStockText = computed(() => {
const text = formatStockPack(stockCount.value)
- return text ? `当前库存:${text}` : ''
+ return text ? `当前仓库/库区的库存:${text}` : ''
})
const stockPackText = computed(() => {
return formatStockPack(stockCount.value) || `${stockCount.value}${stockUnitLabel(sparepart)}`
@@ -298,7 +308,7 @@ function handleConfirm() {
if (stockExceeded.value) {
uni.showModal({
title: '库存不足',
- content: `当前库存:${stockCount.value}${stockUnitLabel(sparepart)}(${stockPackText.value})\n本次出库:${calculatedStock.value}${stockUnitLabel(sparepart)}(${outboundPackText.value})`,
+ content: `当前仓库/库区的库存:${stockCount.value}${stockUnitLabel(sparepart)}(${stockPackText.value})\n本次出库:${calculatedStock.value}${stockUnitLabel(sparepart)}(${outboundPackText.value})`,
showCancel: false,
confirmText: '知道了'
})
@@ -449,19 +459,17 @@ async function loadRepairOrdersById(deviceId) {
}
function toggleWarehouseDropdown() { showWarehouseDropdown.value = !showWarehouseDropdown.value }
-function handleSelectWarehouse(item) { selectedWarehouse.value = item; showWarehouseDropdown.value = false; selectedArea.value = null; areaOptions.value = []; loadAreas(item.value) }
+function handleSelectWarehouse(item) { selectedWarehouse.value = item; showWarehouseDropdown.value = false; selectedArea.value = null; areaOptions.value = []; warehouseAreaStockCount.value = 0; loadAreas(item.value) }
async function loadWarehouses() {
try {
const res = await getWarehouseSimpleList()
const data = Array.isArray(res) ? res : (Array.isArray(res?.data) ? res.data : [])
warehouseOptions.value = data.map(w => ({ value: w.id, label: w.name || String(w.id || '') }))
- const defaultWh = warehouseOptions.value.find(w => (w.label || '').includes('备件仓'))
- if (defaultWh) { selectedWarehouse.value = defaultWh; loadAreas(defaultWh.value) }
} catch (e) {}
}
function toggleAreaDropdown() { if (!selectedWarehouse.value) { uni.showToast({ title: '请先选择仓库', icon: 'none' }); return }; showAreaDropdown.value = !showAreaDropdown.value }
-function handleSelectArea(item) { selectedArea.value = item; showAreaDropdown.value = false }
+function handleSelectArea(item) { selectedArea.value = item; showAreaDropdown.value = false; loadStockCount() }
async function loadAreas(warehouseId) {
if (!warehouseId) return
loadingAreas.value = true
@@ -470,8 +478,6 @@ async function loadAreas(warehouseId) {
const res = await getWarehouseAreaSimpleList(warehouseId)
const data = Array.isArray(res) ? res : (Array.isArray(res?.data) ? res.data : [])
areaOptions.value = data.map(a => ({ value: a.id, label: a.name || a.areaName || String(a.id || '') }))
- const defaultArea = areaOptions.value.find(a => (a.label || '').includes('备件库'))
- if (defaultArea) selectedArea.value = defaultArea
} catch (e) {} finally { loadingAreas.value = false }
}
@@ -485,7 +491,7 @@ onShow(async () => {
try {
const res = await getSparepartDetail(selectResult.id)
const detail = res?.data || res
- if (detail) { sparepart.value = { ...sparepart.value, ...detail }; loadStockCount() }
+ if (detail) { sparepart.value = { ...sparepart.value, ...detail }; loadTotalStockCount() }
} catch (e) { console.error('获取备件详情失败:', e) }
}
}
@@ -493,11 +499,32 @@ onShow(async () => {
loadWarehouses()
})
+// 加载总库存(已选备件卡片显示,get-count 返回纯数字)
+async function loadTotalStockCount() {
+ const id = sparepart.value.id
+ if (!id) return
+ try {
+ const res = await getSparepartStockCount(id)
+ sparepart.value.count = (res?.data ?? res) != null ? Number(res?.data ?? res) : 0
+ } catch (e) { sparepart.value.count = 0 }
+}
+
+// 加载选中仓库库区的库存(出库数量区块用)
async function loadStockCount() {
const id = sparepart.value.id
if (!id) return
- try { const res = await getSparepartStockCount(id); sparepart.value.count = (res?.data ?? res) != null ? Number(res?.data ?? res) : 0 }
- catch (e) { sparepart.value.count = 0 }
+ const whId = selectedWarehouse.value?.value
+ const arId = selectedArea.value?.value
+ if (!whId || !arId) {
+ warehouseAreaStockCount.value = 0
+ return
+ }
+ try {
+ const res = await getSparepartStock(id, whId, arId)
+ const detail = res?.data || res
+ const count = (detail != null && typeof detail === 'object') ? Number(detail.count || 0) : Number(detail || 0)
+ warehouseAreaStockCount.value = Number.isFinite(count) ? count : 0
+ } catch (e) { warehouseAreaStockCount.value = 0 }
}
onHide(() => { showDeviceDropdown.value = false; showOrderDropdown.value = false })
@@ -519,7 +546,8 @@ onHide(() => { showDeviceDropdown.value = false; showOrderDropdown.value = false
.info-item { display: flex; align-items: center; margin-bottom: 8rpx; }
.info-label { font-size: 26rpx; color: #6b7280; flex-shrink: 0; }
.info-name { font-size: 30rpx; font-weight: 700; color: #0f172a; }
-.info-value { font-size: 26rpx; color: #374151; &.stock-highlight { color: #2563eb; font-weight: 500; } }
+.info-value { font-size: 26rpx; color: #374151; }
+.stock-highlight { font-size: 30rpx; font-weight: 700; color: #1f2937; }
.card-bottom { margin-top: 20rpx; padding-top: 20rpx; border-top: 1rpx solid #f0f0f0; }
.detail-row { display: flex; align-items: center; margin-bottom: 14rpx; &:last-child { margin-bottom: 0; } &.two-col { justify-content: space-between; } }
.detail-col { display: flex; align-items: center; flex: 1; }
@@ -541,6 +569,7 @@ onHide(() => { showDeviceDropdown.value = false; showOrderDropdown.value = false
.convert-label-inline { font-size: 26rpx; color: #6b7280; }
.convert-value-inline { font-size: 36rpx; font-weight: 700; color: #1f2937; margin-left: auto; }
.convert-unit-inline { font-size: 24rpx; color: #64748b; margin-left: 8rpx; }
+.warehouse-hint { margin-top: 16rpx; padding: 16rpx 20rpx; background: #fefce8; border: 1rpx solid #fef08a; border-radius: 10rpx; font-size: 24rpx; color: #a16207; }
.convert-formula-inline { margin-top: 10rpx; font-size: 22rpx; color: #9ca3af; }
.convert-helper { margin-top: 8rpx; font-size: 24rpx; color: #9ca3af; }
.text-danger { color: #dc2626 !important; }