| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="record-container"> |
| | | <view class="search-section"> |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <up-input |
| | | class="search-text" |
| | | placeholder="请è¾å
¥äº§å大类" |
| | | v-model="searchForm.productName" |
| | | @confirm="handleQuery" |
| | | clearable |
| | | /> |
| | | </view> |
| | | <view class="filter-button" @click="handleQuery"> |
| | | <up-icon name="search" size="24" color="#999"></up-icon> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <scroll-view scroll-y class="ledger-list" v-if="tableData.length > 0" @scrolltolower="loadMore"> |
| | | <view v-for="item in tableData" :key="item.id" class="ledger-item"> |
| | | <view class="item-header"> |
| | | <view class="item-left"> |
| | | <view class="document-icon"> |
| | | <up-icon name="file-text" size="16" color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-id">{{ item.productName }}</text> |
| | | </view> |
| | | </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">{{ item.batchNo }}</text> |
| | | </view> |
| | | |
| | | <view class="quantity-section"> |
| | | <view class="quantity-box qualified"> |
| | | <text class="q-label">åæ ¼åºå</text> |
| | | <text class="q-value">{{ item.qualifiedQuantity }}</text> |
| | | </view> |
| | | <view class="quantity-box unqualified"> |
| | | <text class="q-label">ä¸åæ ¼åºå</text> |
| | | <text class="q-value">{{ item.unQualifiedQuantity }}</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="quantity-section"> |
| | | <view class="quantity-box locked"> |
| | | <text class="q-label">åæ ¼å»ç»</text> |
| | | <text class="q-value">{{ item.qualifiedLockedQuantity }}</text> |
| | | </view> |
| | | <view class="quantity-box locked"> |
| | | <text class="q-label">ä¸åæ ¼å»ç»</text> |
| | | <text class="q-value">{{ item.unQualifiedLockedQuantity }}</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åºåé¢è¦</text> |
| | | <text class="detail-value">{{ item.warnNum }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">夿³¨</text> |
| | | <text class="detail-value">{{ item.remark || '-' }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ´æ°æ¶é´</text> |
| | | <text class="detail-value">{{ item.updateTime }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <up-loadmore :status="loadStatus" /> |
| | | </scroll-view> |
| | | <view v-else-if="!loading" class="no-data"> |
| | | <up-empty mode="data" text="ææ åºåæ°æ®"></up-empty> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from 'vue'; |
| | | import { getStockInventoryListPageCombined } from "@/api/inventoryManagement/stockInventory.js"; |
| | | |
| | | const props = defineProps({ |
| | | productId: { |
| | | type: Number, |
| | | required: true |
| | | } |
| | | }); |
| | | |
| | | const tableData = ref([]); |
| | | const loading = ref(false); |
| | | const loadStatus = ref('loadmore'); |
| | | const page = reactive({ current: 1, size: 10 }); |
| | | const total = ref(0); |
| | | const searchForm = reactive({ |
| | | productName: '', |
| | | topParentProductId: props.productId |
| | | }); |
| | | |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | tableData.value = []; |
| | | getList(); |
| | | }; |
| | | |
| | | const getList = () => { |
| | | if (loading.value) return; |
| | | loading.value = true; |
| | | loadStatus.value = 'loading'; |
| | | |
| | | getStockInventoryListPageCombined({ |
| | | ...searchForm, |
| | | current: page.current, |
| | | size: page.size |
| | | }).then(res => { |
| | | loading.value = false; |
| | | const records = res.data.records || []; |
| | | tableData.value = page.current === 1 ? records : [...tableData.value, ...records]; |
| | | total.value = res.data.total; |
| | | loadStatus.value = tableData.value.length >= total.value ? 'nomore' : 'loadmore'; |
| | | }).catch(() => { |
| | | loading.value = false; |
| | | loadStatus.value = 'loadmore'; |
| | | }); |
| | | }; |
| | | |
| | | const loadMore = () => { |
| | | if (loadStatus.value === 'loadmore') { |
| | | page.current++; |
| | | getList(); |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .record-container { |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | .search-section { |
| | | padding: 20rpx; |
| | | background-color: #ffffff; |
| | | position: sticky; |
| | | top: 0; |
| | | z-index: 10; |
| | | } |
| | | |
| | | .search-bar { |
| | | display: flex; |
| | | align-items: center; |
| | | background-color: #f2f2f2; |
| | | border-radius: 40rpx; |
| | | padding: 0 30rpx; |
| | | height: 80rpx; |
| | | } |
| | | |
| | | .search-input { |
| | | flex: 1; |
| | | } |
| | | |
| | | .search-text { |
| | | font-size: 28rpx; |
| | | } |
| | | |
| | | .filter-button { |
| | | padding-left: 20rpx; |
| | | } |
| | | |
| | | .ledger-list { |
| | | flex: 1; |
| | | padding: 20rpx; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .ledger-item { |
| | | background-color: #ffffff; |
| | | border-radius: 16rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .item-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20rpx; |
| | | } |
| | | |
| | | .item-left { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .document-icon { |
| | | width: 40rpx; |
| | | height: 40rpx; |
| | | background: linear-gradient(135deg, #2979ff, #1565c0); |
| | | border-radius: 8rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-right: 16rpx; |
| | | } |
| | | |
| | | .item-id { |
| | | font-size: 30rpx; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | } |
| | | |
| | | .item-details { |
| | | .detail-row { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-bottom: 16rpx; |
| | | font-size: 26rpx; |
| | | |
| | | .detail-label { |
| | | color: #909399; |
| | | } |
| | | |
| | | .detail-value { |
| | | color: #303133; |
| | | font-weight: 500; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .quantity-section { |
| | | display: flex; |
| | | gap: 20rpx; |
| | | margin: 20rpx 0; |
| | | |
| | | .quantity-box { |
| | | flex: 1; |
| | | padding: 16rpx; |
| | | border-radius: 8rpx; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | |
| | | .q-label { |
| | | font-size: 22rpx; |
| | | margin-bottom: 8rpx; |
| | | } |
| | | |
| | | .q-value { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | &.qualified { |
| | | background-color: #ecf5ff; |
| | | color: #409eff; |
| | | } |
| | | |
| | | &.unqualified { |
| | | background-color: #fef0f0; |
| | | color: #f56c6c; |
| | | } |
| | | |
| | | &.locked { |
| | | background-color: #f4f4f5; |
| | | color: #909399; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .no-data { |
| | | padding-top: 200rpx; |
| | | } |
| | | </style> |