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; }