Files

745 lines
18 KiB
Vue
Raw Permalink 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="form-item">
<view class="form-label">医院</view>
<view class="form-value">{{hospital}}</view>
</view>
<!-- 分院 -->
<view class="form-item">
<view class="form-label">分院</view>
<view class="form-value">{{sortHospital || '本院'}}</view>
</view>
<!-- 科室 -->
<view class="form-item">
<view class="form-label">科室</view>
<view class="searchable-picker-wrapper">
<view class="searchable-picker" @click="showDepartmentPicker = true">
<text v-if="selectedDepartment" class="picker-text">{{selectedDepartment}}</text>
<text v-else class="placeholder">请选择科室</text>
<text class="picker-icon"></text>
</view>
<!-- 科室搜索弹窗 -->
<view class="picker-modal" v-if="showDepartmentPicker" @click.self="showDepartmentPicker = false">
<view class="picker-modal-content">
<view class="modal-header">
<text class="modal-title">选择科室</text>
<text class="modal-close" @click="showDepartmentPicker = false"></text>
</view>
<view class="search-input-wrapper">
<input class="search-input" v-model="departmentSearchKeyword" placeholder="搜索科室" placeholder-class="search-placeholder" />
<text class="search-icon" v-if="!departmentSearchKeyword">🔍</text>
<text class="clear-icon" v-else @click="departmentSearchKeyword = ''"></text>
</view>
<scroll-view class="picker-list" scroll-y>
<view class="picker-item" v-for="(item, index) in filteredDepartmentList" :key="index" @click="selectDepartment(item)">
<text :class="{'item-active': item === selectedDepartment}">{{item}}</text>
</view>
<view v-if="filteredDepartmentList.length === 0" class="picker-empty">未找到匹配的科室</view>
</scroll-view>
</view>
</view>
</view>
</view>
<!-- 医废编码 -->
<view class="form-item">
<view class="form-label">医废编码</view>
<view class="form-value">{{medicalCode}}</view>
</view>
<!-- 类型 -->
<view class="form-item">
<view class="form-label">类型</view>
<picker mode="selector" :range="typeList" @change="onTypeChange">
<view class="form-value-picker">
<text v-if="selectedType">{{selectedType}}</text>
<text v-else class="placeholder">请选择类型</text>
<text class="picker-icon"></text>
</view>
</picker>
</view>
<!-- 重量 -->
<view class="form-item">
<view class="form-label">重量(kg)</view>
<input class="form-input" type="digit" v-model="weight" placeholder="请输入重量" placeholder-class="input-placeholder" />
</view>
<!-- 收集人员 -->
<view class="form-item">
<view class="form-label">收集人员</view>
<picker mode="selector" :range="collectorList" @change="onCollectorChange">
<view class="form-value-picker">
<text v-if="selectedCollector">{{selectedCollector}}</text>
<text v-else class="placeholder">请选择收集人员</text>
<text class="picker-icon"></text>
</view>
</picker>
</view>
<!-- 交接人员 -->
<view class="form-item">
<view class="form-label">交接人员</view>
<view class="searchable-picker-wrapper">
<view class="searchable-picker" @click="showHandoverPicker = true">
<text v-if="selectedHandover" class="picker-text">{{selectedHandover}}</text>
<text v-else class="placeholder">请选择交接人员</text>
<text class="picker-icon"></text>
</view>
<!-- 交接人员搜索弹窗 -->
<view class="picker-modal" v-if="showHandoverPicker" @click.self="showHandoverPicker = false">
<view class="picker-modal-content">
<view class="modal-header">
<text class="modal-title">选择交接人员</text>
<text class="modal-close" @click="showHandoverPicker = false"></text>
</view>
<view class="search-input-wrapper">
<input class="search-input" v-model="handoverSearchKeyword" placeholder="搜索交接人员" placeholder-class="search-placeholder" />
<text class="search-icon" v-if="!handoverSearchKeyword">🔍</text>
<text class="clear-icon" v-else @click="handoverSearchKeyword = ''"></text>
</view>
<scroll-view class="picker-list" scroll-y>
<view class="picker-item" v-for="(item, index) in filteredHandoverList" :key="index" @click="selectHandover(item)">
<text :class="{'item-active': item === selectedHandover}">{{item}}</text>
</view>
<view v-if="filteredHandoverList.length === 0" class="picker-empty">未找到匹配的交接人员</view>
</scroll-view>
</view>
</view>
</view>
</view>
<!-- 收集时间 -->
<view class="form-item">
<view class="form-label">收集时间</view>
<view class="datetime-picker">
<picker mode="date" :value="collectionDate" @change="onDateChange" :end="endDate">
<view class="picker-box">
<text class="picker-text">{{collectionDate || '选择日期'}}</text>
<text class="picker-arrow"></text>
</view>
</picker>
<view class="picker-separator">·</view>
<picker mode="time" :value="collectionTime" @change="onTimeChange">
<view class="picker-box">
<text class="picker-text">{{collectionTime}}</text>
<text class="picker-arrow"></text>
</view>
</picker>
</view>
</view>
<!-- 按钮组 -->
<view class="button-group">
<button class="cancel-btn" @click="cancelCollection">取消填报</button>
<button class="confirm-btn" @click="confirmCollection">确认填报</button>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
export default {
data() {
return {
hospital: '',
sortHospital: '',
department: '',
name: '',
duty: '',
medicalCode: '',
weight: '',
collectionDate: '',
collectionTime: '',
endDate: '',
selectedDepartment: '',
selectedType: '',
selectedCollector: '',
selectedHandover: '',
departmentList: [],
typeList: [],
collectorList: [],
handoverList: [],
// 搜索弹窗显示状态
showDepartmentPicker: false,
showHandoverPicker: false,
// 搜索关键词
departmentSearchKeyword: '',
handoverSearchKeyword: ''
}
},
mounted() {
// 获取全局变量
this.hospital = getApp().globalData.hospital
this.sortHospital = getApp().globalData.sortHospital
this.department = getApp().globalData.department
this.name = getApp().globalData.name
this.duty = getApp().globalData.duty
// 生成随机医废编码(31开头的20位数字)
this.generateMedicalCode()
// 设置默认收集时间
this.setDefaultTime()
// 获取下拉选项数据(预留接口)
this.getDepartmentOptions()
this.getTypeOptions()
this.getCollectorOptions()
this.getHandoverOptions()
},
computed: {
// 过滤后的科室列表
filteredDepartmentList() {
if (!this.departmentSearchKeyword) {
return this.departmentList;
}
return this.departmentList.filter(dept => {
return dept && dept.includes(this.departmentSearchKeyword);
});
},
// 过滤后的交接人员列表
filteredHandoverList() {
if (!this.handoverSearchKeyword) {
return this.handoverList;
}
return this.handoverList.filter(person => {
return person && person.includes(this.handoverSearchKeyword);
});
}
},
methods: {
// 生成随机医废编码
generateMedicalCode() {
let code = '31'
for (let i = 0; i < 18; i++) {
code += Math.floor(Math.random() * 10)
}
this.medicalCode = code
},
// 设置默认时间
setDefaultTime() {
const now = new Date()
// 日期
const year = now.getFullYear()
const month = String(now.getMonth() + 1).padStart(2, '0')
const day = String(now.getDate()).padStart(2, '0')
this.collectionDate = `${year}-${month}-${day}`
this.endDate = `${year}-${month}-${day}`
// 时间
const hours = String(now.getHours()).padStart(2, '0')
const minutes = String(now.getMinutes()).padStart(2, '0')
this.collectionTime = `${hours}:${minutes}`
},
// 获取科室选项(预留接口)
getDepartmentOptions() {
let that = this
uni.request({
url: 'https://mtx.mini.opmonitor.com/?c=app_api&a=getDepartmentOptions',
data: {hospital: that.hospital, sortHospital: that.sortHospital},
header: {
'Content-type': 'application/json'
},
success: function(res) {
const data = res.data.data || []
// 将对象数组转换为字符串数组,提取 dept_name 字段
that.departmentList = data.map(item => {
if (typeof item === 'object' && item !== null) {
return item.dept_name || item.name || item.department_name || item.text || JSON.stringify(item)
}
return item
})
},
fail: () => {
console.info('获取科室选项失败')
}
})
},
// 获取类型选项(预留接口)
getTypeOptions() {
let that = this
uni.request({
url: 'https://mtx.mini.opmonitor.com/?c=app_api&a=getTypeOptions',
data: {},
header: {
'Content-type': 'application/json'
},
success: function(res) {
const data = res.data.data || []
// 将对象数组转换为字符串数组,假设对象中有 name 或 type_name 字段
that.typeList = data.map(item => {
if (typeof item === 'object' && item !== null) {
return item.name || item.type_name || item.text || JSON.stringify(item)
}
return item
})
},
fail: () => {
console.info('获取类型选项失败')
}
})
},
// 获取收集人员选项(预留接口)
getCollectorOptions() {
let that = this
uni.request({
url: 'https://mtx.mini.opmonitor.com/?c=app_api&a=getCollectorOptions',
data: {hospital: that.hospital, sortHospital: that.sortHospital},
header: {
'Content-type': 'application/json'
},
success: function(res) {
const data = res.data.data || []
// 将对象数组转换为字符串数组,假设对象中有 name 字段
that.collectorList = data.map(item => {
if (typeof item === 'object' && item !== null) {
return item.name || item.text || JSON.stringify(item)
}
return item
})
},
fail: () => {
console.info('获取收集人员选项失败')
}
})
},
// 获取交接人员选项(预留接口)
getHandoverOptions() {
let that = this
uni.request({
url: 'https://mtx.mini.opmonitor.com/?c=app_api&a=getHandoverOptions',
data: {hospital: that.hospital, sortHospital: that.sortHospital},
header: {
'Content-type': 'application/json'
},
success: function(res) {
const data = res.data.data || []
// 将对象数组转换为字符串数组,假设对象中有 name 字段
that.handoverList = data.map(item => {
if (typeof item === 'object' && item !== null) {
return item.name || item.text || JSON.stringify(item)
}
return item
})
},
fail: () => {
console.info('获取交接人员选项失败')
}
})
},
// 选择科室
selectDepartment(item) {
this.selectedDepartment = item;
this.showDepartmentPicker = false;
this.departmentSearchKeyword = '';
},
// 选择交接人员
selectHandover(item) {
this.selectedHandover = item;
this.showHandoverPicker = false;
this.handoverSearchKeyword = '';
},
// 类型选择变化
onTypeChange(e) {
this.selectedType = this.typeList[e.detail.value]
},
// 收集人员选择变化
onCollectorChange(e) {
this.selectedCollector = this.collectorList[e.detail.value]
},
// 交接人员选择变化
onHandoverChange(e) {
this.selectedHandover = this.handoverList[e.detail.value]
},
// 日期选择变化
onDateChange(e) {
this.collectionDate = e.detail.value
},
// 时间选择变化
onTimeChange(e) {
this.collectionTime = e.detail.value
},
// 取消填报
cancelCollection() {
uni.navigateBack()
},
// 确认填报
confirmCollection() {
// 验证必填项
if (!this.selectedDepartment) {
uni.showToast({
title: '请选择科室',
icon: 'none'
})
return
}
if (!this.selectedType) {
uni.showToast({
title: '请选择类型',
icon: 'none'
})
return
}
if (!this.weight) {
uni.showToast({
title: '请输入重量',
icon: 'none'
})
return
}
if (!this.selectedCollector) {
uni.showToast({
title: '请选择收集人员',
icon: 'none'
})
return
}
if (!this.selectedHandover) {
uni.showToast({
title: '请选择交接人员',
icon: 'none'
})
return
}
// 提交数据(预留接口)
let that = this
uni.request({
url: 'https://mtx.mini.opmonitor.com/?c=app_api&a=submitCollectionData',
data: {
hospital: that.hospital,
sortHospital: that.sortHospital,
department: that.selectedDepartment,
medicalCode: that.medicalCode,
type: that.selectedType,
weight: that.weight,
collector: that.selectedCollector,
handover: that.selectedHandover,
collectionTime: `${that.collectionDate} ${that.collectionTime}`
},
header: {
'Content-type': 'application/json'
},
success: function(res) {
uni.showToast({
title: '填报成功',
icon: 'success'
})
setTimeout(() => {
uni.redirectTo({
url: '/pages/main/inventory'
})
}, 1500)
},
fail: () => {
uni.showToast({
title: '填报失败',
icon: 'none'
})
}
})
}
}
}
</script>
<style>
.page {
width: 100vw;
height: 100vh;
background: #f5f5f5;
}
.form-container {
padding: 20rpx;
}
.form-item {
background: #fff;
border-radius: 16rpx;
margin-bottom: 20rpx;
padding: 24rpx 30rpx;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
}
.form-label {
font-size: 28rpx;
color: #333;
font-weight: 600;
min-width: 160rpx;
}
.form-value {
flex: 1;
font-size: 28rpx;
color: #666;
text-align: right;
}
.form-value-picker {
flex: 1;
display: flex;
align-items: center;
justify-content: flex-end;
color: #666;
font-size: 28rpx;
}
.placeholder {
color: #ccc;
}
.picker-icon {
font-size: 40rpx;
color: #999;
margin-left: 10rpx;
}
.form-input {
flex: 1;
font-size: 28rpx;
color: #333;
text-align: right;
}
.input-placeholder {
color: #ccc;
}
/* 日期时间选择器 */
.datetime-picker {
flex: 1;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 20rpx;
}
.picker-box {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border: 1px solid #dee2e6;
border-radius: 12rpx;
padding: 16rpx 20rpx;
transition: all 0.3s ease;
}
.picker-box:active {
background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);
transform: scale(0.98);
}
.picker-icon {
font-size: 32rpx;
margin-right: 10rpx;
}
.picker-text {
flex: 1;
font-size: 28rpx;
color: #495057;
text-align: center;
}
.picker-arrow {
font-size: 36rpx;
color: #adb5bd;
margin-left: 8rpx;
}
.picker-separator {
font-size: 36rpx;
color: #adb5bd;
font-weight: 300;
}
.button-group {
display: flex;
gap: 20rpx;
margin-top: 40rpx;
}
.cancel-btn, .confirm-btn {
flex: 1;
height: 90rpx;
line-height: 90rpx;
border-radius: 45rpx;
font-size: 30rpx;
font-weight: 600;
border: none;
}
.cancel-btn {
background: #f0f0f0;
color: #666;
}
.confirm-btn {
background: linear-gradient(135deg, #4a90e2 0%, #357abd 100%);
color: #fff;
box-shadow: 0 6rpx 20rpx rgba(74, 144, 226, 0.35);
}
.cancel-btn::after, .confirm-btn::after {
border: none;
}
/* 可搜索选择器 */
.searchable-picker-wrapper {
flex: 1;
position: relative;
}
.searchable-picker {
display: flex;
align-items: center;
justify-content: flex-end;
color: #666;
font-size: 28rpx;
}
/* 搜索弹窗 */
.picker-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: flex-end;
justify-content: center;
z-index: 1000;
}
.picker-modal-content {
width: 100%;
background: #fff;
border-radius: 30rpx 30rpx 0 0;
max-height: 80vh;
display: flex;
flex-direction: column;
}
.modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx;
border-bottom: 1px solid #e8e8e8;
}
.modal-title {
font-size: 32rpx;
font-weight: 700;
color: #333;
}
.modal-close {
font-size: 40rpx;
color: #999;
padding: 10rpx;
}
/* 搜索输入框 */
.search-input-wrapper {
padding: 20rpx 30rpx;
background: #f8f9fa;
display: flex;
align-items: center;
border-bottom: 1px solid #e8e8e8;
}
.search-input {
flex: 1;
height: 60rpx;
font-size: 28rpx;
color: #333;
background: #fff;
border-radius: 30rpx;
padding: 0 50rpx 0 24rpx;
border: 1px solid #d9d9d9;
}
.search-placeholder {
color: #ccc;
}
.search-icon, .clear-icon {
position: absolute;
right: 50rpx;
font-size: 28rpx;
}
.search-icon {
color: #999;
}
.clear-icon {
color: #ccc;
padding: 10rpx;
}
/* 列表 */
.picker-list {
flex: 1;
max-height: 50vh;
}
.picker-item {
padding: 28rpx 30rpx;
border-bottom: 1px solid #f0f0f0;
font-size: 30rpx;
color: #333;
transition: all 0.2s;
}
.picker-item:active {
background: #f5f5f5;
}
.picker-item text {
display: block;
}
.item-active {
color: #2980b9;
font-weight: 600;
}
.picker-empty {
padding: 80rpx 0;
text-align: center;
font-size: 28rpx;
color: #999;
}
</style>