From 03a05815d7ea5612206b6cfe5d6537b4d4cedc0a Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 15 九月 2026 11:41:32 +0800
Subject: [PATCH] 天津潜宇塑胶app 1.添加采购需求、库存盘点、计件单价配置、产量统计、材料消耗核算、成本核算分析页面
---
src/pages/inventoryManagement/stockManagement/index.vue | 264 +++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 247 insertions(+), 17 deletions(-)
diff --git a/src/pages/inventoryManagement/stockManagement/index.vue b/src/pages/inventoryManagement/stockManagement/index.vue
index 45d27ad..49e1758 100644
--- a/src/pages/inventoryManagement/stockManagement/index.vue
+++ b/src/pages/inventoryManagement/stockManagement/index.vue
@@ -2,39 +2,141 @@
<view class="app-container">
<PageHeader title="搴撳瓨绠$悊"
@back="goBack" />
- <view v-if="loading"
- class="loading-state">
- <up-loading-icon text="鍔犺浇涓�..."></up-loading-icon>
+ <!-- 搴撳瓨棰勮寮�鍏� -->
+ <view class="warn-bar">
+ <view class="warn-left">
+ <text class="warn-label">鍙湅棰勮</text>
+ <up-switch v-model="warnOnly"
+ size="small"
+ activeColor="#f56c6c"
+ @change="handleWarnToggle"></up-switch>
+ </view>
</view>
+ <!-- 棰勮鍒楄〃 -->
+ <template v-if="warnOnly">
+ <view class="warn-search">
+ <view class="search-input">
+ <up-input class="search-text"
+ v-model="warnSearch.productName"
+ placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�"
+ clearable
+ @confirm="handleWarnQuery" />
+ </view>
+ <view class="filter-button"
+ @click="handleWarnQuery">
+ <up-icon name="search"
+ size="24"
+ color="#999"></up-icon>
+ </view>
+ </view>
+ <scroll-view scroll-y
+ class="warn-list"
+ v-if="warnList.length > 0"
+ @scrolltolower="loadWarnMore">
+ <view v-for="item in warnList"
+ :key="item.id"
+ class="ledger-item warn-item"
+ :class="{ 'is-warn': isWarnRow(item) }">
+ <view class="item-header">
+ <view class="item-left">
+ <view class="document-icon warn-icon">
+ <up-icon name="warning"
+ size="16"
+ color="#ffffff"></up-icon>
+ </view>
+ <text class="item-id">{{ item.productName || '-' }}</text>
+ </view>
+ <up-tag text="棰勮"
+ type="error"
+ size="mini"
+ v-if="isWarnRow(item)" />
+ </view>
+ <up-divider></up-divider>
+ <view class="item-details">
+ <view class="detail-row">
+ <text class="detail-label">瑙勬牸鍨嬪彿</text>
+ <text class="detail-value">{{ item.model || '-' }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍗曚綅</text>
+ <text class="detail-value">{{ item.unit || '-' }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鏁伴噺</text>
+ <text class="detail-value">{{ formatQty(item.qualitity) }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">閿佸畾鏁伴噺</text>
+ <text class="detail-value">{{ formatQty(item.lockedQuantity) }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鍙敤鏁伴噺</text>
+ <text class="detail-value"
+ :class="{ 'warn-value': isWarnRow(item) }">{{ formatQty(item.un_locked_quantity ?? item.unLockedQuantity) }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">棰勮鍊�</text>
+ <text class="detail-value">{{ formatQty(item.warnNum) }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="detail-label">鎵瑰彿</text>
+ <text class="detail-value">{{ item.batchNo || '-' }}</text>
+ </view>
+ </view>
+ </view>
+ <up-loadmore :status="warnStatus" />
+ </scroll-view>
+ <view v-else-if="!warnLoading"
+ class="no-data">
+ <up-empty mode="data"
+ text="鏆傛棤棰勮搴撳瓨"></up-empty>
+ </view>
+ </template>
+ <!-- 搴撳瓨鍒楄〃 -->
<template v-else>
- <up-tabs :list="tabs"
- @click="handleTabClick"
- :current="activeTab" />
- <swiper class="swiper-box"
- :current="activeTab"
- @change="handleSwiperChange">
- <swiper-item class="swiper-item"
- v-for="tab in products"
- :key="tab.id">
- <record :product-id="tab.id"
- v-if="activeTab === products.indexOf(tab) || initializedTabs.includes(tab.id)" />
- </swiper-item>
- </swiper>
+ <view v-if="loading"
+ class="loading-state">
+ <up-loading-icon text="鍔犺浇涓�..."></up-loading-icon>
+ </view>
+ <template v-else>
+ <up-tabs :list="tabs"
+ @click="handleTabClick"
+ :current="activeTab" />
+ <swiper class="swiper-box"
+ :current="activeTab"
+ @change="handleSwiperChange">
+ <swiper-item class="swiper-item"
+ v-for="tab in products"
+ :key="tab.id">
+ <record :product-id="tab.id"
+ v-if="activeTab === products.indexOf(tab) || initializedTabs.includes(tab.id)" />
+ </swiper-item>
+ </swiper>
+ </template>
</template>
</view>
</template>
<script setup>
- import { ref, onMounted } from "vue";
+ import { ref, reactive, onMounted } from "vue";
import PageHeader from "@/components/PageHeader.vue";
import Record from "./Record.vue";
import { productTreeList } from "@/api/basicData/product.js";
+ import { getStockWarnPage } from "@/api/inventoryManagement/stockInventory.js";
const activeTab = ref(0);
const tabs = ref([]);
const products = ref([]);
const loading = ref(false);
const initializedTabs = ref([]);
+
+ // 棰勮
+ const warnOnly = ref(false);
+ const warnLoading = ref(false);
+ const warnStatus = ref("loadmore");
+ const warnList = ref([]);
+ const warnPage = reactive({ current: 1, size: 10, total: 0 });
+ const warnSearch = reactive({ productName: "" });
const handleTabClick = item => {
activeTab.value = item.index;
@@ -74,12 +176,74 @@
uni.navigateBack();
};
+ // 棰勮鐩稿叧
+ const formatQty = val => {
+ if (val === null || val === undefined || val === "") return "-";
+ return Number(val) || 0;
+ };
+
+ const getAvailable = item => {
+ const val = item.un_locked_quantity ?? item.unLockedQuantity;
+ return Number(val) || 0;
+ };
+
+ // 鍙敤鏁伴噺 鈮� 棰勮鍊� 涓� 棰勮鍊�>0
+ const isWarnRow = item => {
+ const warnNum = Number(item.warnNum) || 0;
+ if (warnNum <= 0) return false;
+ return getAvailable(item) <= warnNum;
+ };
+
+ const getWarnList = () => {
+ warnLoading.value = true;
+ warnStatus.value = "loading";
+ getStockWarnPage({
+ current: warnPage.current,
+ size: warnPage.size,
+ productName: warnSearch.productName,
+ })
+ .then(res => {
+ const records = res?.data?.records || [];
+ warnList.value =
+ warnPage.current === 1 ? records : [...warnList.value, ...records];
+ warnPage.total = res?.data?.total || 0;
+ warnStatus.value =
+ warnList.value.length >= warnPage.total ? "nomore" : "loadmore";
+ })
+ .catch(() => {
+ warnStatus.value = "loadmore";
+ })
+ .finally(() => {
+ warnLoading.value = false;
+ });
+ };
+
+ const handleWarnQuery = () => {
+ warnPage.current = 1;
+ warnList.value = [];
+ getWarnList();
+ };
+
+ const loadWarnMore = () => {
+ if (warnStatus.value === "nomore" || warnLoading.value) return;
+ warnPage.current++;
+ getWarnList();
+ };
+
+ const handleWarnToggle = () => {
+ if (warnOnly.value && !warnList.value.length) {
+ handleWarnQuery();
+ }
+ };
+
onMounted(() => {
fetchProducts();
});
</script>
<style scoped lang="scss">
+ @import "@/styles/procurement-common.scss";
+
.app-container {
display: flex;
flex-direction: column;
@@ -101,4 +265,70 @@
:deep(.up-tabs) {
background-color: #fff;
}
+
+ .warn-bar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ background: #fff;
+ padding: 16rpx 30rpx;
+
+ .warn-left {
+ display: flex;
+ align-items: center;
+ gap: 12rpx;
+ }
+
+ .warn-label {
+ font-size: 28rpx;
+ color: #333;
+ }
+ }
+
+ .warn-search {
+ display: flex;
+ align-items: center;
+ gap: 12rpx;
+ background: #fff;
+ padding: 16rpx 30rpx;
+
+ .search-input {
+ flex: 1;
+ background: #f5f5f5;
+ border-radius: 40rpx;
+ padding: 0 24rpx;
+ height: 72rpx;
+ display: flex;
+ align-items: center;
+ }
+ }
+
+ .warn-list {
+ flex: 1;
+ height: 0;
+ padding: 20rpx;
+ box-sizing: border-box;
+ }
+
+ .warn-item {
+ padding: 24rpx;
+
+ &.is-warn {
+ border: 2rpx solid #f56c6c;
+ }
+
+ .warn-icon {
+ background: linear-gradient(135deg, #f56c6c, #c0392b);
+ }
+
+ .warn-value {
+ color: #f56c6c;
+ font-weight: 600;
+ }
+ }
+
+ .no-data {
+ flex: 1;
+ padding-top: 150rpx;
+ }
</style>
--
Gitblit v1.9.3