工器具台账

This commit is contained in:
hayu 2025-06-06 09:08:23 +08:00
parent 30175452a6
commit 41a464a930
5 changed files with 591 additions and 0 deletions

View File

@ -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",

View File

@ -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([])

View File

@ -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>

View File

@ -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>

12
src/services/ledger.js Normal file
View File

@ -0,0 +1,12 @@
import { http } from '@/utils/http'
/**
* 工器具退料 ---- 列表查询
*/
export const getToolsLedgerList = (data) => {
return http({
method: 'GET',
url: '/material/complex_query/getToolsLedgerList',
data,
})
}