<template>
|
<scroll-view class="create-emergency-task-container" scroll-y="true">
|
<view class="form-header">
|
<view class="back-btn" @click="goBack">
|
<uni-icons type="arrowleft" size="20"></uni-icons>
|
</view>
|
<view class="title">创建急救转运任务</view>
|
</view>
|
|
<view class="form-section">
|
<view class="form-item">
|
<view class="form-label">任务车辆</view>
|
<picker mode="selector" :range="vehicles" @change="onVehicleChange">
|
<view class="form-input picker-input">
|
{{ selectedVehicle || '请选择任务车辆' }}
|
<uni-icons type="arrowright" size="16" color="#999"></uni-icons>
|
</view>
|
</picker>
|
</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">({{ staff.postName || staff.roleName || '未知职位' }})</text>
|
</view>
|
<uni-icons
|
v-if="index > 0"
|
type="closeempty"
|
size="20"
|
color="#ff4d4f"
|
@click="removeStaff(index)"
|
></uni-icons>
|
<uni-icons
|
v-else
|
type="checkmarkempty"
|
size="20"
|
color="#007AFF"
|
></uni-icons>
|
</view>
|
<view class="add-staff" @click="showStaffSelector">
|
<uni-icons type="plusempty" size="20" color="#007AFF"></uni-icons>
|
<text>添加人员</text>
|
</view>
|
</view>
|
</view>
|
|
<view class="form-item">
|
<view class="form-label">归属机构</view>
|
<picker mode="selector" :range="organizations" @change="onOrganizationChange">
|
<view class="form-input picker-input">
|
{{ selectedOrganization || '请选择归属机构' }}
|
<uni-icons type="arrowright" size="16" color="#999"></uni-icons>
|
</view>
|
</picker>
|
</view>
|
|
<view class="form-item">
|
<view class="form-label">任务类型</view>
|
<picker mode="selector" :range="emergencyTaskTypes" @change="onEmergencyTaskTypeChange">
|
<view class="form-input picker-input">
|
{{ selectedEmergencyTaskType || '请选择任务类型' }}
|
<uni-icons type="arrowright" size="16" color="#999"></uni-icons>
|
</view>
|
</picker>
|
</view>
|
|
<view class="form-item">
|
<view class="form-label">转运时间</view>
|
<uni-datetime-picker
|
v-model="taskForm.transferTime"
|
type="datetime"
|
:placeholder="'请选择转运时间'"
|
class="form-input"
|
/>
|
</view>
|
|
<view class="form-section-title">患者信息</view>
|
<view class="form-item">
|
<view class="form-label">联系人</view>
|
<input
|
class="form-input"
|
placeholder="请输入联系人"
|
v-model="taskForm.patient.contact"
|
/>
|
</view>
|
|
<view class="form-item">
|
<view class="form-label">联系电话</view>
|
<input
|
class="form-input"
|
type="number"
|
placeholder="请输入联系电话"
|
v-model="taskForm.patient.phone"
|
/>
|
</view>
|
|
<view class="form-item">
|
<view class="form-label">患者姓名</view>
|
<input
|
class="form-input"
|
placeholder="请输入患者姓名"
|
v-model="taskForm.patient.name"
|
/>
|
</view>
|
|
<view class="form-item">
|
<view class="form-label">性别</view>
|
<view class="radio-group">
|
<label class="radio-item">
|
<radio value="male" :checked="taskForm.patient.gender === 'male'" @click="taskForm.patient.gender = 'male'" />
|
<text>男</text>
|
</label>
|
<label class="radio-item">
|
<radio value="female" :checked="taskForm.patient.gender === 'female'" @click="taskForm.patient.gender = 'female'" />
|
<text>女</text>
|
</label>
|
</view>
|
</view>
|
|
<view class="form-item">
|
<view class="form-label">患者身份证</view>
|
<input
|
class="form-input"
|
type="idcard"
|
placeholder="请输入患者身份证号"
|
v-model="taskForm.patient.idCard"
|
/>
|
</view>
|
|
<view class="form-item">
|
<view class="form-label">病情</view>
|
<view class="disease-container">
|
<view class="disease-tags" v-if="selectedDiseases.length > 0">
|
<view
|
class="disease-tag"
|
v-for="(disease, index) in selectedDiseases"
|
:key="index"
|
>
|
<text class="disease-name">{{ disease.icdName }}</text>
|
<uni-icons
|
type="closeempty"
|
size="16"
|
color="#fff"
|
@click="removeDisease(index)"
|
></uni-icons>
|
</view>
|
</view>
|
<view class="add-disease-btn" @click="showDiseaseSelector">
|
<uni-icons type="plusempty" size="20" color="#007AFF"></uni-icons>
|
<text>添加病情</text>
|
</view>
|
<textarea
|
class="form-textarea"
|
placeholder="其他病情描述(选填)"
|
v-model="taskForm.patient.condition"
|
style="margin-top: 20rpx;"
|
/>
|
</view>
|
</view>
|
|
<view class="form-section-title">转出医院信息</view>
|
<view class="form-item">
|
<view class="form-label">医院名称</view>
|
<view class="hospital-search-container">
|
<input
|
class="form-input"
|
placeholder="请输入医院名称或地址搜索"
|
v-model="hospitalOutSearchKeyword"
|
@input="onHospitalOutSearch"
|
@focus="onHospitalOutFocus"
|
/>
|
<view class="search-results" v-if="showHospitalOutResults && hospitalOutResults.length > 0">
|
<view
|
class="search-result-item"
|
v-for="hospital in hospitalOutResults"
|
:key="hospital.hospId"
|
@click="selectHospitalOut(hospital)"
|
>
|
<view class="hospital-name">{{ hospital.hospName }}</view>
|
<view class="hospital-address">{{ hospital.hospAddress }}</view>
|
</view>
|
</view>
|
</view>
|
</view>
|
|
<view class="form-item">
|
<view class="form-label">科室</view>
|
<picker mode="selector" :range="departmentOptions" range-key="dictLabel" @change="onHospitalOutDepartmentChange">
|
<view class="form-input picker-input">
|
{{ taskForm.hospitalOut.department || '请选择科室' }}
|
<uni-icons type="arrowright" size="16" color="#999"></uni-icons>
|
</view>
|
</picker>
|
</view>
|
|
<view class="form-item">
|
<view class="form-label">床号</view>
|
<input
|
class="form-input"
|
placeholder="请输入床号"
|
v-model="taskForm.hospitalOut.bedNumber"
|
/>
|
</view>
|
|
<view class="form-item">
|
<view class="form-label">转出地址</view>
|
<view class="form-input picker-input disabled">
|
{{ taskForm.hospitalOut.address || '选择医院后自动填充' }}
|
</view>
|
</view>
|
|
<view class="form-section-title">转入医院信息</view>
|
<view class="form-item">
|
<view class="form-label">医院名称</view>
|
<view class="hospital-search-container">
|
<input
|
class="form-input"
|
placeholder="请输入医院名称或地址搜索"
|
v-model="hospitalInSearchKeyword"
|
@input="onHospitalInSearch"
|
@focus="onHospitalInFocus"
|
/>
|
<view class="search-results" v-if="showHospitalInResults && hospitalInResults.length > 0">
|
<view
|
class="search-result-item"
|
v-for="hospital in hospitalInResults"
|
:key="hospital.hospId"
|
@click="selectHospitalIn(hospital)"
|
>
|
<view class="hospital-name">{{ hospital.hospName }}</view>
|
<view class="hospital-address">{{ hospital.hospAddress }}</view>
|
</view>
|
</view>
|
</view>
|
</view>
|
|
<view class="form-item">
|
<view class="form-label">科室</view>
|
<picker mode="selector" :range="departmentOptions" range-key="dictLabel" @change="onHospitalInDepartmentChange">
|
<view class="form-input picker-input">
|
{{ taskForm.hospitalIn.department || '请选择科室' }}
|
<uni-icons type="arrowright" size="16" color="#999"></uni-icons>
|
</view>
|
</picker>
|
</view>
|
|
<view class="form-item">
|
<view class="form-label">床号</view>
|
<input
|
class="form-input"
|
placeholder="请输入床号"
|
v-model="taskForm.hospitalIn.bedNumber"
|
/>
|
</view>
|
|
<view class="form-item">
|
<view class="form-label">转入地址</view>
|
<view class="form-input picker-input disabled">
|
{{ taskForm.hospitalIn.address || '选择医院后自动填充' }}
|
</view>
|
</view>
|
|
<view class="form-item">
|
<view class="form-label">转运公里数</view>
|
<input
|
class="form-input"
|
type="digit"
|
placeholder="请输入转运公里数"
|
v-model="taskForm.transferDistance"
|
/>
|
</view>
|
|
<view class="form-item">
|
<view class="form-label">成交价</view>
|
<input
|
class="form-input"
|
type="digit"
|
placeholder="请输入成交价"
|
v-model="taskForm.price"
|
/>
|
</view>
|
|
<view class="form-actions">
|
<button class="submit-btn" @click="submitTask" :disabled="loading">
|
{{ loading ? '保存中...' : '保存' }}
|
</button>
|
</view>
|
</view>
|
|
<!-- 人员选择弹窗 -->
|
<uni-popup ref="staffPopup" type="bottom" :safe-area="true">
|
<view class="staff-selector-popup">
|
<view class="popup-header">
|
<view class="popup-title">选择执行人员</view>
|
<view class="popup-close" @click="closeStaffSelector">
|
<uni-icons type="closeempty" size="24" color="#333"></uni-icons>
|
</view>
|
</view>
|
|
<view class="search-box">
|
<uni-icons type="search" size="18" color="#999"></uni-icons>
|
<input
|
class="search-input"
|
placeholder="搜索姓名、手机号"
|
v-model="staffSearchKeyword"
|
@input="onStaffSearch"
|
/>
|
</view>
|
|
<view class="staff-filter">
|
<view
|
class="filter-item"
|
:class="{ active: staffFilterType === 'all' }"
|
@click="filterStaff('all')"
|
>全部</view>
|
<view
|
class="filter-item"
|
:class="{ active: staffFilterType === 'driver' }"
|
@click="filterStaff('driver')"
|
>司机</view>
|
<view
|
class="filter-item"
|
:class="{ active: staffFilterType === 'nurse' }"
|
@click="filterStaff('nurse')"
|
>护士</view>
|
</view>
|
|
<scroll-view class="staff-list-popup" scroll-y="true">
|
<view
|
class="staff-item-popup"
|
v-for="staff in filteredStaffList"
|
:key="staff.userId"
|
@click="toggleStaffSelection(staff)"
|
>
|
<view class="staff-info">
|
<view class="staff-name-row">
|
<text class="staff-name">{{ staff.nickName }}</text>
|
<text class="staff-phone">{{ staff.phonenumber }}</text>
|
</view>
|
<view class="staff-detail-row">
|
<text class="staff-dept">{{ staff.deptName }}</text>
|
<text class="staff-post">{{ staff.postName || staff.roleName || '未知职位' }}</text>
|
</view>
|
</view>
|
<uni-icons
|
v-if="isStaffSelected(staff.userId)"
|
type="checkmarkempty"
|
size="24"
|
color="#007AFF"
|
></uni-icons>
|
<view v-else class="checkbox-empty"></view>
|
</view>
|
|
<view class="no-data" v-if="filteredStaffList.length === 0">
|
<uni-icons type="info" size="40" color="#ccc"></uni-icons>
|
<text>暂无人员数据</text>
|
</view>
|
</scroll-view>
|
|
<view class="popup-footer">
|
<button class="cancel-btn" @click="closeStaffSelector">取消</button>
|
<button class="confirm-btn" @click="confirmStaffSelection">确定(已选{{ selectedStaff.length }})</button>
|
</view>
|
</view>
|
</uni-popup>
|
|
<!-- 病情选择弹窗 -->
|
<uni-popup ref="diseasePopup" type="bottom" :safe-area="true">
|
<view class="disease-selector-popup">
|
<view class="popup-header">
|
<view class="popup-title">选择病情(ICD-10)</view>
|
<view class="popup-close" @click="closeDiseaseSelector">
|
<uni-icons type="closeempty" size="24" color="#333"></uni-icons>
|
</view>
|
</view>
|
|
<view class="search-box">
|
<uni-icons type="search" size="18" color="#999"></uni-icons>
|
<input
|
class="search-input"
|
placeholder="搜索疾病名称、编码或助记码"
|
v-model="diseaseSearchKeyword"
|
@input="onDiseaseSearch"
|
/>
|
</view>
|
|
<scroll-view class="disease-list-popup" scroll-y="true">
|
<view
|
class="disease-item-popup"
|
v-for="disease in diseaseSearchResults"
|
:key="disease.id"
|
@click="toggleDiseaseSelection(disease)"
|
>
|
<view class="disease-info">
|
<view class="disease-name-row">
|
<text class="disease-name">{{ disease.icdName }}</text>
|
<text class="disease-code">[{{ disease.icdCode }}]</text>
|
</view>
|
<view class="disease-detail-row" v-if="disease.sm">
|
<text class="disease-desc">{{ disease.sm }}</text>
|
</view>
|
</view>
|
<uni-icons
|
v-if="isDiseaseSelected(disease.id)"
|
type="checkmarkempty"
|
size="24"
|
color="#007AFF"
|
></uni-icons>
|
<view v-else class="checkbox-empty"></view>
|
</view>
|
|
<view class="no-data" v-if="diseaseSearchResults.length === 0">
|
<uni-icons type="info" size="40" color="#ccc"></uni-icons>
|
<text>{{ diseaseSearchKeyword ? '未找到相关疾病' : '暂无病情数据' }}</text>
|
</view>
|
</scroll-view>
|
|
<view class="popup-footer">
|
<button class="cancel-btn" @click="closeDiseaseSelector">取消</button>
|
<button class="confirm-btn" @click="confirmDiseaseSelection">确定(已选{{ tempSelectedDiseases.length }})</button>
|
</view>
|
</view>
|
</uni-popup>
|
</scroll-view>
|
</template>
|
|
<script>
|
import { mapState } from 'vuex'
|
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 { addTask } from "@/api/task"
|
import { listAvailableVehicles, getUserBoundVehicle } from "@/api/vehicle"
|
import { calculateDistance } from "@/api/map"
|
import { searchHospitals } from "@/api/hospital"
|
import { listUser } from "@/api/system/user"
|
import { searchIcd10 } from "@/api/icd10"
|
import { getUserProfile } from "@/api/system/user"
|
import { getDicts } from "@/api/dict"
|
import MapSelector from '@/components/map-selector.vue'
|
|
export default {
|
components: {
|
uniDatetimePicker,
|
uniPopup,
|
MapSelector
|
},
|
data() {
|
return {
|
selectedVehicle: '',
|
selectedVehicleId: null,
|
selectedOrganization: '',
|
selectedEmergencyTaskType: '',
|
mapSelectorType: '',
|
// 医院搜索相关
|
hospitalOutSearchKeyword: '',
|
hospitalOutResults: [],
|
showHospitalOutResults: false,
|
hospitalInSearchKeyword: '',
|
hospitalInResults: [],
|
showHospitalInResults: false,
|
searchTimer: null,
|
defaultHospitals: [], // 默认的100条医院数据
|
// 人员选择相关
|
selectedStaff: [], // 已选择的人员列表
|
allStaffList: [], // 所有人员列表
|
filteredStaffList: [], // 过滤后的人员列表
|
staffSearchKeyword: '', // 人员搜索关键词
|
staffFilterType: 'all', // 人员筛选类型:all/driver/nurse
|
// 病情选择相关
|
selectedDiseases: [], // 已选择的病情列表
|
tempSelectedDiseases: [], // 临时选择的病情列表(用于弹窗)
|
diseaseSearchKeyword: '', // 病情搜索关键词
|
diseaseSearchResults: [], // 病情搜索结果
|
diseaseSearchTimer: null, // 病情搜索防抖定时器
|
taskForm: {
|
transferTime: '',
|
patient: {
|
contact: '',
|
phone: '',
|
name: '',
|
gender: 'male',
|
idCard: '',
|
condition: ''
|
},
|
hospitalOut: {
|
name: '',
|
department: '',
|
bedNumber: '',
|
address: ''
|
},
|
hospitalIn: {
|
name: '',
|
department: '',
|
bedNumber: '',
|
address: ''
|
},
|
transferDistance: '',
|
price: ''
|
},
|
vehicles: [],
|
vehicleOptions: [],
|
organizations: ['广州分公司', '深圳分公司', '珠海分公司', '佛山分公司'],
|
emergencyTaskTypes: ['急救转运', '航空转运'],
|
departmentOptions: [], // 科室字典数据
|
loading: false,
|
addressCoordinates: {
|
hospitalOutAddress: null,
|
hospitalInAddress: null
|
}
|
}
|
},
|
computed: {
|
...mapState({
|
currentUser: state => ({
|
userId: state.user.userId,
|
name: state.user.name || '张三',
|
nickName: state.user.nickName || state.user.name || '张三',
|
position: '司机',
|
deptId: state.user.deptId || 100,
|
phonenumber: state.user.phonenumber || '',
|
branchCompanyId: state.user.branchCompanyId,
|
branchCompanyName: state.user.branchCompanyName
|
})
|
})
|
},
|
onLoad(options) {
|
// 先加载车辆列表,然后加载绑定车辆信息
|
this.getAvailableVehicles().then(() => {
|
this.getUserBoundVehicleInfo()
|
})
|
this.initSelectedStaff()
|
this.loadDeptStaff()
|
// 设置默认归属机构
|
if (this.currentUser.branchCompanyName) {
|
this.selectedOrganization = this.currentUser.branchCompanyName
|
}
|
// 加载默认医院列表(前100条)
|
this.loadDefaultHospitals()
|
// 加载科室字典数据
|
this.loadDepartments()
|
},
|
methods: {
|
// 获取用户绑定的车辆信息
|
getUserBoundVehicleInfo() {
|
getUserProfile().then(response => {
|
const userInfo = response.data || response
|
if (userInfo.boundVehicle) {
|
const boundVehicleNo = userInfo.boundVehicle.vehicleNumber
|
const boundVehicleId = userInfo.boundVehicle.vehicleId
|
|
// 在车辆列表中查找绑定的车辆
|
const vehicleIndex = this.vehicleOptions.findIndex(v =>
|
v.id === boundVehicleId || v.name === boundVehicleNo
|
)
|
|
if (vehicleIndex !== -1) {
|
// 设置默认选中的车辆
|
this.selectedVehicle = this.vehicleOptions[vehicleIndex].name
|
this.selectedVehicleId = this.vehicleOptions[vehicleIndex].id
|
}
|
}
|
}).catch(error => {
|
console.error('获取用户绑定车辆信息失败:', error)
|
})
|
},
|
|
getAvailableVehicles() {
|
const deptId = this.currentUser.deptId
|
return listAvailableVehicles(deptId, 'EMERGENCY').then(response => {
|
const vehicleList = response.data || response.rows || []
|
this.vehicleOptions = vehicleList.map(vehicle => ({
|
id: vehicle.vehicleId,
|
name: vehicle.vehicleNo,
|
type: vehicle.vehicleType,
|
status: vehicle.status
|
}))
|
this.vehicles = this.vehicleOptions.map(v => v.name)
|
}).catch(() => {
|
this.vehicles = []
|
})
|
},
|
|
onVehicleChange(e) {
|
const index = e.detail.value
|
this.selectedVehicle = this.vehicles[index]
|
this.selectedVehicleId = this.vehicleOptions[index]?.id
|
},
|
|
onOrganizationChange(e) {
|
this.selectedOrganization = this.organizations[e.detail.value]
|
},
|
|
onEmergencyTaskTypeChange(e) {
|
this.selectedEmergencyTaskType = this.emergencyTaskTypes[e.detail.value]
|
},
|
|
// 加载科室字典数据
|
loadDepartments() {
|
getDicts('hospital_department').then(response => {
|
this.departmentOptions = response.data || []
|
}).catch(error => {
|
console.error('加载科室字典失败:', error)
|
this.departmentOptions = []
|
})
|
},
|
|
// 转出医院科室选择
|
onHospitalOutDepartmentChange(e) {
|
const index = e.detail.value
|
this.taskForm.hospitalOut.department = this.departmentOptions[index].dictValue
|
},
|
|
// 转入医院科室选择
|
onHospitalInDepartmentChange(e) {
|
const index = e.detail.value
|
this.taskForm.hospitalIn.department = this.departmentOptions[index].dictValue
|
},
|
|
// 加载默认医院列表(前100条)
|
loadDefaultHospitals() {
|
// 传入空字符串或特殊标识获取前100条
|
searchHospitals('').then(response => {
|
this.defaultHospitals = response.data || []
|
// 同时初始化两个搜索结果为默认数据
|
this.hospitalOutResults = [...this.defaultHospitals]
|
this.hospitalInResults = [...this.defaultHospitals]
|
}).catch(error => {
|
console.error('加载默认医院列表失败:', error)
|
this.defaultHospitals = []
|
})
|
},
|
|
// 转出医院输入框获得焦点
|
onHospitalOutFocus() {
|
// 如果没有搜索关键词,显示默认的100条数据
|
if (!this.hospitalOutSearchKeyword || this.hospitalOutSearchKeyword.trim() === '') {
|
this.hospitalOutResults = [...this.defaultHospitals]
|
}
|
this.showHospitalOutResults = true
|
},
|
|
// 转出医院搜索
|
onHospitalOutSearch(e) {
|
const keyword = e.detail.value
|
this.hospitalOutSearchKeyword = keyword
|
|
// 防抖处理
|
if (this.searchTimer) {
|
clearTimeout(this.searchTimer)
|
}
|
|
// 如果关键词为空,显示默认100条
|
if (!keyword || keyword.trim() === '') {
|
this.hospitalOutResults = [...this.defaultHospitals]
|
this.showHospitalOutResults = true
|
return
|
}
|
|
// 有关键词时,去服务端搜索
|
this.searchTimer = setTimeout(() => {
|
this.searchHospitalOut(keyword)
|
}, 300)
|
},
|
|
// 搜索转出医院
|
searchHospitalOut(keyword) {
|
searchHospitals(keyword).then(response => {
|
this.hospitalOutResults = response.data || []
|
this.showHospitalOutResults = true
|
}).catch(error => {
|
console.error('搜索医院失败:', error)
|
this.hospitalOutResults = []
|
})
|
},
|
|
// 选择转出医院
|
selectHospitalOut(hospital) {
|
this.taskForm.hospitalOut.name = hospital.hospName
|
this.taskForm.hospitalOut.address = hospital.hospAddress
|
this.hospitalOutSearchKeyword = hospital.hospName
|
this.showHospitalOutResults = false
|
this.hospitalOutResults = []
|
|
// 如果有GPS坐标,保存下来
|
// 注意:HospData表中可能没有GPS坐标,需要根据地址进行地理编码
|
// 这里先置为null,后续可以通过地址解析获取
|
this.addressCoordinates.hospitalOutAddress = null
|
|
// 如果两个医院都已选择,自动计算距离
|
if (this.taskForm.hospitalIn.address) {
|
// 这里可以调用地址解析和距离计算
|
// 暂时留空,由用户手动输入距离
|
}
|
},
|
|
// 转入医院输入框获得焦点
|
onHospitalInFocus() {
|
// 如果没有搜索关键词,显示默认的100条数据
|
if (!this.hospitalInSearchKeyword || this.hospitalInSearchKeyword.trim() === '') {
|
this.hospitalInResults = [...this.defaultHospitals]
|
}
|
this.showHospitalInResults = true
|
},
|
|
// 转入医院搜索
|
onHospitalInSearch(e) {
|
const keyword = e.detail.value
|
this.hospitalInSearchKeyword = keyword
|
|
// 防抖处理
|
if (this.searchTimer) {
|
clearTimeout(this.searchTimer)
|
}
|
|
// 如果关键词为空,显示默认100条
|
if (!keyword || keyword.trim() === '') {
|
this.hospitalInResults = [...this.defaultHospitals]
|
this.showHospitalInResults = true
|
return
|
}
|
|
// 有关键词时,去服务端搜索
|
this.searchTimer = setTimeout(() => {
|
this.searchHospitalIn(keyword)
|
}, 300)
|
},
|
|
// 搜索转入医院
|
searchHospitalIn(keyword) {
|
searchHospitals(keyword).then(response => {
|
this.hospitalInResults = response.data || []
|
this.showHospitalInResults = true
|
}).catch(error => {
|
console.error('搜索医院失败:', error)
|
this.hospitalInResults = []
|
})
|
},
|
|
// 选择转入医院
|
selectHospitalIn(hospital) {
|
this.taskForm.hospitalIn.name = hospital.hospName
|
this.taskForm.hospitalIn.address = hospital.hospAddress
|
this.hospitalInSearchKeyword = hospital.hospName
|
this.showHospitalInResults = false
|
this.hospitalInResults = []
|
|
// 如果有GPS坐标,保存下来
|
this.addressCoordinates.hospitalInAddress = null
|
|
// 如果两个医院都已选择,自动计算距离
|
if (this.taskForm.hospitalOut.address) {
|
// 这里可以调用地址解析和距离计算
|
// 暂时留空,由用户手动输入距离
|
}
|
},
|
|
// 初始化选中的人员(默认包含当前用户)
|
initSelectedStaff() {
|
this.selectedStaff = [{
|
userId: this.currentUser.userId,
|
nickName: this.currentUser.nickName,
|
phonenumber: this.currentUser.phonenumber,
|
postName: this.currentUser.position,
|
deptId: this.currentUser.deptId
|
}]
|
},
|
|
// 加载当前用户所在分公司的所有人员
|
loadDeptStaff() {
|
const deptId = this.currentUser.deptId
|
if (!deptId) {
|
console.error('无法获取当前用户所在部门')
|
this.$modal.showToast('无法获取所在部门信息')
|
return
|
}
|
|
// 直接查询当前用户部门下的所有用户
|
// 后端SQL会自动处理:如果传入的是子部门,会查找其所属的分公司及其所有子部门的用户
|
const queryParams = {
|
deptId: deptId,
|
status: '0', // 只查询正常状态的用户
|
pageNum: 1,
|
pageSize: 10000 // 设置足够大的页面大小,获取所有用户
|
}
|
|
listUser(queryParams).then(response => {
|
const userList = response.rows || response.data || []
|
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)
|
}))
|
|
// 初始化过滤列表
|
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 : ''
|
|
// 判断是否为司机
|
if (postName.includes('司机') || roleName.includes('司机')) {
|
return 'driver'
|
}
|
// 判断是否为护士
|
if (postName.includes('护士') || roleName.includes('护士')) {
|
return 'nurse'
|
}
|
// 其他类型
|
return 'other'
|
},
|
|
// 显示人员选择弹窗
|
showStaffSelector() {
|
this.$refs.staffPopup.open()
|
this.filterStaffList()
|
},
|
|
// 关闭人员选择弹窗
|
closeStaffSelector() {
|
this.$refs.staffPopup.close()
|
this.staffSearchKeyword = ''
|
this.staffFilterType = 'all'
|
},
|
|
// 人员搜索
|
onStaffSearch(e) {
|
this.staffSearchKeyword = e.detail.value
|
this.filterStaffList()
|
},
|
|
// 筛选人员类型
|
filterStaff(type) {
|
this.staffFilterType = type
|
this.filterStaffList()
|
},
|
|
// 过滤人员列表
|
filterStaffList() {
|
let list = [...this.allStaffList]
|
|
// 按类型过滤
|
if (this.staffFilterType === 'driver') {
|
list = list.filter(staff => staff.type === 'driver')
|
} else if (this.staffFilterType === 'nurse') {
|
list = list.filter(staff => staff.type === 'nurse')
|
}
|
|
// 按关键词搜索
|
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))
|
})
|
}
|
|
this.filteredStaffList = list
|
},
|
|
// 切换人员选中状态
|
toggleStaffSelection(staff) {
|
const index = this.selectedStaff.findIndex(s => s.userId === staff.userId)
|
|
if (index > -1) {
|
// 如果是第一个(当前用户),不允许移除
|
if (index === 0) {
|
this.$modal.showToast('当前用户不能移除')
|
return
|
}
|
// 已选中,移除
|
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) {
|
if (index === 0) {
|
this.$modal.showToast('当前用户不能移除')
|
return
|
}
|
this.selectedStaff.splice(index, 1)
|
},
|
|
addStaff() {
|
this.showStaffSelector()
|
},
|
|
// ==================== 病情选择相关方法 ====================
|
|
// 显示病情选择弹窗
|
showDiseaseSelector() {
|
// 初始化临时选择列表(复制当前已选择的病情)
|
this.tempSelectedDiseases = [...this.selectedDiseases]
|
this.diseaseSearchKeyword = ''
|
// 默认加载所有病情
|
this.loadAllDiseases()
|
this.$refs.diseasePopup.open()
|
},
|
|
// 关闭病情选择弹窗
|
closeDiseaseSelector() {
|
this.$refs.diseasePopup.close()
|
this.diseaseSearchKeyword = ''
|
this.diseaseSearchResults = []
|
this.tempSelectedDiseases = []
|
},
|
|
// 病情搜索
|
onDiseaseSearch(e) {
|
const keyword = e.detail.value
|
this.diseaseSearchKeyword = keyword
|
|
// 防抖处理
|
if (this.diseaseSearchTimer) {
|
clearTimeout(this.diseaseSearchTimer)
|
}
|
|
// 如果关键词为空,加载所有病情
|
if (!keyword || keyword.trim() === '') {
|
this.loadAllDiseases()
|
return
|
}
|
|
// 有关键词时进行搜索
|
this.diseaseSearchTimer = setTimeout(() => {
|
this.searchDiseaseByKeyword(keyword)
|
}, 300)
|
},
|
|
// 加载所有病情(默认显示)
|
loadAllDiseases() {
|
// 使用空字符串或特殊标识符来获取所有病情
|
// 如果后端不支持空查询,可以传入一个通配符如'%'或者修改后端接口
|
searchIcd10('').then(response => {
|
this.diseaseSearchResults = response.data || []
|
}).catch(error => {
|
console.error('加载病情列表失败:', error)
|
this.diseaseSearchResults = []
|
})
|
},
|
|
// 根据关键词搜索病情
|
searchDiseaseByKeyword(keyword) {
|
searchIcd10(keyword).then(response => {
|
this.diseaseSearchResults = response.data || []
|
}).catch(error => {
|
console.error('搜索病情失败:', error)
|
this.diseaseSearchResults = []
|
})
|
},
|
|
// 切换病情选中状态
|
toggleDiseaseSelection(disease) {
|
const index = this.tempSelectedDiseases.findIndex(d => d.id === disease.id)
|
|
if (index > -1) {
|
// 已选中,移除
|
this.tempSelectedDiseases.splice(index, 1)
|
} else {
|
// 未选中,添加
|
this.tempSelectedDiseases.push({
|
id: disease.id,
|
icdCode: disease.icdCode,
|
icdName: disease.icdName,
|
sm: disease.sm
|
})
|
}
|
},
|
|
// 判断病情是否已选中
|
isDiseaseSelected(diseaseId) {
|
return this.tempSelectedDiseases.some(d => d.id === diseaseId)
|
},
|
|
// 确认病情选择
|
confirmDiseaseSelection() {
|
// 将临时选择的病情复制到正式列表
|
this.selectedDiseases = [...this.tempSelectedDiseases]
|
this.closeDiseaseSelector()
|
},
|
|
// 移除病情
|
removeDisease(index) {
|
this.selectedDiseases.splice(index, 1)
|
},
|
|
validateForm() {
|
if (!this.selectedVehicleId) {
|
this.$modal.showToast('请选择任务车辆')
|
return false
|
}
|
|
if (!this.taskForm.patient.name) {
|
this.$modal.showToast('请输入患者姓名')
|
return false
|
}
|
|
if (!this.taskForm.patient.phone) {
|
this.$modal.showToast('请输入患者联系电话')
|
return false
|
}
|
|
if (!this.taskForm.hospitalOut.name) {
|
this.$modal.showToast('请输入转出医院名称')
|
return false
|
}
|
|
if (!this.taskForm.hospitalIn.name) {
|
this.$modal.showToast('请输入转入医院名称')
|
return false
|
}
|
|
return true
|
},
|
|
buildSubmitData() {
|
// 合并病情信息:选中的ICD-10疾病 + 其他描述
|
let conditionText = ''
|
if (this.selectedDiseases.length > 0) {
|
const diseaseNames = this.selectedDiseases.map(d => `${d.icdName}(${d.icdCode})`).join('、')
|
conditionText = diseaseNames
|
}
|
if (this.taskForm.patient.condition && this.taskForm.patient.condition.trim()) {
|
if (conditionText) {
|
conditionText += '\n其他:' + this.taskForm.patient.condition
|
} else {
|
conditionText = this.taskForm.patient.condition
|
}
|
}
|
|
const submitData = {
|
taskType: 'EMERGENCY_TRANSFER',
|
vehicleIds: this.selectedVehicleId ? [this.selectedVehicleId] : [],
|
assigneeIds: this.selectedStaff.map(staff => staff.userId), // 添加执行人员ID列表
|
transferTime: this.taskForm.transferTime,
|
patient: {
|
...this.taskForm.patient,
|
condition: conditionText, // 使用合并后的病情信息
|
diseases: this.selectedDiseases.map(d => ({
|
icdId: d.id,
|
icdCode: d.icdCode,
|
icdName: d.icdName
|
}))
|
},
|
hospitalOut: this.taskForm.hospitalOut,
|
hospitalIn: this.taskForm.hospitalIn,
|
transferDistance: this.taskForm.transferDistance ? parseFloat(this.taskForm.transferDistance) : null,
|
price: this.taskForm.price ? parseFloat(this.taskForm.price) : null
|
}
|
|
if (this.addressCoordinates.hospitalOutAddress) {
|
if (!submitData.hospitalOut) submitData.hospitalOut = {}
|
submitData.hospitalOut.longitude = this.addressCoordinates.hospitalOutAddress.lng
|
submitData.hospitalOut.latitude = this.addressCoordinates.hospitalOutAddress.lat
|
}
|
|
if (this.addressCoordinates.hospitalInAddress) {
|
if (!submitData.hospitalIn) submitData.hospitalIn = {}
|
submitData.hospitalIn.longitude = this.addressCoordinates.hospitalInAddress.lng
|
submitData.hospitalIn.latitude = this.addressCoordinates.hospitalInAddress.lat
|
}
|
|
return submitData
|
},
|
|
submitTask() {
|
if (!this.validateForm()) {
|
return
|
}
|
|
this.$modal.confirm('确定要保存任务吗?').then(() => {
|
this.loading = true
|
const submitData = this.buildSubmitData()
|
|
addTask(submitData).then(response => {
|
this.loading = false
|
this.$modal.showToast('任务创建成功')
|
setTimeout(() => {
|
uni.redirectTo({
|
url: '/pages/task/index'
|
})
|
}, 1500)
|
}).catch(error => {
|
this.loading = false
|
console.error('任务创建失败:', error)
|
this.$modal.showToast('任务创建失败,请重试')
|
})
|
}).catch(() => {})
|
},
|
|
goBack() {
|
uni.navigateBack()
|
}
|
}
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
.create-emergency-task-container {
|
padding: 20rpx;
|
background-color: #f5f5f5;
|
min-height: 100vh;
|
|
.form-header {
|
display: flex;
|
align-items: center;
|
padding: 20rpx 0;
|
margin-bottom: 30rpx;
|
|
.back-btn {
|
width: 60rpx;
|
height: 60rpx;
|
border-radius: 50%;
|
background-color: #f0f0f0;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
margin-right: 20rpx;
|
}
|
|
.title {
|
font-size: 36rpx;
|
font-weight: bold;
|
color: #333;
|
}
|
}
|
|
.form-section {
|
background-color: white;
|
border-radius: 15rpx;
|
padding: 30rpx;
|
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
|
.form-section-title {
|
font-size: 32rpx;
|
font-weight: bold;
|
margin: 40rpx 0 20rpx 0;
|
padding-bottom: 10rpx;
|
border-bottom: 1rpx solid #f0f0f0;
|
}
|
|
.form-item {
|
margin-bottom: 40rpx;
|
|
.form-label {
|
font-size: 28rpx;
|
margin-bottom: 15rpx;
|
color: #333;
|
}
|
|
.hospital-search-container {
|
position: relative;
|
|
.search-results {
|
position: absolute;
|
top: 75rpx;
|
left: 0;
|
right: 0;
|
max-height: 400rpx;
|
background-color: white;
|
border: 1rpx solid #eee;
|
border-radius: 10rpx;
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
z-index: 100;
|
overflow-y: auto;
|
|
.search-result-item {
|
padding: 20rpx 30rpx;
|
border-bottom: 1rpx solid #f0f0f0;
|
|
&:last-child {
|
border-bottom: none;
|
}
|
|
&:active {
|
background-color: #f5f5f5;
|
}
|
|
.hospital-name {
|
font-size: 28rpx;
|
color: #333;
|
font-weight: bold;
|
margin-bottom: 8rpx;
|
}
|
|
.hospital-address {
|
font-size: 24rpx;
|
color: #999;
|
}
|
}
|
}
|
}
|
|
.form-input {
|
height: 70rpx;
|
padding: 0 20rpx;
|
border: 1rpx solid #eee;
|
border-radius: 10rpx;
|
font-size: 28rpx;
|
|
&.picker-input {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
|
&.disabled {
|
background-color: #f5f5f5;
|
color: #999;
|
}
|
}
|
}
|
|
.form-textarea {
|
width: 100%;
|
min-height: 150rpx;
|
padding: 20rpx;
|
border: 1rpx solid #eee;
|
border-radius: 10rpx;
|
font-size: 28rpx;
|
}
|
|
.disease-container {
|
.disease-tags {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 15rpx;
|
margin-bottom: 20rpx;
|
|
.disease-tag {
|
display: flex;
|
align-items: center;
|
padding: 10rpx 20rpx;
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
border-radius: 30rpx;
|
|
.disease-name {
|
font-size: 26rpx;
|
color: white;
|
margin-right: 10rpx;
|
}
|
}
|
}
|
|
.add-disease-btn {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
padding: 20rpx;
|
border: 1rpx dashed #007AFF;
|
border-radius: 10rpx;
|
color: #007AFF;
|
font-size: 28rpx;
|
|
text {
|
margin-left: 10rpx;
|
}
|
}
|
}
|
|
.radio-group {
|
display: flex;
|
|
.radio-item {
|
display: flex;
|
align-items: center;
|
margin-right: 30rpx;
|
|
radio {
|
margin-right: 10rpx;
|
}
|
}
|
}
|
|
.staff-list {
|
.staff-item {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 20rpx;
|
background-color: #f9f9f9;
|
border-radius: 10rpx;
|
margin-bottom: 20rpx;
|
|
.staff-info {
|
flex: 1;
|
display: flex;
|
align-items: center;
|
|
.staff-name {
|
font-size: 28rpx;
|
color: #333;
|
margin-right: 10rpx;
|
}
|
|
.staff-role {
|
font-size: 24rpx;
|
color: #999;
|
}
|
}
|
}
|
|
.add-staff {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
padding: 20rpx;
|
border: 1rpx dashed #007AFF;
|
border-radius: 10rpx;
|
color: #007AFF;
|
}
|
}
|
}
|
|
.form-actions {
|
margin-top: 50rpx;
|
text-align: center;
|
|
.submit-btn {
|
width: 80%;
|
height: 80rpx;
|
background-color: #007AFF;
|
color: white;
|
border-radius: 10rpx;
|
font-size: 32rpx;
|
|
&[disabled] {
|
background-color: #ccc;
|
color: #999;
|
}
|
}
|
}
|
}
|
}
|
|
// 人员选择弹窗样式
|
.staff-selector-popup {
|
background-color: white;
|
border-radius: 20rpx 20rpx 0 0;
|
max-height: 80vh;
|
display: flex;
|
flex-direction: column;
|
|
.popup-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 30rpx;
|
border-bottom: 1rpx solid #f0f0f0;
|
flex-shrink: 0;
|
|
.popup-title {
|
font-size: 32rpx;
|
font-weight: bold;
|
color: #333;
|
}
|
|
.popup-close {
|
padding: 10rpx;
|
}
|
}
|
|
.search-box {
|
display: flex;
|
align-items: center;
|
margin: 20rpx 30rpx;
|
padding: 15rpx 20rpx;
|
background-color: #f5f5f5;
|
border-radius: 10rpx;
|
flex-shrink: 0;
|
|
.search-input {
|
flex: 1;
|
margin-left: 10rpx;
|
font-size: 28rpx;
|
}
|
}
|
|
.staff-filter {
|
display: flex;
|
padding: 0 30rpx 20rpx;
|
gap: 20rpx;
|
flex-shrink: 0;
|
|
.filter-item {
|
flex: 1;
|
text-align: center;
|
padding: 15rpx 0;
|
background-color: #f5f5f5;
|
border-radius: 10rpx;
|
font-size: 28rpx;
|
color: #666;
|
|
&.active {
|
background-color: #007AFF;
|
color: white;
|
}
|
}
|
}
|
|
.staff-list-popup {
|
flex: 1;
|
overflow-y: auto;
|
padding: 0 30rpx;
|
|
.staff-item-popup {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 25rpx 20rpx;
|
border-bottom: 1rpx solid #f0f0f0;
|
|
&:active {
|
background-color: #f5f5f5;
|
}
|
|
.staff-info {
|
flex: 1;
|
|
.staff-name-row {
|
display: flex;
|
align-items: center;
|
margin-bottom: 10rpx;
|
|
.staff-name {
|
font-size: 30rpx;
|
font-weight: bold;
|
color: #333;
|
margin-right: 20rpx;
|
}
|
|
.staff-phone {
|
font-size: 24rpx;
|
color: #999;
|
}
|
}
|
|
.staff-detail-row {
|
display: flex;
|
align-items: center;
|
|
.staff-dept {
|
font-size: 24rpx;
|
color: #666;
|
margin-right: 20rpx;
|
}
|
|
.staff-post {
|
font-size: 24rpx;
|
color: #007AFF;
|
}
|
}
|
}
|
|
.checkbox-empty {
|
width: 40rpx;
|
height: 40rpx;
|
border: 2rpx solid #ddd;
|
border-radius: 50%;
|
}
|
}
|
|
.no-data {
|
text-align: center;
|
padding: 100rpx 0;
|
color: #999;
|
|
text {
|
display: block;
|
margin-top: 20rpx;
|
font-size: 28rpx;
|
}
|
}
|
}
|
|
.popup-footer {
|
display: flex;
|
padding: 20rpx 30rpx;
|
border-top: 1rpx solid #f0f0f0;
|
gap: 20rpx;
|
flex-shrink: 0;
|
|
button {
|
flex: 1;
|
height: 80rpx;
|
border-radius: 10rpx;
|
font-size: 30rpx;
|
}
|
|
.cancel-btn {
|
background-color: #f5f5f5;
|
color: #666;
|
}
|
|
.confirm-btn {
|
background-color: #007AFF;
|
color: white;
|
}
|
}
|
}
|
|
// 病情选择弹窗样式
|
.disease-selector-popup {
|
background-color: white;
|
border-radius: 20rpx 20rpx 0 0;
|
max-height: 80vh;
|
display: flex;
|
flex-direction: column;
|
|
.popup-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 30rpx;
|
border-bottom: 1rpx solid #f0f0f0;
|
flex-shrink: 0;
|
|
.popup-title {
|
font-size: 32rpx;
|
font-weight: bold;
|
color: #333;
|
}
|
|
.popup-close {
|
padding: 10rpx;
|
}
|
}
|
|
.search-box {
|
display: flex;
|
align-items: center;
|
margin: 20rpx 30rpx;
|
padding: 15rpx 20rpx;
|
background-color: #f5f5f5;
|
border-radius: 10rpx;
|
flex-shrink: 0;
|
|
.search-input {
|
flex: 1;
|
margin-left: 10rpx;
|
font-size: 28rpx;
|
}
|
}
|
|
.disease-list-popup {
|
flex: 1;
|
overflow-y: auto;
|
padding: 0 30rpx;
|
|
.disease-item-popup {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 25rpx 20rpx;
|
border-bottom: 1rpx solid #f0f0f0;
|
|
&:active {
|
background-color: #f5f5f5;
|
}
|
|
.disease-info {
|
flex: 1;
|
|
.disease-name-row {
|
display: flex;
|
align-items: center;
|
margin-bottom: 8rpx;
|
|
.disease-name {
|
font-size: 30rpx;
|
font-weight: bold;
|
color: #333;
|
margin-right: 15rpx;
|
}
|
|
.disease-code {
|
font-size: 24rpx;
|
color: #007AFF;
|
background-color: #e6f2ff;
|
padding: 4rpx 12rpx;
|
border-radius: 6rpx;
|
}
|
}
|
|
.disease-detail-row {
|
.disease-desc {
|
font-size: 24rpx;
|
color: #999;
|
line-height: 1.5;
|
}
|
}
|
}
|
|
.checkbox-empty {
|
width: 40rpx;
|
height: 40rpx;
|
border: 2rpx solid #ddd;
|
border-radius: 50%;
|
}
|
}
|
|
.no-data {
|
text-align: center;
|
padding: 100rpx 0;
|
color: #999;
|
|
text {
|
display: block;
|
margin-top: 20rpx;
|
font-size: 28rpx;
|
}
|
}
|
}
|
|
.popup-footer {
|
display: flex;
|
padding: 20rpx 30rpx;
|
border-top: 1rpx solid #f0f0f0;
|
gap: 20rpx;
|
flex-shrink: 0;
|
|
button {
|
flex: 1;
|
height: 80rpx;
|
border-radius: 10rpx;
|
font-size: 30rpx;
|
}
|
|
.cancel-btn {
|
background-color: #f5f5f5;
|
color: #666;
|
}
|
|
.confirm-btn {
|
background-color: #007AFF;
|
color: white;
|
}
|
}
|
}
|
</style>
|