Files
im-uniapp/pages/workbench/wms/wms.vue
2025-07-28 10:15:30 +08:00

386 lines
8.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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: 'name' // 当前展开的筛选项
}
},
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>