| | |
| | | this.lastToken = getToken() |
| | | this.initApp() |
| | | |
| | | // 监听用户登录事件 |
| | | uni.$on('user-login', () => { |
| | | console.log('接收到用户登录事件,启动消息轮询') |
| | | const token = getToken() |
| | | if (token) { |
| | | this.lastToken = token |
| | | this.updateUnreadMessageBadge() |
| | | this.startMessagePolling() |
| | | } |
| | | }) |
| | | |
| | | // 监听用户登出事件 |
| | | uni.$on('user-logout', () => { |
| | | console.log('接收到用户登出事件,停止消息轮询') |
| | |
| | | this.checkLogin() |
| | | //#endif |
| | | |
| | | // 如果已登录,启动未读消息轮询 |
| | | if (getToken()) { |
| | | this.updateUnreadMessageBadge() |
| | | // 每30秒轮询一次 |
| | | this.startMessagePolling() |
| | | } |
| | | // 注意:不在应用启动时自动启动轮询 |
| | | // 只有在用户主动登录成功后才启动(通过 user-login 事件触发) |
| | | }, |
| | | initConfig() { |
| | | this.globalData.config = config |
| | |
| | | loginSuccess(result) { |
| | | // 设置用户信息 |
| | | this.$store.dispatch('GetInfo').then(res => { |
| | | // 触发登录成功事件,启动消息轮询 |
| | | uni.$emit('user-login') |
| | | this.$tab.reLaunch('/pages/index') |
| | | }) |
| | | } |
| | |
| | | |
| | | |
| | | <view class="form-item"> |
| | | <view class="form-label">转运时间</view> |
| | | <view class="form-label required">转运时间</view> |
| | | <uni-datetime-picker |
| | | v-model="taskForm.transferTime" |
| | | type="datetime" |
| | |
| | | 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 { calculateDistance, baiduDistanceByAddress } from "@/api/map" |
| | | import { searchHospitals } from "@/api/hospital" |
| | | import { listUser } from "@/api/system/user" |
| | | import { searchIcd10 } from "@/api/icd10" |
| | |
| | | } |
| | | }, |
| | | onLoad(options) { |
| | | // 设置默认转运时间为当前时间 |
| | | this.setDefaultTransferTime() |
| | | |
| | | // 先加载车辆列表,然后加载绑定车辆信息 |
| | | this.getAvailableVehicles().then(() => { |
| | | this.getUserBoundVehicleInfo() |
| | |
| | | this.showHospitalOutResults = false |
| | | this.hospitalOutResults = [] |
| | | |
| | | // 如果有GPS坐标,保存下来 |
| | | // 注意:HospData表中可能没有GPS坐标,需要根据地址进行地理编码 |
| | | // 这里先置为null,后续可以通过地址解析获取 |
| | | this.addressCoordinates.hospitalOutAddress = null |
| | | // 保存转出医院的城市信息 |
| | | this.taskForm.hospitalOut.city = hospital.hopsCity || '' |
| | | |
| | | // 如果两个医院都已选择,自动计算距离 |
| | | if (this.taskForm.hospitalIn.address) { |
| | | // 这里可以调用地址解析和距离计算 |
| | | // 暂时留空,由用户手动输入距离 |
| | | this.calculateHospitalDistance() |
| | | } |
| | | }, |
| | | |
| | |
| | | this.showHospitalInResults = false |
| | | this.hospitalInResults = [] |
| | | |
| | | // 如果有GPS坐标,保存下来 |
| | | this.addressCoordinates.hospitalInAddress = null |
| | | // 保存转入医院的城市信息 |
| | | this.taskForm.hospitalIn.city = hospital.hopsCity || '' |
| | | |
| | | // 如果两个医院都已选择,自动计算距离 |
| | | if (this.taskForm.hospitalOut.address) { |
| | | // 这里可以调用地址解析和距离计算 |
| | | // 暂时留空,由用户手动输入距离 |
| | | this.calculateHospitalDistance() |
| | | } |
| | | }, |
| | | |
| | |
| | | this.selectedDiseases.splice(index, 1) |
| | | }, |
| | | |
| | | // 设置默认转运时间为当前时间 |
| | | setDefaultTransferTime() { |
| | | 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') |
| | | const hours = String(now.getHours()).padStart(2, '0') |
| | | const minutes = String(now.getMinutes()).padStart(2, '0') |
| | | const seconds = String(now.getSeconds()).padStart(2, '0') |
| | | |
| | | // 格式化为 YYYY-MM-DD HH:mm:ss |
| | | this.taskForm.transferTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}` |
| | | }, |
| | | |
| | | validateForm() { |
| | | if (!this.selectedVehicleId) { |
| | | this.$modal.showToast('请选择任务车辆') |
| | |
| | | |
| | | if (!this.selectedDocumentType) { |
| | | this.$modal.showToast('请选择单据类型') |
| | | return false |
| | | } |
| | | |
| | | if (!this.taskForm.transferTime) { |
| | | this.$modal.showToast('请选择转运时间') |
| | | return false |
| | | } |
| | | |
| | |
| | | parts.push(hospital.hospAddress) |
| | | } |
| | | return parts.join('') |
| | | }, |
| | | |
| | | // 自动计算两个医院之间的距离 |
| | | calculateHospitalDistance() { |
| | | const fromAddress = this.taskForm.hospitalOut.address |
| | | const fromCity = this.taskForm.hospitalOut.city |
| | | const toAddress = this.taskForm.hospitalIn.address |
| | | const toCity = this.taskForm.hospitalIn.city |
| | | |
| | | if (!fromAddress || !toAddress) { |
| | | console.log('地址信息不完整,无法计算距离') |
| | | return |
| | | } |
| | | |
| | | console.log('开始计算距离:', fromAddress, '->', toAddress) |
| | | |
| | | // 显示加载提示 |
| | | uni.showLoading({ |
| | | title: '计算距离中...' |
| | | }) |
| | | |
| | | // 调用百度地图API计算距离 |
| | | baiduDistanceByAddress(fromAddress, fromCity, toAddress, toCity) |
| | | .then(response => { |
| | | uni.hideLoading() |
| | | |
| | | if (response.code === 200 && response.data) { |
| | | const distanceInMeters = response.data.distance |
| | | // 转换为公里,保留1位小数 |
| | | const distanceInKm = (distanceInMeters / 1000).toFixed(1) |
| | | this.taskForm.transferDistance = distanceInKm |
| | | |
| | | console.log('距离计算成功:', distanceInKm, 'km') |
| | | this.$modal.showToast(`距离计算成功: ${distanceInKm}公里`) |
| | | } else { |
| | | console.error('距离计算失败:', response.msg) |
| | | this.$modal.showToast('距离计算失败,请手动输入') |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | uni.hideLoading() |
| | | console.error('距离计算失败:', error) |
| | | this.$modal.showToast('距离计算失败,请手动输入') |
| | | }) |
| | | } |
| | | } |
| | | } |
| | |
| | | String geocodingResponse1 = HttpUtils.sendGet(geocodingUrl1, geocodingParams1); |
| | | logger.info("起点地理编码响应: {}", geocodingResponse1); |
| | | |
| | | // 解析起点坐标 |
| | | com.alibaba.fastjson2.JSONObject geocodingJson1 = com.alibaba.fastjson2.JSONObject.parseObject(geocodingResponse1); |
| | | if (geocodingJson1.getInteger("status") != 0) { |
| | | logger.error("起点地理编码失败: {}", geocodingResponse1); |
| | | return AjaxResult.error("起点地址解析失败"); |
| | | } |
| | | com.alibaba.fastjson2.JSONObject location1 = geocodingJson1.getJSONObject("result").getJSONObject("location"); |
| | | double fromLat = location1.getDouble("lat"); |
| | | double fromLng = location1.getDouble("lng"); |
| | | logger.info("起点坐标: lat={}, lng={}", fromLat, fromLng); |
| | | |
| | | // 第二步:终点地址转坐标 |
| | | String geocodingUrl2 = "https://api.map.baidu.com/geocoding/v3/"; |
| | | String geocodingParams2 = "address=" + URLEncoder.encode(toAddress, StandardCharsets.UTF_8.toString()) + |
| | |
| | | String geocodingResponse2 = HttpUtils.sendGet(geocodingUrl2, geocodingParams2); |
| | | logger.info("终点地理编码响应: {}", geocodingResponse2); |
| | | |
| | | // 解析坐标(这里简化处理,实际应该解析JSON) |
| | | // 注意:需要从响应中提取坐标,这里返回中间结果供前端处理 |
| | | Map<String, Object> result = new HashMap<>(); |
| | | result.put("fromGeocoding", geocodingResponse1); |
| | | result.put("toGeocoding", geocodingResponse2); |
| | | result.put("message", "请解析坐标后调用 /baidu/route/driving 接口计算距离"); |
| | | // 解析终点坐标 |
| | | com.alibaba.fastjson2.JSONObject geocodingJson2 = com.alibaba.fastjson2.JSONObject.parseObject(geocodingResponse2); |
| | | if (geocodingJson2.getInteger("status") != 0) { |
| | | logger.error("终点地理编码失败: {}", geocodingResponse2); |
| | | return AjaxResult.error("终点地址解析失败"); |
| | | } |
| | | com.alibaba.fastjson2.JSONObject location2 = geocodingJson2.getJSONObject("result").getJSONObject("location"); |
| | | double toLat = location2.getDouble("lat"); |
| | | double toLng = location2.getDouble("lng"); |
| | | logger.info("终点坐标: lat={}, lng={}", toLat, toLng); |
| | | |
| | | return AjaxResult.success("地理编码成功", result); |
| | | // 第三步:调用路线规划接口计算距离 |
| | | String routeUrl = "https://api.map.baidu.com/directionlite/v1/driving"; |
| | | String origin = fromLat + "," + fromLng; |
| | | String destination = toLat + "," + toLng; |
| | | String routeParams = "origin=" + origin + |
| | | "&destination=" + destination + |
| | | "&ak=" + baiduMapConfig.getAk(); |
| | | |
| | | logger.info("路线规划请求: origin={}, destination={}", origin, destination); |
| | | String routeResponse = HttpUtils.sendGet(routeUrl, routeParams); |
| | | logger.info("路线规划响应: {}", routeResponse); |
| | | |
| | | // 解析距离结果 |
| | | com.alibaba.fastjson2.JSONObject routeJson = com.alibaba.fastjson2.JSONObject.parseObject(routeResponse); |
| | | if (routeJson.getInteger("status") != 0) { |
| | | logger.error("路线规划失败: {}", routeResponse); |
| | | return AjaxResult.error("路线规划失败"); |
| | | } |
| | | |
| | | // 提取距离信息(单位:米) |
| | | com.alibaba.fastjson2.JSONObject result = routeJson.getJSONObject("result"); |
| | | com.alibaba.fastjson2.JSONArray routes = result.getJSONArray("routes"); |
| | | if (routes == null || routes.isEmpty()) { |
| | | logger.error("未找到路线信息"); |
| | | return AjaxResult.error("未找到路线信息"); |
| | | } |
| | | |
| | | com.alibaba.fastjson2.JSONObject route = routes.getJSONObject(0); |
| | | int distance = route.getInteger("distance"); // 距离,单位:米 |
| | | int duration = route.getInteger("duration"); // 时长,单位:秒 |
| | | |
| | | logger.info("计算成功: 距离={}米, 时长={}秒", distance, duration); |
| | | |
| | | // 构建返回结果 |
| | | Map<String, Object> resultMap = new HashMap<>(); |
| | | resultMap.put("distance", distance); // 距离(米) |
| | | resultMap.put("duration", duration); // 时长(秒) |
| | | resultMap.put("distanceKm", String.format("%.1f", distance / 1000.0)); // 距离(公里) |
| | | resultMap.put("durationMin", duration / 60); // 时长(分钟) |
| | | |
| | | // 起点坐标 |
| | | Map<String, Object> fromLocation = new HashMap<>(); |
| | | fromLocation.put("lat", fromLat); |
| | | fromLocation.put("lng", fromLng); |
| | | resultMap.put("fromLocation", fromLocation); |
| | | |
| | | // 终点坐标 |
| | | Map<String, Object> toLocation = new HashMap<>(); |
| | | toLocation.put("lat", toLat); |
| | | toLocation.put("lng", toLng); |
| | | resultMap.put("toLocation", toLocation); |
| | | |
| | | return AjaxResult.success("计算成功", resultMap); |
| | | } catch (Exception e) { |
| | | logger.error("计算地址距离失败", e); |
| | | return AjaxResult.error("计算距离失败:" + e.getMessage()); |
| | |
| | | basename: i18n/messages |
| | | profiles: |
| | | # 环境 dev|test|prod |
| | | active: prod |
| | | active: dev |
| | | # 文件上传 |
| | | servlet: |
| | | multipart: |
| | |
| | | # 百度地图配置 |
| | | baidu: |
| | | map: |
| | | ak: YOUR_BAIDU_MAP_AK_HERE # 请替换为您的百度地图API Key |
| | | ak: GX7G1RmAbTEQHor9NKpzRiB2jerqaY1E # 请替换为您的百度地图API Key |
| | |
| | | // 保存GPS位置信息 |
| | | vehicleGpsService.insertVehicleGps(gps); |
| | | |
| | | log.info("车辆[{}]GPS位置已更新: 经度={}, 纬度={}, 设备时间={}, 处理时间={}", |
| | | vehicle.getVehicleNo(), position.getCallon(), position.getCallat(), |
| | | gps.getDeviceReportTime(), gps.getPlatformProcessTime()); |
| | | // log.info("车辆[{}]GPS位置已更新: 经度={}, 纬度={}, 设备时间={}, 处理时间={}", |
| | | // vehicle.getVehicleNo(), position.getCallon(), position.getCallat(), |
| | | // gps.getDeviceReportTime(), gps.getPlatformProcessTime()); |
| | | } catch (Exception e) { |
| | | log.error("更新车辆[{}]GPS位置失败: {}", vehicle.getVehicleNo(), e.getMessage()); |
| | | } |
| | |
| | | while (true) { |
| | | // 分页查询已同步服务单但未同步调度单的任务 |
| | | List<SysTaskEmergency> pendingTasks = sysTaskEmergencyService.selectPendingDispatchSyncTasks(offset, pageSize); |
| | | |
| | | log.info("查询到未同步调度单的任务数量: {}", pendingTasks.size()); |
| | | if (pendingTasks == null || pendingTasks.isEmpty()) { |
| | | log.info("没有更多需要同步调度单的任务,offset: {}", offset); |
| | | break; // 没有更多数据,退出循环 |
| | |
| | | |
| | | int pageSuccessCount = 0; |
| | | for (SysTaskEmergency emergency : pendingTasks) { |
| | | log.info("开始同步调度单,任务ID: {}", emergency.getTaskId()); |
| | | Long dispatchOrdId = syncDispatchOrderToLegacy(emergency.getTaskId()); |
| | | if (dispatchOrdId != null && dispatchOrdId > 0) { |
| | | pageSuccessCount++; |
| | |
| | | </resultMap> |
| | | |
| | | <select id="searchHospitals" resultMap="HospDataResult"> |
| | | SELECT TOP 100 |
| | | SELECT TOP 1000 |
| | | HospID, HospName, HospCityID, HospShort, |
| | | HopsProvince, HopsCity, HopsArea, HospAddress, |
| | | HospTEL, HospUnitID, HospState, HospOAID, |
| | |
| | | `update_time`, |
| | | `remark` |
| | | ) VALUES ( |
| | | '任务状态同步', |
| | | '任务状态旧到新同步', |
| | | 'DEFAULT', |
| | | 'legacySystemSyncTask.syncTaskStatusFromLegacy()', |
| | | '0 0/5 * * * ?', |
| | |
| | | -- ---------------------------- |
| | | INSERT INTO sys_job (job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, update_by, update_time, remark) |
| | | VALUES |
| | | ('任务状态推送', 'DEFAULT', 'legacySystemSyncTask.pushTaskStatusToLegacy()', '0 0/3 * * * ?', '3', '1', '1', 'admin', sysdate(), 'admin', sysdate(), |
| | | ('任务状态推送新到旧', 'DEFAULT', 'legacySystemSyncTask.pushTaskStatusToLegacy()', '0 0/3 * * * ?', '3', '1', '1', 'admin', sysdate(), 'admin', sysdate(), |
| | | '每3分钟执行一次,将新系统中状态已变化的任务推送到旧系统。推送规则:出发中->4,任务中->6,返程中->7,已完成->8,已取消->10。旧系统状态>=目标状态时不推送。'); |