库存盘点和项目的初版

This commit is contained in:
砂糖
2025-07-26 14:06:06 +08:00
parent 56409a9340
commit bf05e84eee
18 changed files with 3112 additions and 4 deletions

385
pages/workbench/wms/wms.vue Normal file
View File

@@ -0,0 +1,385 @@
<template>
<view class="container">
<!-- 筛选表单 一行展示 -->
<view class="filter-form-row">
<!-- 型号筛选 -->
<view :class="['filter-item', activeFilter === 'model' ? 'filter-item-expand' : 'filter-item-collapse']">
<template v-if="activeFilter === 'model'">
<view class="input-clear-wrap">
<input
class="filter-input"
v-model="queryParams.model"
placeholder="型号"
@blur="onFilterBlur('model')"
:style="{ color: queryParams.model ? '#2979ff' : '#999' }"
/>
<view v-if="queryParams.model" class="clear-icon" @click="clearFilter('model')">
<uni-icons type="closeempty" color="#bbb" size="18" />
</view>
</view>
</template>
<template v-else>
<view class="filter-icon" @click="toggleFilter('model')">
<uni-icons type="cart" :color="queryParams.model ? '#2979ff' : '#bbb'" size="24" />
</view>
</template>
</view>
<!-- 物料名称筛选 -->
<view :class="['filter-item', activeFilter === 'name' ? 'filter-item-expand' : 'filter-item-collapse']">
<template v-if="activeFilter === 'name'">
<view class="input-clear-wrap">
<input
class="filter-input"
v-model="queryParams.name"
placeholder="物料名称"
@blur="onFilterBlur('name')"
:style="{ color: queryParams.name ? '#2979ff' : '#999' }"
/>
<view v-if="queryParams.name" class="clear-icon" @click="clearFilter('name')">
<uni-icons type="closeempty" color="#bbb" size="18" />
</view>
</view>
</template>
<template v-else>
<view class="filter-icon" @click="toggleFilter('name')">
<uni-icons type="search" :color="queryParams.name ? '#2979ff' : '#bbb'" size="24" />
</view>
</template>
</view>
<!-- 品牌筛选 -->
<view :class="['filter-item', activeFilter === 'brand' ? 'filter-item-expand' : 'filter-item-collapse']">
<template v-if="activeFilter === 'brand'">
<view class="input-clear-wrap">
<input
class="filter-input"
v-model="queryParams.brand"
placeholder="品牌"
@blur="onFilterBlur('brand')"
:style="{ color: queryParams.brand ? '#2979ff' : '#999' }"
/>
<view v-if="queryParams.brand" class="clear-icon" @click="clearFilter('brand')">
<uni-icons type="closeempty" color="#bbb" size="18" />
</view>
</view>
</template>
<template v-else>
<view class="filter-icon" @click="toggleFilter('brand')">
<uni-icons type="circle" :color="queryParams.brand ? '#2979ff' : '#bbb'" size="24" />
</view>
</template>
</view>
<button class="filter-btn" @click="resetQuery">重置</button>
</view>
<!-- 列表展示下拉加载更多 -->
<scroll-view class="list" scroll-y @scrolltolower="loadMore">
<view v-for="(item, index) in oaWarehouseList" :key="item.id" class="list-item">
<view class="row">
<text class="index">{{ index + 1 }}</text>
<text class="name">{{ item.name }}</text>
<text class="model">{{ item.model }}</text>
<text class="brand">{{ item.brand }}</text>
</view>
<view class="row">
<text class="price">单价{{ item.price }}</text>
<text :class="['inventory', item.inventory < item.threshold ? 'low' : '']">
库存{{ item.inventory }}
<text v-if="item.taskInventory !== null">({{ item.taskInventory }})</text>
</text>
<text class="unit">{{ item.unit }}</text>
<text class="specifications">{{ item.specifications }}</text>
</view>
</view>
<view v-if="oaWarehouseList.length === 0" class="empty">暂无数据</view>
<view v-if="loadingMore" class="loading-more">加载中...</view>
<view v-if="!hasMore && oaWarehouseList.length > 0" class="no-more">没有更多了</view>
</scroll-view>
</view>
</template>
<script>
import { listStock } from '@/api/oa/wms/stock.js'
import uniIcons from '@/uni_modules/uni-icons/components/uni-icons/uni-icons.vue'
import uniEasyinput from '@/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue'
export default {
components: {
uniIcons
},
data() {
return {
oaWarehouseList: [],
queryParams: {
pageNum: 1,
pageSize: 20,
model: '',
name: '',
brand: ''
},
total: 0,
loadingMore: false,
hasMore: true,
activeFilter: 'model' // 当前展开的筛选项
}
},
onLoad() {
this.getList()
},
methods: {
getList(isLoadMore = false) {
if (!isLoadMore) {
this.queryParams.pageNum = 1
this.oaWarehouseList = []
this.hasMore = true
}
listStock(this.queryParams).then(res => {
const rows = res.rows || []
this.total = res.total || 0
if (isLoadMore) {
this.oaWarehouseList = this.oaWarehouseList.concat(rows)
} else {
this.oaWarehouseList = rows
}
// 判断是否还有更多
this.hasMore = this.oaWarehouseList.length < this.total
this.loadingMore = false
})
},
handleQuery() {
this.getList(false)
},
toggleFilter(type) {
this.activeFilter = type
},
onFilterBlur(type) {
// 输入框失焦后自动筛选
this.handleQuery()
},
clearFilter(type) {
this.queryParams[type] = ''
this.handleQuery()
},
resetQuery() {
this.queryParams = {
pageNum: 1,
pageSize: 10,
model: '',
name: '',
brand: ''
}
this.getList(false)
},
loadMore() {
if (!this.hasMore || this.loadingMore) return
this.loadingMore = true
this.queryParams.pageNum++
this.getList(true)
}
}
}
</script>
<style scoped>
.input-clear-wrap {
position: relative;
width: 100%;
display: flex;
align-items: center;
}
.clear-icon {
position: absolute;
right: 10rpx;
top: 50%;
transform: translateY(-50%);
z-index: 2;
background: #fff;
border-radius: 50%;
padding: 4rpx;
display: flex;
align-items: center;
justify-content: center;
}
.container {
padding: 20rpx;
}
.filter-form-row {
display: flex;
align-items: center;
margin-bottom: 20rpx;
background: #fff;
border-radius: 8rpx;
box-shadow: 0 2rpx 8rpx #eee;
padding: 8rpx 16rpx;
gap: 12rpx;
}
.filter-item {
display: flex;
align-items: center;
justify-content: center;
height: 56rpx;
transition: all 0.2s;
}
.filter-item-expand {
flex: 1 1 0%;
margin-right: 16rpx;
min-width: 120rpx;
}
.filter-item-collapse {
flex: 0 0 48rpx;
margin-right: 8rpx;
min-width: 48rpx;
max-width: 48rpx;
}
.filter-input {
width: 100%;
padding: 8rpx 12rpx;
border: 1rpx solid #eee;
border-radius: 6rpx;
background: #f8f8f8;
font-size: 28rpx;
transition: color 0.2s;
}
.filter-input {
width: 100%;
padding: 8rpx 12rpx;
border: 1rpx solid #eee;
border-radius: 6rpx;
background: #f8f8f8;
font-size: 28rpx;
transition: color 0.2s;
}
.filter-btn {
margin-right: 12rpx;
padding: 8rpx 24rpx;
background: #2979ff;
color: #fff;
border-radius: 6rpx;
font-size: 28rpx;
border: none;
}
.list {
background: #fff;
border-radius: 8rpx;
box-shadow: 0 2rpx 8rpx #eee;
height: 90vh;
overflow: hidden;
}
.list-item {
margin: 16rpx 16rpx 0 16rpx;
padding: 24rpx 20rpx 16rpx 20rpx;
background: #fff;
border-radius: 12rpx;
box-shadow: 0 2rpx 12rpx #e5e5e5;
display: flex;
flex-direction: column;
position: relative;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 8rpx;
}
.index {
width: 48rpx;
color: #bbb;
font-size: 28rpx;
font-weight: bold;
margin-right: 16rpx;
}
.name {
font-size: 32rpx;
font-weight: 600;
color: #2979ff;
margin-right: 24rpx;
max-width: 220rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.model {
font-size: 28rpx;
color: #333;
margin-right: 20rpx;
max-width: 160rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.brand {
font-size: 28rpx;
color: #666;
margin-right: 20rpx;
max-width: 120rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.price {
font-size: 28rpx;
color: #faad14;
margin-right: 20rpx;
}
.inventory {
font-size: 28rpx;
font-weight: 600;
margin-right: 20rpx;
color: #52c41a;
}
.inventory.low {
color: #ff4d4f !important;
background: #fff2f0;
border-radius: 6rpx;
padding: 0 8rpx;
}
.unit {
font-size: 26rpx;
color: #999;
margin-right: 16rpx;
}
.specifications {
font-size: 26rpx;
color: #999;
margin-right: 16rpx;
max-width: 120rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.empty {
text-align: center;
color: #999;
padding: 40rpx 0;
}
.loading-more {
text-align: center;
color: #2979ff;
padding: 20rpx 0;
}
.no-more {
text-align: center;
color: #bbb;
padding: 20rpx 0;
}
</style>