| | |
| | | /> |
| | | </view> |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">执行任务人员</view> |
| | | <view class="staff-list"> |
| | | <view class="staff-item" v-for="(staff, index) in selectedStaff" :key="staff.userId"> |
| | | <view class="staff-info"> |
| | | <text class="staff-name">{{ staff.nickName }}</text> |
| | | <text class="staff-role">({{ getUserTypeName(staff.type) || '未知职位' }})</text> |
| | | </view> |
| | | <uni-icons |
| | | type="closeempty" |
| | | size="20" |
| | | color="#ff4d4f" |
| | | @click="removeStaff(index)" |
| | | ></uni-icons> |
| | | </view> |
| | | <view class="add-staff" @click="showStaffSelector"> |
| | | <uni-icons type="plusempty" size="20" color="#007AFF"></uni-icons> |
| | | <text>添加人员</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <StaffSelector |
| | | v-model="selectedStaff" |
| | | label="执行任务人员" |
| | | :required="false" |
| | | :auto-add-current-user="false" |
| | | :current-user-removable="true" |
| | | @change="onStaffChange" |
| | | /> |
| | | |
| | | <view class="form-section-title">患者信息</view> |
| | | <view class="form-item"> |
| | |
| | | ></map-selector> |
| | | </view> |
| | | </uni-popup> |
| | | |
| | | <!-- 人员选择器弹窗 --> |
| | | <uni-popup ref="staffPopup" type="bottom" :mask-click="false"> |
| | | <view class="staff-popup-container"> |
| | | <view class="popup-header"> |
| | | <view class="popup-title">选择执行人员</view> |
| | | <view class="close-btn" @click="closeStaffSelector"> |
| | | <uni-icons type="closeempty" size="20" color="#999"></uni-icons> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="search-bar"> |
| | | <input |
| | | class="search-input" |
| | | placeholder="搜索姓名或电话" |
| | | v-model="staffSearchKeyword" |
| | | @input="onStaffSearch" |
| | | /> |
| | | </view> |
| | | |
| | | <view class="filter-tabs"> |
| | | <view |
| | | class="filter-tab" |
| | | :class="{ active: staffFilterType === 'driver' }" |
| | | @click="filterStaff('driver')" |
| | | > |
| | | 司机 |
| | | </view> |
| | | <view |
| | | class="filter-tab" |
| | | :class="{ active: staffFilterType === 'doctor' }" |
| | | @click="filterStaff('doctor')" |
| | | > |
| | | 医生 |
| | | </view> |
| | | <view |
| | | class="filter-tab" |
| | | :class="{ active: staffFilterType === 'nurse' }" |
| | | @click="filterStaff('nurse')" |
| | | > |
| | | 护士 |
| | | </view> |
| | | </view> |
| | | |
| | | <scroll-view class="staff-list-scroll" scroll-y="true"> |
| | | <view |
| | | class="staff-list-item" |
| | | v-for="staff in filteredStaffList" |
| | | :key="staff.userId" |
| | | @click="toggleStaffSelection(staff)" |
| | | > |
| | | <view class="staff-item-info"> |
| | | <text class="staff-item-name">{{ staff.nickName }}</text> |
| | | <text class="staff-item-dept">{{ staff.deptName }}</text> |
| | | </view> |
| | | <view class="staff-item-check"> |
| | | <uni-icons |
| | | v-if="isStaffSelected(staff.userId)" |
| | | type="checkmarkempty" |
| | | size="24" |
| | | color="#007AFF" |
| | | ></uni-icons> |
| | | </view> |
| | | </view> |
| | | <view v-if="filteredStaffList.length === 0" class="empty-tip"> |
| | | 暂无人员数据 |
| | | </view> |
| | | </scroll-view> |
| | | |
| | | <view class="popup-footer"> |
| | | <button class="confirm-btn" @click="confirmStaffSelection">确定(已选{{ selectedStaff.length }})</button> |
| | | </view> |
| | | </view> |
| | | </uni-popup> |
| | | </scroll-view> |
| | | </template> |
| | | |
| | |
| | | import uniDatetimePicker from '@/uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue' |
| | | import uniPopup from '@/uni_modules/uni-popup/components/uni-popup/uni-popup.vue' |
| | | import { getTask, updateTask } from "@/api/task" |
| | | import { listBranchUsers } from "@/api/system/user" |
| | | import { baiduDistanceByAddress } from "@/api/map" |
| | | import { calculateTransferPrice } from "@/api/price" |
| | | import MapSelector from './components/map-selector.vue' |
| | |
| | | import HospitalSelector from './components/HospitalSelector.vue' |
| | | import DiseaseSelector from './components/DiseaseSelector.vue' |
| | | import DepartureSelector from './components/DepartureSelector.vue' |
| | | import StaffSelector from './components/StaffSelector.vue' |
| | | import distanceCalculator from '@/mixins/distanceCalculator.js' |
| | | |
| | | export default { |
| | |
| | | OrganizationSelector, |
| | | HospitalSelector, |
| | | DiseaseSelector, |
| | | DepartureSelector |
| | | DepartureSelector, |
| | | StaffSelector |
| | | }, |
| | | mixins: [distanceCalculator], |
| | | data() { |
| | |
| | | departureLatitude: null, |
| | | selectedDiseases: [], // 已选择的病情列表(确保初始化为空数组) |
| | | selectedStaff: [], // 已选择的人员列表(确保初始化为空数组) |
| | | allStaffList: [], // 所有人员列表 |
| | | filteredStaffList: [], // 过滤后的人员列表 |
| | | staffSearchKeyword: '', // 人员搜索关键词 |
| | | staffFilterType: 'driver', // 人员筛选类型 |
| | | taskForm: { |
| | | transferTime: '', |
| | | patient: { |
| | |
| | | if (options.id) { |
| | | this.taskId = options.id |
| | | this.loadTaskDetail() |
| | | this.loadDeptStaff() // 加载人员列表 |
| | | } else { |
| | | this.$modal.showToast('任务ID不能为空') |
| | | setTimeout(() => { |
| | |
| | | this.taskForm.hospitalOut.id = info.hospitalOutId || null |
| | | this.taskForm.hospitalOut.name = info.hospitalOutName || '' |
| | | this.taskForm.hospitalOut.department = info.hospitalOutDepartment || '' |
| | | this.taskForm.hospitalOut.departmentId = info.hospitalOutDepartmentId || null |
| | | this.taskForm.hospitalOut.bedNumber = info.hospitalOutBedNumber || '' |
| | | this.taskForm.hospitalOut.address = info.hospitalOutAddress || '' |
| | | console.log('转出医院科室ID:', info.hospitalOutDepartmentId) |
| | | |
| | | // 加载转出医院GPS坐标(不显示,但保存在数据中) |
| | | if (info.hospitalOutLongitude && info.hospitalOutLatitude) { |
| | |
| | | this.taskForm.hospitalIn.id = info.hospitalInId || null |
| | | this.taskForm.hospitalIn.name = info.hospitalInName || '' |
| | | this.taskForm.hospitalIn.department = info.hospitalInDepartment || '' |
| | | this.taskForm.hospitalIn.departmentId = info.hospitalInDepartmentId || null |
| | | this.taskForm.hospitalIn.bedNumber = info.hospitalInBedNumber || '' |
| | | this.taskForm.hospitalIn.address = info.hospitalInAddress || '' |
| | | console.log('转入医院科室ID:', info.hospitalInDepartmentId) |
| | | |
| | | // 加载转入医院GPS坐标(不显示,但保存在数据中) |
| | | if (info.hospitalInLongitude && info.hospitalInLatitude) { |
| | |
| | | // 组件已经通过 v-model 更新了 selectedDiseases |
| | | }, |
| | | |
| | | // 加载当前用户所在分公司的所有人员 |
| | | loadDeptStaff() { |
| | | console.log('开始加载人员列表') |
| | | |
| | | listBranchUsers().then(response => { |
| | | console.log('人员列表API响应:', response) |
| | | const userList = response.data || [] |
| | | console.log('解析出的用户列表:', userList, '数量:', userList.length) |
| | | |
| | | this.allStaffList = userList.map(user => ({ |
| | | userId: user.userId, |
| | | nickName: user.nickName, |
| | | phonenumber: user.phonenumber, |
| | | deptName: user.dept?.deptName || '', |
| | | postName: user.posts && user.posts.length > 0 ? user.posts[0].postName : '', |
| | | roleName: user.roles && user.roles.length > 0 ? user.roles[0].roleName : '', |
| | | type: this.getUserType(user) |
| | | })) |
| | | |
| | | console.log('处理后的人员列表:', this.allStaffList, '数量:', this.allStaffList.length) |
| | | |
| | | this.filterStaffList() |
| | | }).catch(error => { |
| | | console.error('加载人员列表失败:', error) |
| | | this.$modal.showToast('加载人员列表失败') |
| | | }) |
| | | }, |
| | | |
| | | // 根据用户的岗位或角色判断类型 |
| | | getUserType(user) { |
| | | const postName = user.posts && user.posts.length > 0 ? user.posts[0].postName : '' |
| | | const roleName = user.roles && user.roles.length > 0 ? user.roles[0].roleName : '' |
| | | const deptName = user.dept?.deptName || '' |
| | | |
| | | if (postName.includes('司机') || roleName.includes('司机') || deptName.includes('车队') || deptName.includes('司机')) { |
| | | return 'driver' |
| | | } |
| | | if (postName.includes('护士') || roleName.includes('护士') || deptName.includes('护士')) { |
| | | return 'nurse' |
| | | } |
| | | if (postName.includes('医生') || roleName.includes('医生') || deptName.includes('医生')) { |
| | | return 'doctor' |
| | | } |
| | | if (deptName.includes('医护')) { |
| | | return 'doctor' |
| | | } |
| | | |
| | | return 'driver' |
| | | }, |
| | | |
| | | getUserTypeName(staffType) { |
| | | switch(staffType) { |
| | | case 'nurse': |
| | | return '护士' |
| | | case 'doctor': |
| | | return '医生' |
| | | case 'driver': |
| | | return '司机' |
| | | default: |
| | | return '司机' |
| | | } |
| | | }, |
| | | |
| | | // 显示人员选择弹窗 |
| | | showStaffSelector() { |
| | | this.$refs.staffPopup.open() |
| | | this.filterStaffList() |
| | | }, |
| | | |
| | | // 关闭人员选择弹窗 |
| | | closeStaffSelector() { |
| | | this.$refs.staffPopup.close() |
| | | this.staffSearchKeyword = '' |
| | | this.staffFilterType = 'driver' |
| | | }, |
| | | |
| | | // 人员搜索 |
| | | onStaffSearch(e) { |
| | | this.staffSearchKeyword = e.detail.value |
| | | this.filterStaffList() |
| | | }, |
| | | |
| | | // 筛选人员类型 |
| | | filterStaff(type) { |
| | | this.staffFilterType = type |
| | | this.filterStaffList() |
| | | }, |
| | | |
| | | // 过滤人员列表 |
| | | filterStaffList() { |
| | | console.log('开始过滤人员列表,原始数量:', this.allStaffList.length) |
| | | let list = [...this.allStaffList] |
| | | |
| | | // 按类型过滤 |
| | | if (this.staffFilterType === 'driver') { |
| | | list = list.filter(staff => staff.type === 'driver') |
| | | } else if (this.staffFilterType === 'doctor') { |
| | | list = list.filter(staff => staff.type === 'doctor') |
| | | } else if (this.staffFilterType === 'nurse') { |
| | | list = list.filter(staff => staff.type === 'nurse') |
| | | } |
| | | |
| | | console.log('按类型过滤后:', this.staffFilterType, '数量:', list.length) |
| | | |
| | | // 按关键词搜索 |
| | | if (this.staffSearchKeyword && this.staffSearchKeyword.trim() !== '') { |
| | | const keyword = this.staffSearchKeyword.trim().toLowerCase() |
| | | list = list.filter(staff => { |
| | | return staff.nickName.toLowerCase().includes(keyword) || |
| | | (staff.phonenumber && staff.phonenumber.includes(keyword)) |
| | | }) |
| | | } |
| | | |
| | | console.log('按关键词过滤后,数量:', list.length) |
| | | |
| | | this.filteredStaffList = list |
| | | }, |
| | | |
| | | // 切换人员选中状态 |
| | | toggleStaffSelection(staff) { |
| | | const index = this.selectedStaff.findIndex(s => s.userId === staff.userId) |
| | | |
| | | if (index > -1) { |
| | | // 已选中,移除 |
| | | this.selectedStaff.splice(index, 1) |
| | | } else { |
| | | // 未选中,添加 |
| | | this.selectedStaff.push(staff) |
| | | } |
| | | }, |
| | | |
| | | // 判断人员是否已选中 |
| | | isStaffSelected(userId) { |
| | | return this.selectedStaff.some(staff => staff.userId === userId) |
| | | }, |
| | | |
| | | // 确认人员选择 |
| | | confirmStaffSelection() { |
| | | if (this.selectedStaff.length === 0) { |
| | | this.$modal.showToast('请至少选择一名人员') |
| | | return |
| | | } |
| | | this.closeStaffSelector() |
| | | }, |
| | | |
| | | // 移除人员 |
| | | removeStaff(index) { |
| | | this.selectedStaff.splice(index, 1) |
| | | // 人员变化 |
| | | onStaffChange(staff) { |
| | | console.log('选中人员变化:', staff) |
| | | // 组件已经通过 v-model 更新了 selectedStaff |
| | | }, |
| | | |
| | | // 解析病情信息(从字符串解析出ICD-10疾病列表)- 修复:与创建界面保持一致 |
| | |
| | | this.$modal.confirm('确定要保存修改吗?').then(() => { |
| | | this.loading = true |
| | | const submitData = this.buildSubmitData() |
| | | |
| | | console.log('提交数据 - 转出医院科室ID:', submitData.hospitalOut.departmentId) |
| | | console.log('提交数据 - 转入医院科室ID:', submitData.hospitalIn.departmentId) |
| | | |
| | | updateTask(submitData).then(response => { |
| | | this.loading = false |
| | |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .staff-popup-container { |
| | | height: 80vh; |
| | | background-color: white; |
| | | border-top-left-radius: 20rpx; |
| | | border-top-right-radius: 20rpx; |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | .popup-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 20rpx 30rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | .popup-title { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | |
| | | .close-btn { |
| | | width: 50rpx; |
| | | height: 50rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | } |
| | | |
| | | .search-bar { |
| | | padding: 20rpx 30rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | .search-input { |
| | | height: 70rpx; |
| | | padding: 0 20rpx; |
| | | background-color: #f5f5f5; |
| | | border-radius: 10rpx; |
| | | font-size: 28rpx; |
| | | } |
| | | } |
| | | |
| | | .filter-tabs { |
| | | display: flex; |
| | | padding: 20rpx 30rpx; |
| | | gap: 20rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | .filter-tab { |
| | | flex: 1; |
| | | height: 60rpx; |
| | | line-height: 60rpx; |
| | | text-align: center; |
| | | background-color: #f5f5f5; |
| | | border-radius: 10rpx; |
| | | font-size: 28rpx; |
| | | color: #666; |
| | | |
| | | &.active { |
| | | background-color: #007AFF; |
| | | color: white; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .staff-list-scroll { |
| | | flex: 1; |
| | | padding: 20rpx 30rpx; |
| | | |
| | | .staff-list-item { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 20rpx; |
| | | margin-bottom: 15rpx; |
| | | background-color: #f8f8f8; |
| | | border-radius: 10rpx; |
| | | |
| | | .staff-item-info { |
| | | flex: 1; |
| | | |
| | | .staff-item-name { |
| | | display: block; |
| | | font-size: 30rpx; |
| | | color: #333; |
| | | margin-bottom: 8rpx; |
| | | } |
| | | |
| | | .staff-item-dept { |
| | | display: block; |
| | | font-size: 24rpx; |
| | | color: #999; |
| | | } |
| | | } |
| | | |
| | | .staff-item-check { |
| | | width: 50rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | } |
| | | |
| | | .empty-tip { |
| | | text-align: center; |
| | | padding: 100rpx 0; |
| | | color: #999; |
| | | font-size: 28rpx; |
| | | } |
| | | } |
| | | |
| | | .popup-footer { |
| | | padding: 20rpx 30rpx; |
| | | border-top: 1rpx solid #f0f0f0; |
| | | |
| | | .confirm-btn { |
| | | width: 100%; |
| | | height: 80rpx; |
| | | background-color: #007AFF; |
| | | color: white; |
| | | border-radius: 10rpx; |
| | | font-size: 32rpx; |
| | | } |
| | | } |
| | | } |