Browse Source

室内外足迹跳转

heyifan 1 tuần trước cách đây
mục cha
commit
7789b5fc9f

+ 4 - 0
languages/en.js

@@ -1859,5 +1859,9 @@ module.exports = {
   radiusTooSmall: 'The radius must be no less than 200',
   radiusTooLarge: 'The radius cannot exceed 2000 meters',
   inputLocationKeyword: 'Please enter a location keyword'
+  },
+   he20250620:{
+   indoorFootprint: 'Indoor Footprint',
+  outdoorFootprint: 'Outdoor Footprint'
   }
 }

+ 5 - 1
languages/es.js

@@ -1859,5 +1859,9 @@ module.exports = {
     radiusTooSmall: 'El radio no puede ser menor a 200',
     radiusTooLarge: 'El radio no puede exceder los 2000 metros',
     inputLocationKeyword: 'Por favor, ingrese una palabra clave para la ubicación',
-  }
+  },
+  he20250620: {
+  indoorFootprint: 'Huella interior',
+  outdoorFootprint: 'Huella exterior'
+}
 }

+ 5 - 1
languages/ru-RU.js

@@ -1882,5 +1882,9 @@ module.exports = {
     radiusTooSmall: 'Радиус не может быть меньше 200',
     radiusTooLarge: 'Радиус не может превышать 2000 метров',
     inputLocationKeyword: 'Пожалуйста, введите ключевое слово для места'
-  }
+  },
+  he20250620: {
+    indoorFootprint: 'Внутренний след',
+    outdoorFootprint: 'Внешний след'
+}
 }

+ 4 - 0
languages/zh-CN.js

@@ -1860,5 +1860,9 @@ module.exports = {
     radiusTooSmall: '围栏半径不能小于200',
     radiusTooLarge: '围栏半径不能超过2000米',
     inputLocationKeyword:'请输入地名关键字',
+  },
+  he20250620:{
+    indoorFootprint:'室内足迹',
+    outdoorFootprint:'室外足迹',
   }
 }

+ 4 - 0
languages/zh-TW.js

@@ -1822,5 +1822,9 @@ module.exports = {
     radiusTooSmall: '圍欄半徑不能小於200',
     radiusTooLarge: '圍欄半徑不能超過2000米',
     inputLocationKeyword: '請輸入地名關鍵字',
+  },
+   he20250620:{
+   indoorFootprint: '室內足跡',
+  outdoorFootprint: '室外足跡'
   }
 }

+ 4 - 4
public/domain.js

@@ -1,8 +1,8 @@
 const domain = {
-  // serverUrl: 'http://8.129.220.143:8005',
-  // DeviceUrl: 'http://8.129.220.143:8006',
-  serverUrl: 'http://192.168.1.187:8005',
-  DeviceUrl: 'http://192.168.1.187:8006',
+  serverUrl: 'http://8.129.220.143:8005',
+  DeviceUrl: 'http://8.129.220.143:8006',
+  // serverUrl: 'http://192.168.1.187:8005',
+  // DeviceUrl: 'http://192.168.1.187:8006',
   mediaUrl: 'http://8.129.220.143:8004',
   OnlineSystemUrl: 'http://api.base.wdklian.com',
   gateWayUrl:'http://8.129.220.143:8014',

+ 2 - 1
src/utils/enum/DeviceTypeEnum.js

@@ -57,6 +57,7 @@ export const DEVICE_TYPE = createEnum(
     SMART_LIFE_VOICE_GATE: [51, i18n.t('zy20240611.SMART_LIFE_VOICE_GATE')], // 智慧生活语音网关
     CURTAIN: [52, i18n.t('zy20240611.CURTAIN')], // 窗帘
     SWITCH: [53, i18n.t('zy20240611.SWITCH')], // 开关
-    SIMULATE_BLUE_CODE: [54, i18n.t('zy20240611.SIMULATE_BLUE_CODE')]
+    SIMULATE_BLUE_CODE: [54, i18n.t('zy20240611.SIMULATE_BLUE_CODE')],
+ 
   }
 )

+ 2 - 1
src/utils/enum/DeviceTypeNewEnum.js

@@ -23,7 +23,8 @@ export const DEVICE_TYPE_ENUM = {
     CURTAIN: 'CURTAIN', // 窗帘
     SWITCH: 'SWITCH', // 开关
     SIMULATE_BLUE_CODE: 'SIMULATE_BLUE_CODE', // 模拟BLUE CODE
-    EMERGENCY_BUTTON: 'EMERGENCY_BUTTON' // 紧急按钮
+    EMERGENCY_BUTTON: 'EMERGENCY_BUTTON', // 紧急按钮
+    SIMULATE_NURSING:'SIMULATE_NURSING'//模拟护理按钮
 }
 // export const DEVICE_TYPE = (
 //   {

+ 72 - 5
src/views/customer/components/patientManager.vue

@@ -570,6 +570,25 @@
               @childFn="setVal"></my-map>
     </el-dialog>
     <!--    选择坐标-->
+  <!-- 足迹选择弹窗 -->
+<el-dialog
+  :title="$t('customerManage.footprint')"
+  :visible.sync="popoverVisible"
+  custom-class="footprint-dialog"
+  width="300px"
+  center
+  top="40vh"
+  >
+  <div class="footprint-options">
+    <el-button type="primary" @click="showIndoorFootprint">{{ $t('he20250620.indoorFootprint') }}</el-button>
+    <el-button type="primary" @click="showOutdoorFootprint">{{ $t('he20250620.outdoorFootprint') }}</el-button>
+  </div>
+</el-dialog>
+
+<!--    位置信息-->
+<el-dialog :title="this.$t('watch.placeInfo')" :visible.sync="locationShow2" width="70%" top="8vh">
+  <watch-location :key="locationComponentKey" :device-id="deviceId" :is-show="locationShow2" :memberId="memberId" :frameId="frameId"></watch-location>
+</el-dialog>
   </div>
 
 </template>
@@ -608,7 +627,8 @@ import * as API_SystemConfig from '@/api/ncs_systemconfig'
 import * as shop_API from '@/api/ncs_shop'
 import { getRelativeList, removeRelative } from '@/api/ncs_relative'
 import { getWatchFootprint } from '@/api/ncs_device'
-
+//室内足迹
+import watchLocation from '@/views/ncs-device/watch_location'
 const serverUrl = domain.serverUrl
 export default {
   name: 'PatientManager',
@@ -623,7 +643,8 @@ export default {
     vitalSignLog,
     vueQr,
     customerFee,
-    advice
+    advice,
+    watchLocation,//室内足迹
   },
   filters: {
     unixDateFilter(val) {
@@ -789,7 +810,14 @@ export default {
       childbirthTypeEnum: CHILDBIRTH_TYPE.getValueList(),
       locationShow: false,
       isChild: false,
-      vitalDrawer: false
+      vitalDrawer: false,
+      popoverVisible: false,
+      currentRow: null,
+      locationShow2: false,
+      deviceId: null,
+      memberId: null,
+      frameId: null,
+      locationComponentKey: 0
     }
   },
   computed: {
@@ -1787,9 +1815,40 @@ export default {
       this.$router.push({ name: 'advice', params: { id: row.id, callback: this.getList() } })
 
     },
+    // lookLocation(row) {
+    //   console.log('触发了足迹跳转',row)
+    //   this.$router.push({ path: '/device/map', query: { mapUrl: this.mapUrl, uuid: row.uuid, frameId: row.frame_id } })
+    // },
     lookLocation(row) {
-      this.$router.push({ path: '/device/map', query: { mapUrl: this.mapUrl, uuid: row.uuid, frameId: row.frame_id } })
-    },
+  this.currentRow = row
+  this.popoverVisible = true
+},
+// 显示室内足迹
+showIndoorFootprint() {
+  if (!this.currentRow) return
+      // 更新 key,强制重新创建组件
+  this.locationComponentKey = Date.now()
+  this.deviceId = this.currentRow.id
+  this.frameId = this.currentRow.frame_id
+  this.memberId = this.currentRow.member_id
+  this.popoverVisible = false
+  this.locationShow2 = true
+},
+
+// 显示室外足迹
+showOutdoorFootprint() {
+  if (!this.currentRow) return
+  this.popoverVisible = false
+  console.log('点击室外足迹')
+  this.$router.push({ 
+    path: '/device/map', 
+    query: { 
+      mapUrl: this.mapUrl, 
+      uuid: this.currentRow.uuid, 
+      frameId: this.currentRow.frame_id 
+    } 
+  })
+},
     lookVitalSigns(row) {
       this.formmodel = {
         ...row
@@ -1872,4 +1931,12 @@ export default {
 .el-input .el-select {
   width: 120px;
 }
+.footprint-options {
+  display: flex;
+  justify-content: space-around;
+  padding: 10px 0;
+}
+::v-deep .footprint-dialog {
+  border-radius: 8px;
+}
 </style>

+ 2 - 1
src/views/ncs-device/components/deviceManager.vue

@@ -1199,7 +1199,8 @@
             },
           /** 判断是否是模拟设备 **/
           isSimulatedDevice(code) {
-            const simulatedDevices = [DEVICE_TYPE_ENUM.SIMULATE_BED_DEVICE, DEVICE_TYPE_ENUM.RS485_DOOR, DEVICE_TYPE_ENUM.SIMULATE_EMERGENCY_BUTTON, DEVICE_TYPE_ENUM.SIMULATE_DOOR_LIGHT, DEVICE_TYPE_ENUM.SIMULATE_BLUE_CODE];
+            const simulatedDevices = [DEVICE_TYPE_ENUM.SIMULATE_BED_DEVICE, DEVICE_TYPE_ENUM.RS485_DOOR, DEVICE_TYPE_ENUM.SIMULATE_EMERGENCY_BUTTON, 
+            DEVICE_TYPE_ENUM.SIMULATE_DOOR_LIGHT, DEVICE_TYPE_ENUM.SIMULATE_BLUE_CODE, DEVICE_TYPE_ENUM.SIMULATE_NURSING];
             return simulatedDevices.includes(code);
           },
           /** 判断是否是智慧控制设备 **/

+ 3 - 2
src/views/ncs-device/user_watch.vue

@@ -52,7 +52,7 @@
     </el-dialog>
 
 <!--    位置信息-->
-    <el-dialog :title="this.$t('watch.placeInfo')" :visible.sync="locationShow" width="70%">
+    <el-dialog :title="this.$t('watch.placeInfo')" :visible.sync="locationShow" width="70%" top="8vh">
       <watch-location :device-id="deviceId" :is-show="locationShow" ></watch-location>
     </el-dialog>
   </div>
@@ -66,6 +66,7 @@ import ButtonCellRender from '@/components/AgGridCellRender/ButtonCellRender'
 import RadioFilter from '@/components/AgGridCustomFilter/RadioFilter'
 import watchLocation from '@/views/ncs-device/watch_location'
 import { getListByPartId } from '@/api/ncs_customer'
+import { DEVICE_TYPE } from '@/utils/enum/DeviceTypeEnum'
 const DeviceUrl = domain.DeviceUrl
 export default {
   name: 'Index',
@@ -90,7 +91,7 @@ export default {
       params: {
         page_size: 100,
         page_no: 1,
-        fixedCondition: ' part_id=' + this.$store.getters.partId + ' and device_type = 9',
+        fixedCondition: ` part_id=${this.$store.getters.partId} and device_type = ${DEVICE_TYPE.USER_WATCH}`,
         sort: 'id',
         dir: 'desc'
       },

+ 116 - 21
src/views/ncs-device/watch_location.vue

@@ -1,23 +1,35 @@
 <template>
   <div class="app-container">
     <div class="block">
-      <el-date-picker v-model="queryTime" type="date" :placeholder="this.$t('watch.dateKeywords')"
+      <el-date-picker v-model="queryTime" type="date" :placeholder="$t('watch.dateKeywords')"
         value-format="yyyy-MM-dd">
       </el-date-picker>
       <el-button type="primary" plain style="margin-left: 30px" v-loading.fullscreen.lock="fullscreenLoading"
         @click="getNewLocation">
-        {{ this.$t('watch.getNewPlace') }}</el-button>
+        {{ $t('watch.getNewPlace') }}</el-button>
       <el-tag v-if="myTitle" style="margin-left: 20px;" type="warning">{{ myTitle }}</el-tag>
 
 <div class="color-legend">
   <div class="legend-item">
     <span class="color-dot green"></span>
-    <span>{{ this.$t('he20250514.currentPosition') }}</span>
+    <span>{{ $t('he20250514.currentPosition') }}</span>
   </div>
   <div class="legend-item">
     <span class="color-dot red"></span>
-    <span>{{ this.$t('he20250514.aiarmArea') }}</span>
+    <span>{{ $t('he20250514.aiarmArea') }}</span>
   </div>
+<!-- 添加设备选择下拉框 -->
+    <div class="device-selector" v-if="deviceDisplay">
+      <el-select :disabled="isLoadingLocations"  v-model="selectedDeviceType" @change="handleDeviceTypeChange" placeholder="请选择设备类型" style="width: 300px;">
+        <el-option
+          v-for="item in deviceTypeOptions"
+          :key="item.eth_mac"
+          :label="`${item.name} --- ${item.eth_mac}`"
+          :value="item.eth_mac">
+        </el-option>
+      </el-select>
+    </div>
+  
 </div>
     </div>
     <div class="location-map">
@@ -65,7 +77,7 @@
             <div class="location-info">
               <i class="el-icon-location-outline"></i>
               <span>{{ item.full_name }}</span>
-              <span v-if="index === 0" class="current-badge">当前位置</span>
+              <span v-if="index === 0" class="current-badge">{{ $t('he20250514.currentPosition') }}</span>
             </div>
           </el-card>
         </el-timeline-item>
@@ -78,6 +90,7 @@
 </template>
 
 <script>
+import * as API_Realdevice from '@/api/ncs_device'
 import * as API_DeviceLocation from '@/api/ncs_device_location'
 import { unixToDate } from '@/utils/Foundation'
 import { getListByDeviceId } from '@/api/ncs_hospitalFrame'
@@ -95,6 +108,14 @@ export default {
     isShow: {
       type: Boolean,
       default: false
+    },
+    memberId: {
+      type: Number,
+      default: null
+    },
+    frameId: {
+      type: Number,
+      default: null
     }
   },
   data: function () {
@@ -119,16 +140,31 @@ export default {
       pathData: '',
       viewBox: '0 0 1000 1000',
       gridPositions: null,
-
+      selectedDeviceType:'',
+      deviceTypeOptions:[],
+       params2: {
+        page_size: 100,
+        page_no: 1,
+        fixedCondition: `(device_type = ${DEVICE_TYPE.USER_WATCH} and member_id =${this.memberId})  or (device_type = ${DEVICE_TYPE.WATCH_BSJ} and frame_id=${this.frameId})`,
+        sort: 'id',
+        dir: 'desc'
+      },
+      deviceDisplay: false,
+      isLoadingLocations: false,
     }
   },
   watch: {
-    isShow: function () {
-      if (this.isShow) {
+    isShow:{
+      handler(newVal){
+if(newVal){
         this.sx()
-      } else {
+}else {
         this.websocketclose()
+        this.clearDeviceTypeOptions() 
       }
+
+      },
+      immediate: true
     },
     queryTime: function () {
       if (this.queryTime) {
@@ -141,13 +177,55 @@ export default {
     }
   },
   mounted() {
-    this.API_Devices()
-    this.initWebSocket()
   },
   methods: {
+     clearDeviceTypeOptions() {
+    this.deviceTypeOptions = [] // 清空设备类型选项
+    this.selectedDeviceType = '' // 重置选中的设备类型
+  },
+      // 处理设备类型变化
+  handleDeviceTypeChange() {
+     console.log('设备类型变化:', this.selectedDeviceType)
+
+  if (this.selectedDeviceType) {  
+    // 找到选中的设备对象
+    const selectedDevice = this.deviceTypeOptions.find(device => device.eth_mac === this.selectedDeviceType)
+    
+    if (selectedDevice) {
+      // 更新查询条件,使用选中设备的ID
+      this.params.fixedCondition = ` device_id = ${selectedDevice.id}`
+      console.log('更新位置查询条件:', this.params.fixedCondition)
+      
+      // 清除之前的样式和数据
+      this.clearStyle()
+      this.beaconDevices = []
+      this.locationList = []
+            
+      this.API_Devices()
+    }
+  } else {
+    console.log('未选择设备')
+  }
+  },
+  API_Realdevice(){
+     const _this = this
+     API_Realdevice.getList(this.params2).then(res => { 
+     this.deviceTypeOptions =res.data 
+     if(this.deviceTypeOptions && this.deviceTypeOptions.length>0){
+         this.deviceDisplay = true
+         this.selectedDeviceType = this.deviceTypeOptions[0].eth_mac
+         this.params.fixedCondition = ' device_id = ' + this.deviceTypeOptions[0].id
+              this.API_Devices()
+     }else{
+       this.API_Devices()
+     }
+})
+  },
+  
     API_Devices() {
       const _this = this
       getLocationDeviceList(this.$store.getters.partId).then(res => {
+        // console.log('位置信息',res)
         _this.beaconDevices = res
         _this.initGridPositions()
         _this.API_GetList()
@@ -156,6 +234,7 @@ export default {
     API_GetList() {
       const _this = this
       API_DeviceLocation.getPage(this.params).then(res => {
+        // console.log('移动轨迹',res)
         _this.tableData = [...res.data]
         _this.pageData = {
           page_no: res.page_no,
@@ -176,6 +255,7 @@ export default {
         _this.myTitle = this.$t('watch.notCovered')
       }
       this.tableData.reverse()
+      this.isLoadingLocations = true // 开始渲染
       for (let i = 0; i < _this.tableData.length; i++) {
         (function (t, data) {
           setTimeout(function () {
@@ -203,13 +283,13 @@ export default {
               }
             }
             document.getElementById('myIcon' + data.beacon_device_id).style.display = 'inline'
-            _this.$notify({
-              title: data.full_name,
-              message: unixToDate(data.create_time) + _this.$t('watch.in') + data.full_name + _this.$t('watch.nearby'),
-              position: 'bottom-right',
-              showClose: false,
-              duration: 2500
-            })
+            // _this.$notify({
+            //   title: data.full_name,
+            //   message: unixToDate(data.create_time) + _this.$t('watch.in') + data.full_name + _this.$t('watch.nearby'),
+            //   position: 'bottom-right',
+            //   showClose: false,
+            //   duration: 2500
+            // })
             myId = 'myFrame'+data.beacon_device_id
             _this.locationList.unshift(data)
             // let text = document.getElementById('myText' + data.beacon_device_id)
@@ -224,9 +304,18 @@ export default {
             // if (t === _this.tableData.length - 1) {
             //   _this.updateMovementPath()
             // }
+            if (t === _this.tableData.length - 1) {
+          _this.$nextTick(() => {
+            _this.isLoadingLocations = false // 标记渲染完成
+          })
+        }
           }, 250 * t)
         })(i, _this.tableData[i])
       }
+        if (this.tableData.length === 0) {
+    this.isLoadingLocations = false
+  }
+  
       // this.updateMovementPath()
     },
     sx() {
@@ -242,7 +331,12 @@ export default {
       this.beaconDevices = []
       this.locationList = []
       this.initWebSocket()
-      this.API_Devices()
+     if (this.memberId && this.frameId) {
+    this.API_Realdevice()
+  } else {
+    this.API_Devices()
+  }
+ 
     },
     /** 分页大小发生改变 */
     handlePageSizeChange(size) {
@@ -267,7 +361,7 @@ export default {
           element.style = ''
         }
         document.getElementById('myIcon' + item).style.display = 'none'
-        document.getElementById('myText' + item).innerText = ''
+        // document.getElementById('myText' + item).innerText = ''
       })
     },
     formatterCreateTime(data) {
@@ -339,6 +433,7 @@ export default {
     initGridPositions() {
       const totalBeacons = this.beaconDevices.length
       const cols = Math.ceil(Math.sqrt(totalBeacons))
+      // console.log('totalBeacons',totalBeacons,'cols', cols)
       this.gridPositions = this.beaconDevices.reduce((acc, device, index) => {
         acc[device.id] = {
           x: (index % cols) + 1,
@@ -346,6 +441,7 @@ export default {
         }
         return acc
       }, {})
+      // console.log('this.gridPositions',this.gridPositions)  
     },
     getBeaconStyle(beacon) {
       if (!this.gridPositions) this.initGridPositions()
@@ -381,7 +477,6 @@ export default {
 .location-map {
   position: relative;
   margin: 20px 0;
-  height: 200px;
   background: #f8fafc;
   border-radius: 8px;
   padding: 20px;