工器具台账
This commit is contained in:
parent
30175452a6
commit
41a464a930
|
|
@ -57,6 +57,20 @@
|
|||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
//工器具台账
|
||||
{
|
||||
"path": "pages/toolsLedger/toolsLedger",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
//工器具台账-编码设备列表
|
||||
{
|
||||
"path": "pages/toolsLedger/toolsLedgerDetails",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
// 工器具退料
|
||||
{
|
||||
"path": "pages/toolsBack/toolsBack",
|
||||
|
|
@ -253,6 +267,12 @@
|
|||
"navigationBarTitleText": "OCR出库"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/toolsLease/rfidOut",
|
||||
"style": {
|
||||
"navigationBarTitleText": "rfid出库"
|
||||
}
|
||||
},
|
||||
// 4. 数量出库
|
||||
{
|
||||
"path": "pages/picking/outbound/num-outbound",
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ const isUsingList = ref([
|
|||
{ iconMark: 'toolsLease', iconName: '工器具领料' },
|
||||
{ iconMark: 'toolsOut', iconName: '工器具出库' },
|
||||
{ iconMark: 'toolsBack', iconName: '工器具退料' },
|
||||
{ iconMark: 'toolsLedger', iconName: '工器具台账' },
|
||||
])
|
||||
const percent = ref('')
|
||||
const unreadList = ref([])
|
||||
|
|
|
|||
|
|
@ -0,0 +1,253 @@
|
|||
<template>
|
||||
<uni-nav-bar dark :fixed="true" shadow background-color="#4AA4EA" status-bar title="设备库存">
|
||||
<template v-slot:left>
|
||||
<view style="font-size: 18px; display: flex; align-items: center" @click="back">
|
||||
<uni-icons type="left" size="20" color="#fff"></uni-icons>
|
||||
<text>返回</text>
|
||||
</view>
|
||||
</template>
|
||||
</uni-nav-bar>
|
||||
|
||||
<div class="content">
|
||||
<div class="search-box">
|
||||
<uni-easyinput
|
||||
v-model="searchText"
|
||||
placeholder="搜索物资名称、规格型号"
|
||||
prefixIcon="search"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
|
||||
<scroll-view scroll-y class="scroll-container">
|
||||
<div class="equipment-list">
|
||||
<div
|
||||
v-for="(category, categoryIndex) in filteredEquipmentCategories"
|
||||
:key="categoryIndex"
|
||||
class="equipment-category-section"
|
||||
>
|
||||
<!-- 设备类别标题 -->
|
||||
<div
|
||||
class="equipment-category"
|
||||
@click="toggleCategory(categoryIndex)"
|
||||
>
|
||||
<span>{{ category.name }}</span>
|
||||
<uni-icons
|
||||
:type="category.expanded ? 'top' : 'bottom'"
|
||||
size="16"
|
||||
color="#999"
|
||||
class="expand-icon"
|
||||
></uni-icons>
|
||||
</div>
|
||||
|
||||
<!-- 设备规格列表 -->
|
||||
<div v-if="category.expanded" class="equipment-specs">
|
||||
<div
|
||||
v-for="(spec, specIndex) in category.specs"
|
||||
:key="specIndex"
|
||||
class="equipment-item"
|
||||
@click="showDetail(category.name, spec)"
|
||||
>
|
||||
<div class="equipment-info">
|
||||
<div class="equipment-name">{{ category.name }}</div>
|
||||
<div class="equipment-spec">{{ spec.model }}</div>
|
||||
</div>
|
||||
<div class="equipment-quantity">在库数量:{{ spec.quantity }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</scroll-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref, computed } from 'vue'
|
||||
import { getToolsLedgerList } from "../../services/ledger";
|
||||
|
||||
const searchText = ref('')
|
||||
const back = () => {
|
||||
uni.navigateBack({
|
||||
delta: 1,
|
||||
})
|
||||
}
|
||||
|
||||
// 设备类别数据
|
||||
const equipmentCategories = ref([])
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
const filteredEquipmentCategories = computed(() => {
|
||||
if (!searchText.value) return equipmentCategories.value;
|
||||
|
||||
return equipmentCategories.value
|
||||
.filter(category => {
|
||||
const hasMatchingSpecs = category.specs.some(spec =>
|
||||
category.name.toLowerCase().includes(searchText.value.toLowerCase()) ||
|
||||
spec.model.toLowerCase().includes(searchText.value.toLowerCase())
|
||||
);
|
||||
return hasMatchingSpecs;
|
||||
})
|
||||
.map(category => ({
|
||||
...category,
|
||||
specs: category.specs.filter(spec =>
|
||||
category.name.toLowerCase().includes(searchText.value.toLowerCase()) ||
|
||||
spec.model.toLowerCase().includes(searchText.value.toLowerCase())
|
||||
)
|
||||
}));
|
||||
});
|
||||
|
||||
const toggleCategory = (categoryIndex) => {
|
||||
// 获取过滤后的类别名称
|
||||
const filteredCategoryName = filteredEquipmentCategories.value[categoryIndex].name;
|
||||
|
||||
// 在原始数组中查找对应类别的索引
|
||||
const originalIndex = equipmentCategories.value.findIndex(
|
||||
category => category.name === filteredCategoryName
|
||||
);
|
||||
|
||||
// 如果找到,则切换展开状态
|
||||
if (originalIndex !== -1) {
|
||||
equipmentCategories.value[originalIndex].expanded =
|
||||
!equipmentCategories.value[originalIndex].expanded;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取设备列表数据
|
||||
const getList = async () => {
|
||||
const params = {
|
||||
keyWord: ''
|
||||
}
|
||||
try {
|
||||
const res = await getToolsLedgerList(params)
|
||||
console.log('获取设备列表数据:', res)
|
||||
|
||||
if (res.code === 200) {
|
||||
// 转换API返回的数据结构为组件需要的格式
|
||||
const formattedData = res.data.map(item => {
|
||||
return {
|
||||
name: item.typeName,
|
||||
expanded: false, // 默认收起
|
||||
thirdTypeId: item.thirdTypeId,
|
||||
specs: item.modelList.map(model => {
|
||||
return {
|
||||
model: model.typeModelName,
|
||||
quantity: model.storeNum || 0,
|
||||
manageType: model.manageType,
|
||||
buyPrice: model.buyPrice
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
equipmentCategories.value = formattedData
|
||||
|
||||
// 如果只有一个类别,默认展开
|
||||
if (equipmentCategories.value.length === 1) {
|
||||
equipmentCategories.value[0].expanded = true
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取设备列表失败:', error)
|
||||
equipmentCategories.value = []
|
||||
}
|
||||
}
|
||||
|
||||
const showDetail = (categoryName, spec) => {
|
||||
console.log('查看详情:', categoryName, spec)
|
||||
uni.navigateTo({
|
||||
url: '/pages/toolsLedger/toolsLedgerDetails'
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content {
|
||||
padding: 10px;
|
||||
height: calc(100vh - 100px);
|
||||
|
||||
.search-box {
|
||||
padding: 10px;
|
||||
background: #fff;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.equipment-list {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
|
||||
.equipment-category-section {
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.equipment-category {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
padding: 15px;
|
||||
background: #fafafa;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
|
||||
&:active {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
|
||||
.expand-icon {
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
}
|
||||
|
||||
.equipment-specs {
|
||||
.equipment-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 15px;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
.equipment-info {
|
||||
.equipment-name {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
}
|
||||
.equipment-spec {
|
||||
color: #666;
|
||||
font-size: 12px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.equipment-quantity {
|
||||
color: #4AA4EA;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-container {
|
||||
height: calc(100vh - 150px);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,305 @@
|
|||
<template>
|
||||
<uni-nav-bar dark :fixed="true" shadow background-color="#4AA4EA" status-bar title="设备库存">
|
||||
<template v-slot:left>
|
||||
<view style="font-size: 18px; display: flex; align-items: center" @click="back">
|
||||
<uni-icons type="left" size="20" color="#fff"></uni-icons>
|
||||
<text>返回</text>
|
||||
</view>
|
||||
</template>
|
||||
</uni-nav-bar>
|
||||
|
||||
<div class="content">
|
||||
<!-- 搜索区域 -->
|
||||
<div class="search-section">
|
||||
<div class="search-row">
|
||||
<uni-easyinput
|
||||
v-model="searchCode"
|
||||
placeholder="输入设备编码"
|
||||
class="search-input"
|
||||
/>
|
||||
</div>
|
||||
<div class="search-row">
|
||||
<picker
|
||||
:value="selectedStatusIndex"
|
||||
:range="statusOptions"
|
||||
@change="onStatusChange"
|
||||
class="status-picker"
|
||||
>
|
||||
<view class="picker-display">
|
||||
{{ statusOptions[selectedStatusIndex] }}
|
||||
<uni-icons type="bottom" size="14" color="#999"></uni-icons>
|
||||
</view>
|
||||
</picker>
|
||||
<button class="search-btn" @click="handleSearch">查询</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 设备列表 -->
|
||||
<scroll-view scroll-y class="scroll-container">
|
||||
<div class="equipment-list">
|
||||
<div
|
||||
v-for="(item, index) in filteredEquipmentList"
|
||||
:key="index"
|
||||
class="equipment-item"
|
||||
@click="showDetail(item)"
|
||||
>
|
||||
<div class="equipment-info">
|
||||
<div class="equipment-code">{{ item.code }}</div>
|
||||
<div class="equipment-details">
|
||||
<div class="detail-row">
|
||||
<span class="label">物资名称:</span>
|
||||
<span class="value">{{ item.name }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="label">规格型号:</span>
|
||||
<span class="value">{{ item.spec }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-tag" :class="getStatusClass(item.status)">
|
||||
{{ item.status }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</scroll-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
const searchCode = ref('')
|
||||
const selectedStatusIndex = ref(0)
|
||||
|
||||
const statusOptions = [
|
||||
'选择到期监测状态',
|
||||
'正常',
|
||||
'三月内检测到期',
|
||||
'一月内检测到期',
|
||||
'已过期'
|
||||
]
|
||||
|
||||
const back = () => {
|
||||
uni.navigateBack({
|
||||
delta: 1,
|
||||
})
|
||||
}
|
||||
|
||||
// 设备列表数据
|
||||
const equipmentList = ref([
|
||||
{
|
||||
code: '2025-0001',
|
||||
name: '安全帽',
|
||||
spec: '白',
|
||||
status: '正常'
|
||||
},
|
||||
{
|
||||
code: '2025-0002',
|
||||
name: '安全帽',
|
||||
spec: '蓝',
|
||||
status: '三月内检测到期'
|
||||
},
|
||||
{
|
||||
code: '2025-0002',
|
||||
name: '安全帽',
|
||||
spec: '蓝',
|
||||
status: '一月内检测到期'
|
||||
},
|
||||
{
|
||||
code: '2025-0002',
|
||||
name: '安全帽',
|
||||
spec: '蓝',
|
||||
status: '已过期'
|
||||
}
|
||||
])
|
||||
|
||||
// 状态选择器变化
|
||||
const onStatusChange = (e) => {
|
||||
selectedStatusIndex.value = e.detail.value
|
||||
}
|
||||
|
||||
// 根据状态获取样式类
|
||||
const getStatusClass = (status) => {
|
||||
switch (status) {
|
||||
case '正常':
|
||||
return 'status-normal'
|
||||
case '三月内检测到期':
|
||||
return 'status-warning-3'
|
||||
case '一月内检测到期':
|
||||
return 'status-warning-1'
|
||||
case '已过期':
|
||||
return 'status-expired'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
// 过滤设备列表
|
||||
const filteredEquipmentList = computed(() => {
|
||||
let filtered = equipmentList.value
|
||||
|
||||
// 按设备编码过滤
|
||||
if (searchCode.value) {
|
||||
filtered = filtered.filter(item =>
|
||||
item.code.includes(searchCode.value)
|
||||
)
|
||||
}
|
||||
|
||||
// 按状态过滤
|
||||
if (selectedStatusIndex.value > 0) {
|
||||
const selectedStatus = statusOptions[selectedStatusIndex.value]
|
||||
filtered = filtered.filter(item => item.status === selectedStatus)
|
||||
}
|
||||
|
||||
return filtered
|
||||
})
|
||||
|
||||
const handleSearch = () => {
|
||||
// 触发搜索逻辑
|
||||
console.log('搜索设备编码:', searchCode.value)
|
||||
console.log('选择状态:', statusOptions[selectedStatusIndex.value])
|
||||
}
|
||||
|
||||
const showDetail = (item) => {
|
||||
uni.showModal({
|
||||
title: `设备详情`,
|
||||
content: `编码: ${item.code}\n名称: ${item.name}\n规格: ${item.spec}\n状态: ${item.status}`,
|
||||
showCancel: false
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content {
|
||||
padding: 10px;
|
||||
height: calc(100vh - 100px);
|
||||
|
||||
.search-section {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.search-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.status-picker {
|
||||
flex: 1;
|
||||
margin-right: 10px;
|
||||
|
||||
.picker-display {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
background: #4AA4EA;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 10px 20px;
|
||||
font-size: 14px;
|
||||
|
||||
&:active {
|
||||
background: #3a8bc8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.equipment-list {
|
||||
.equipment-item {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.equipment-info {
|
||||
flex: 1;
|
||||
|
||||
.equipment-code {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.equipment-details {
|
||||
.detail-row {
|
||||
display: flex;
|
||||
margin-bottom: 4px;
|
||||
font-size: 14px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #666;
|
||||
min-width: 70px;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
|
||||
&.status-normal {
|
||||
background: #e8f5e8;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
&.status-warning-3 {
|
||||
background: #fff7e6;
|
||||
color: #fa8c16;
|
||||
}
|
||||
|
||||
&.status-warning-1 {
|
||||
background: #fff2f0;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
&.status-expired {
|
||||
background: #fff2f0;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-container {
|
||||
height: calc(100vh - 200px);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import { http } from '@/utils/http'
|
||||
|
||||
/**
|
||||
* 工器具退料 ---- 列表查询
|
||||
*/
|
||||
export const getToolsLedgerList = (data) => {
|
||||
return http({
|
||||
method: 'GET',
|
||||
url: '/material/complex_query/getToolsLedgerList',
|
||||
data,
|
||||
})
|
||||
}
|
||||
Loading…
Reference in New Issue