Files
mwims-new-mini-program/pages/plugin/onekeyIn.vue
T

942 lines
20 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>
<scroll-view scroll-y class="page">
<cu-custom bgColor="bg-blue" :isBack="true">
<block slot="backText">返回</block>
<block slot="content">一键入库</block>
</cu-custom>
<view class="form-container">
<!-- 车辆选择 -->
<view class="vehicle-section">
<view class="section-title">车辆信息</view>
<view class="vehicle-picker">
<view class="picker-label">选择车辆</view>
<view class="picker-value" :class="{'has-value': selectedVehicle}" @click="showVehiclePicker">
{{selectedVehicle ? selectedVehicle.vehicleCode : '请选择车辆'}}
<text class="cuIcon-right"></text>
</view>
</view>
</view>
<!-- 查询按钮 -->
<view class="query-section">
<button class="query-btn" @click="queryData" :disabled="!selectedVehicle || isLoading">
<text class="cuIcon-search"></text>
<text>查询入库数据</text>
</button>
</view>
<!-- 查询结果 -->
<view class="result-section" v-if="hasResult">
<view class="section-title">入库数据统计</view>
<!-- 收集人员信息 -->
<view class="collector-info">
<text class="info-label">收集人员</text>
<text class="info-value">{{queryResult.collectorName}}</text>
</view>
<!-- 总计卡片 -->
<view class="total-card">
<view class="total-item">
<view class="total-value">{{queryResult.totalBagCount}}</view>
<view class="total-label">总袋数</view>
</view>
<view class="total-divider"></view>
<view class="total-item">
<view class="total-value">{{queryResult.totalWeight}}</view>
<view class="total-label">总重量(kg)</view>
</view>
</view>
<!-- 分类明细 -->
<view class="type-list">
<view class="type-header">分类明细</view>
<view class="type-item" v-for="(item, index) in queryResult.typeList" :key="index">
<view class="type-info">
<text class="type-tag" :class="'tag-' + item.typeCode">{{item.typeName}}</text>
</view>
<view class="type-stats">
<text class="stat-bags">{{item.bagCount}}</text>
<text class="stat-weight">{{item.weight}}kg</text>
</view>
</view>
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" v-if="!hasResult && !isLoading">
<text class="cuIcon-searchlist"></text>
<text class="empty-text">请选择车辆后查询入库数据</text>
</view>
</view>
<!-- 底部按钮 -->
<view class="footer">
<button class="submit-btn" :disabled="!hasResult || isSubmitting" @click="showConfirmModal">
一键入库
</button>
</view>
<view class="cu-tabbar-height"></view>
</scroll-view>
<!-- 入库确认弹窗 -->
<view class="modal" v-if="showModal" @click.self="closeModal">
<view class="modal-content">
<view class="modal-header">
<text class="modal-title">入库确认</text>
<text class="modal-close" @click="closeModal"></text>
</view>
<view class="modal-body">
<view class="confirm-section">
<view class="confirm-label">车辆编码</view>
<view class="confirm-value highlight">{{selectedVehicle ? selectedVehicle.vehicleCode : '-'}}</view>
</view>
<view class="confirm-section">
<view class="confirm-label">医废袋数量</view>
<view class="confirm-value">{{queryResult.totalBagCount}}</view>
</view>
<view class="confirm-section">
<view class="confirm-label">总重量</view>
<view class="confirm-value highlight">{{queryResult.totalWeight}}kg</view>
</view>
<view class="confirm-section type-detail">
<view class="confirm-label">类型明细</view>
<view class="type-list">
<view class="type-row" v-for="(item, index) in queryResult.typeList" :key="index">
<text class="type-name">{{item.typeName}}</text>
<text class="type-info">{{item.bagCount}} / {{item.weight}}kg</text>
</view>
</view>
</view>
</view>
<view class="modal-footer">
<button class="btn-cancel" @click="closeModal">取消</button>
<button class="btn-confirm" @click="confirmStorage">确认入库</button>
</view>
</view>
</view>
<!-- 加载中 -->
<view class="loading-mask" v-if="isLoading || isSubmitting">
<view class="loading-content">
<view class="cuIcon-loading2 loading-icon"></view>
<text class="loading-text">{{isSubmitting ? '提交中...' : '加载中...'}}</text>
</view>
</view>
<!-- 车辆选择弹窗 -->
<view class="picker-modal" v-if="showPickerModal" @click.self="closePickerModal">
<view class="picker-content">
<view class="picker-header">
<text class="picker-title">选择车辆</text>
<text class="picker-close" @click="closePickerModal"></text>
</view>
<view class="picker-search">
<input class="search-input" v-model="searchKeyword" placeholder="输入车辆编码搜索" @input="onSearch" />
<text class="cuIcon-search search-icon"></text>
</view>
<scroll-view scroll-y class="picker-list">
<view v-if="filteredVehicleList.length === 0" class="picker-empty">
<text>未找到匹配的车辆</text>
</view>
<view class="picker-item" :class="{'active': selectedVehicle && item.id === selectedVehicle.id}"
v-for="(item, index) in filteredVehicleList" :key="index" @click="selectVehicle(item)">
<text class="item-code">{{item.vehicleCode}}</text>
<text class="cuIcon-check" v-if="selectedVehicle && item.id === selectedVehicle.id"></text>
</view>
</scroll-view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
vehicleList: [],
filteredVehicleList: [],
selectedVehicle: null,
searchKeyword: '',
showPickerModal: false,
queryResult: {
totalBagCount: 0,
totalWeight: 0,
typeList: []
},
hasResult: false,
showModal: false,
isLoading: false,
isSubmitting: false,
typeMap: {
'感染性废物': { code: 'infectious', color: '#e54d42' },
'损伤性废物': { code: 'injury', color: '#f37b1d' },
'病理性废物': { code: 'pathology', color: '#8dc63f' },
'化学性废物': { code: 'chemical', color: '#6739b6' },
'药物性废物': { code: 'pharmaceutical', color: '#279cff' }
}
}
},
onLoad() {
this.loadVehicleList()
},
methods: {
// 加载车辆列表(预留接口)
loadVehicleList() {
// TODO: 替换为实际接口
// 接口示例: GET /api/vehicle/list
// 假数据(接口未提供前使用)
setTimeout(() => {
this.vehicleList = [
{ id: 1, vehicleCode: 'CL001 - 转运车A' },
{ id: 2, vehicleCode: 'CL002 - 转运车B' },
{ id: 3, vehicleCode: 'CL003 - 转运车C' },
{ id: 4, vehicleCode: 'CL004 - 转运车D' },
{ id: 5, vehicleCode: 'CL005 - 转运车E' },
{ id: 6, vehicleCode: 'CL006 - 转运车F' }
]
this.filteredVehicleList = [...this.vehicleList]
}, 300)
uni.request({
url: 'https://lekapi.opmonitor.com/?c=app_api&a=getVehicleList',
success: (res) => {
if (res.data.err_msg == 'success') {
this.vehicleList = res.data.data || []
this.filteredVehicleList = [...this.vehicleList]
}
}
})
},
// 显示车辆选择弹窗
showVehiclePicker() {
this.showPickerModal = true
this.searchKeyword = ''
this.filteredVehicleList = [...this.vehicleList]
},
// 关闭车辆选择弹窗
closePickerModal() {
this.showPickerModal = false
},
// 搜索车辆
onSearch() {
const keyword = this.searchKeyword.trim().toLowerCase()
if (!keyword) {
this.filteredVehicleList = [...this.vehicleList]
} else {
this.filteredVehicleList = this.vehicleList.filter(item =>
item.vehicleCode.toLowerCase().includes(keyword)
)
}
},
// 选择车辆
selectVehicle(item) {
this.selectedVehicle = item
this.hasResult = false
this.closePickerModal()
},
// 查询入库数据(预留接口)
queryData() {
if (!this.selectedVehicle) {
uni.showToast({
title: '请选择车辆',
icon: 'none'
})
return
}
this.isLoading = true
// TODO: 替换为实际接口
// 接口示例: GET /api/onekeyIn/query?vehicleId=xxx
const params = {
vehicleId: this.selectedVehicle.id,
vehicleCode: this.selectedVehicle.vehicleCode
}
// 模拟请求延迟,直接显示假数据
setTimeout(() => {
// 假数据
this.queryResult = {
collectorName: '李素',
totalBagCount: 156,
totalWeight: 485.5,
typeList: [
{ typeName: '感染性废物', typeCode: 'infectious', bagCount: 68, weight: 198.5 },
{ typeName: '损伤性废物', typeCode: 'injury', bagCount: 45, weight: 120.3 },
{ typeName: '病理性废物', typeCode: 'pathology', bagCount: 18, weight: 56.7 },
{ typeName: '化学性废物', typeCode: 'chemical', bagCount: 15, weight: 72.0 },
{ typeName: '药物性废物', typeCode: 'pharmaceutical', bagCount: 10, weight: 38.0 }
]
}
this.hasResult = true
this.isLoading = false
}, 800)
// 实际接口调用(替换上方假数据逻辑)
uni.request({
url: 'https://lekapi.opmonitor.com/?c=app_api&a=getOnekeyInData',
data: params,
success: (res) => {
console.log('查询结果:', res.data)
// TODO: 接口通了之后,删除上方假数据逻辑,取消注释下方代码
// if (res.data.err_msg == 'success') {
// this.queryResult = res.data.data
// this.hasResult = true
// } else {
// uni.showToast({
// title: '查询失败',
// icon: 'none'
// })
// }
},
fail: () => {
// 假数据(接口未提供前使用)
this.queryResult = {
totalBagCount: 156,
totalWeight: 485.5,
typeList: [
{ typeName: '感染性废物', typeCode: 'infectious', bagCount: 68, weight: 198.5 },
{ typeName: '损伤性废物', typeCode: 'injury', bagCount: 45, weight: 120.3 },
{ typeName: '病理性废物', typeCode: 'pathology', bagCount: 18, weight: 56.7 },
{ typeName: '化学性废物', typeCode: 'chemical', bagCount: 15, weight: 72.0 },
{ typeName: '药物性废物', typeCode: 'pharmaceutical', bagCount: 10, weight: 38.0 }
]
}
this.hasResult = true
},
complete: () => {
this.isLoading = false
}
})
},
// 显示确认弹窗
showConfirmModal() {
if (!this.hasResult) {
uni.showToast({
title: '请先查询数据',
icon: 'none'
})
return
}
this.showModal = true
},
// 关闭弹窗
closeModal() {
this.showModal = false
},
// 确认入库(预留接口)
confirmStorage() {
this.isSubmitting = true
// TODO: 替换为实际接口
// 接口示例: POST /api/onekeyIn/submit
const params = {
vehicleId: this.selectedVehicle.id,
vehicleCode: this.selectedVehicle.vehicleCode,
totalBagCount: this.queryResult.totalBagCount,
totalWeight: this.queryResult.totalWeight,
typeList: this.queryResult.typeList
}
uni.request({
url: 'https://lekapi.opmonitor.com/?c=app_api&a=onekeyInSubmit',
method: 'POST',
data: params,
success: (res) => {
console.log('入库结果:', res.data)
if (res.data.err_msg == 'success') {
uni.showToast({
title: '入库成功',
icon: 'success'
})
this.showModal = false
this.resetData()
setTimeout(() => {
uni.navigateBack()
}, 1500)
} else {
uni.showModal({
title: '提示',
content: '入库失败,请重试',
showCancel: false
})
}
},
fail: () => {
// 假数据(接口未提供前使用)
uni.showToast({
title: '入库成功',
icon: 'success'
})
this.showModal = false
this.resetData()
setTimeout(() => {
uni.navigateBack()
}, 1500)
},
complete: () => {
this.isSubmitting = false
}
})
},
// 重置数据
resetData() {
this.selectedVehicle = null
this.queryResult = {
totalBagCount: 0,
totalWeight: 0,
typeList: []
}
this.hasResult = false
}
}
}
</script>
<style>
.page {
width: 100vw;
height: 100vh;
background: #f5f5f5;
}
.form-container {
padding: 20rpx;
}
.vehicle-section {
background: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
}
.section-title {
font-size: 28rpx;
color: #333;
font-weight: 500;
margin-bottom: 24rpx;
}
.vehicle-picker {
display: flex;
align-items: center;
justify-content: space-between;
}
.picker-label {
font-size: 28rpx;
color: #666;
}
.picker-value {
display: flex;
align-items: center;
padding: 20rpx 30rpx;
background: #f5f5f5;
border-radius: 12rpx;
font-size: 28rpx;
color: #999;
min-width: 350rpx;
justify-content: space-between;
}
.picker-value.has-value {
background: #e6f7ff;
color: #1890ff;
}
.query-section {
margin-bottom: 20rpx;
}
.query-btn {
height: 88rpx;
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
color: #fff;
border: none;
border-radius: 44rpx;
display: flex;
align-items: center;
justify-content: center;
gap: 10rpx;
font-size: 30rpx;
box-shadow: 0 4rpx 16rpx rgba(24, 144, 255, 0.3);
}
.query-btn[disabled] {
background: #ccc;
box-shadow: none;
}
.query-btn::after {
border: none;
}
.result-section {
background: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
}
.total-card {
display: flex;
align-items: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 16rpx;
padding: 40rpx 30rpx;
margin-bottom: 30rpx;
}
.total-item {
flex: 1;
text-align: center;
}
.total-value {
font-size: 56rpx;
font-weight: bold;
color: #fff;
margin-bottom: 8rpx;
}
.total-label {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.8);
}
.total-divider {
width: 2rpx;
height: 80rpx;
background: rgba(255, 255, 255, 0.3);
}
.type-list {
margin-top: 20rpx;
}
.type-header {
font-size: 26rpx;
color: #666;
margin-bottom: 20rpx;
padding-bottom: 16rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.type-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 24rpx;
background: #f9f9f9;
border-radius: 12rpx;
margin-bottom: 16rpx;
}
.type-tag {
font-size: 26rpx;
padding: 6rpx 20rpx;
border-radius: 8rpx;
color: #fff;
}
.tag-infectious {
background: #e54d42;
}
.tag-injury {
background: #f37b1d;
}
.tag-pathology {
background: #8dc63f;
}
.tag-chemical {
background: #6739b6;
}
.tag-pharmaceutical {
background: #279cff;
}
.tag-other {
background: #8799a3;
}
.type-stats {
display: flex;
align-items: center;
gap: 20rpx;
}
.stat-bags {
font-size: 28rpx;
color: #1890ff;
font-weight: 500;
}
.stat-weight {
font-size: 28rpx;
color: #52c41a;
font-weight: 500;
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
color: #999;
}
.empty-state text:first-child {
font-size: 80rpx;
margin-bottom: 20rpx;
}
.empty-text {
font-size: 28rpx;
}
.footer {
padding: 20rpx 40rpx 40rpx;
}
.submit-btn {
height: 96rpx;
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
color: #fff;
border: none;
border-radius: 48rpx;
font-size: 32rpx;
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 24rpx rgba(24, 144, 255, 0.3);
}
.submit-btn[disabled] {
background: #ccc;
box-shadow: none;
}
.submit-btn::after {
border: none;
}
/* 弹窗样式 */
.modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 999;
}
.modal-content {
width: 80%;
max-width: 600rpx;
background: #fff;
border-radius: 24rpx;
overflow: hidden;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.modal-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.modal-close {
font-size: 36rpx;
color: #999;
padding: 10rpx;
}
.modal-body {
padding: 30rpx;
}
.confirm-section {
display: flex;
align-items: center;
margin-bottom: 20rpx;
}
.confirm-section.type-detail {
flex-direction: column;
align-items: flex-start;
margin-top: 30rpx;
padding-top: 20rpx;
border-top: 2rpx solid #f0f0f0;
}
.confirm-label {
font-size: 28rpx;
color: #666;
width: 160rpx;
}
.confirm-value {
font-size: 28rpx;
color: #333;
font-weight: 500;
}
.confirm-value.highlight {
color: #1890ff;
font-size: 32rpx;
}
.type-list {
width: 100%;
margin-top: 16rpx;
}
.type-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16rpx 20rpx;
background: #f9f9f9;
border-radius: 12rpx;
margin-bottom: 12rpx;
}
.type-row .type-name {
font-size: 28rpx;
color: #333;
}
.type-row .type-info {
font-size: 26rpx;
color: #666;
}
.modal-footer {
display: flex;
padding: 20rpx 30rpx 30rpx;
gap: 20rpx;
}
.btn-cancel,
.btn-confirm {
flex: 1;
height: 80rpx;
border-radius: 40rpx;
font-size: 28rpx;
border: none;
}
.btn-cancel {
background: #f5f5f5;
color: #666;
}
.btn-confirm {
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
color: #fff;
}
.btn-cancel::after,
.btn-confirm::after {
border: none;
}
/* 加载中 */
.loading-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.loading-content {
display: flex;
flex-direction: column;
align-items: center;
background: #fff;
padding: 40rpx 60rpx;
border-radius: 16rpx;
}
.loading-icon {
font-size: 60rpx;
color: #1890ff;
animation: rotate 1s linear infinite;
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.loading-text {
font-size: 28rpx;
color: #333;
margin-top: 20rpx;
}
.collector-info {
display: flex;
align-items: center;
padding: 20rpx 24rpx;
background: #f0f7ff;
border-radius: 12rpx;
margin-bottom: 20rpx;
}
.collector-info .info-label {
font-size: 28rpx;
color: #666;
}
.collector-info .info-value {
font-size: 28rpx;
color: #1890ff;
font-weight: 500;
}
/* 车辆选择弹窗 */
.picker-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 999;
}
.picker-content {
width: 85%;
max-width: 650rpx;
max-height: 70vh;
background: #fff;
border-radius: 24rpx;
overflow: hidden;
display: flex;
flex-direction: column;
}
.picker-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.picker-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.picker-close {
font-size: 36rpx;
color: #999;
padding: 10rpx;
}
.picker-search {
position: relative;
padding: 20rpx 30rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.picker-search .search-input {
width: 100%;
height: 72rpx;
background: #f5f5f5;
border-radius: 36rpx;
padding: 0 70rpx 0 30rpx;
font-size: 28rpx;
}
.picker-search .search-icon {
position: absolute;
right: 50rpx;
top: 50%;
transform: translateY(-50%);
font-size: 32rpx;
color: #999;
}
.picker-list {
flex: 1;
max-height: 400rpx;
padding: 20rpx;
}
.picker-empty {
display: flex;
align-items: center;
justify-content: center;
padding: 60rpx 0;
color: #999;
font-size: 28rpx;
}
.picker-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 30rpx;
background: #f9f9f9;
border-radius: 12rpx;
margin-bottom: 16rpx;
transition: all 0.2s;
}
.picker-item:active {
background: #e6f7ff;
}
.picker-item.active {
background: #e6f7ff;
border: 2rpx solid #1890ff;
}
.picker-item .item-code {
font-size: 28rpx;
color: #333;
}
.picker-item .cuIcon-check {
font-size: 32rpx;
color: #1890ff;
}
</style>