From 4279049add5b532755649e46a7411bc1d31fda60 Mon Sep 17 00:00:00 2001 From: Teng <461587751@qq.com> Date: Fri, 26 Dec 2025 17:31:07 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=90=88=E5=B9=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/NursingNew/component/equipment.vue | 50 +-- pages/NursingNew/component/index.vue | 2 +- pages/NursingNew/component/nurse/index.css | 45 --- pages/NursingNew/component/nurse/index.ts | 7 - pages/NursingNew/component/nurse/index.vue | 350 +----------------- .../pleasetake/component/takehomep.vue | 2 +- 6 files changed, 23 insertions(+), 433 deletions(-) delete mode 100644 pages/NursingNew/component/nurse/index.ts diff --git a/pages/NursingNew/component/equipment.vue b/pages/NursingNew/component/equipment.vue index b437124..03e02ce 100644 --- a/pages/NursingNew/component/equipment.vue +++ b/pages/NursingNew/component/equipment.vue @@ -1,5 +1,5 @@ + /* 每个页面公共css */ + \ No newline at end of file diff --git a/common/websocket.js b/common/websocket.js new file mode 100644 index 0000000..76eec43 --- /dev/null +++ b/common/websocket.js @@ -0,0 +1,319 @@ +// common/websocket.js +// 带中文日志与消息体打印选项的 WsRequest(替换你当前文件即可) + +class WsRequest { + constructor(url = '', options = {}) { + this.url = url || ''; + this.options = Object.assign({ + header: {}, + protocols: [], + debug: true, + lang: 'zh', // 'zh' 或 'en',控制日志语言(默认中文) + showMessageBody: true, // 是否在日志中显示收到消息的完整 JSON(默认 true) + filterPing: true, // 是否过滤掉 ping/pong 日志(默认 true) + heartbeatInterval: 30000, + heartbeatTimeout: 15000, + pingMessage: { type: 'ping' }, + parseJSON: true, + maxReconnectAttempts: 10, + reconnectDelayBase: 1000, + autoConnect: false, + bindGlobal: true + }, options); + + this.socketTask = null; + this.connected = false; + this._msgQueue = []; + this.reconnectAttempts = 0; + this._lastPongAt = Date.now(); + this._hbTimer = null; + this._hbTimeoutTimer = null; + this._subscriptions = new Map(); + + if (this.options.bindGlobal) this._bindGlobalSocketEvents(); + if (this.options.autoConnect) setTimeout(() => this.open(), 0); + } + + // 内部多语言 Label + _label(key) { + const zh = { + open: '打开连接 ->', + alreadyConnected: '已连接,忽略 open', + connectNoTask: 'connectSocket 未返回 task,使用全局回调', + onOpen: '连接已打开', + onMessage: '收到消息', + onClose: '连接已关闭', + onError: '连接错误', + globalOnOpen: '全局 onSocketOpen', + globalOnMessage: '全局 onSocketMessage', + hbTimeout: '心跳超时', + reconnectScheduled: '计划重连', + sendFailed: '发送失败', + closeError: '关闭错误' + }; + const en = { + open: 'open ->', + alreadyConnected: 'already connected, ignore open', + connectNoTask: 'connectSocket returned no task (using global callbacks if available)', + onOpen: 'onOpen', + onMessage: 'onMessage', + onClose: 'onClose', + onError: 'onError', + globalOnOpen: 'global onSocketOpen', + globalOnMessage: 'global onSocketMessage', + hbTimeout: 'hb timeout', + reconnectScheduled: 'reconnect scheduled', + sendFailed: 'send failed', + closeError: 'close error' + }; + return this.options.lang === 'zh' ? zh[key] || key : en[key] || key; + } + + // 简单统一日志 + log(...args) { + if (!this.options.debug) return; + // 如果是对象,格式化输出以便控制台可读 + const out = args.map(a => { + if (typeof a === 'object') { + try { return JSON.stringify(a, null, 2); } catch (e) { return String(a); } + } + return String(a); + }).join(' '); + console.log('[WsRequest]', out); + } + + // ---------- 对外控制 ---------- + open() { + if (!this.url) { this.log(this._label('open'), this._label('noUrl') || 'no url'); return; } + if (this.connected) { this.log(this._label('alreadyConnected')); return; } + this.log(this._label('open'), this.url); + try { + const task = uni.connectSocket({ url: this.url, header: this.options.header, protocols: this.options.protocols }); + if (task && typeof task.onOpen === 'function') { + this._bindSocketTask(task); + } else { + this.log(this._label('connectNoTask')); + // 依赖全局回调,_bindGlobalSocketEvents 已经绑定则会处理 onOpen/onMessage + } + } catch (e) { + console.error(e); + } + } + + close(code = 1000, reason = 'client close') { + this._stopHeartbeat(); + try { + if (this.socketTask && typeof this.socketTask.close === 'function') { + this.socketTask.close({ code, reason }); + } else if (typeof uni.closeSocket === 'function') { + uni.closeSocket(); + } + } catch (e) { + this.log(this._label('closeError'), e); + } + this.connected = false; + } + + send(payload) { + const data = typeof payload === 'string' ? payload : JSON.stringify(payload); + if (this.socketTask && typeof this.socketTask.send === 'function' && this.connected) { + try { this.socketTask.send({ data }); return; } catch (e) { this.log(this._label('sendFailed'), e); this._msgQueue.push(data); } + } else { + try { uni.sendSocketMessage({ data }); return; } catch (e) { this._msgQueue.push(data); } + } + } + + _flushQueue() { + if (!this.connected) return; + while (this._msgQueue.length) { + const d = this._msgQueue.shift(); + try { + if (this.socketTask && typeof this.socketTask.send === 'function') { + this.socketTask.send({ data: d }); + } else { + uni.sendSocketMessage({ data: d }); + } + } catch (e) { this._msgQueue.unshift(d); break; } + } + } + + _bindSocketTask(task) { + this.socketTask = task; + if (task.__ws_bound__) return; + task.__ws_bound__ = true; + + task.onOpen(res => { + this.log(this._label('onOpen'), res); + this.connected = true; + this.reconnectAttempts = 0; + this._lastPongAt = Date.now(); + this._startHeartbeat(); + this._flushQueue(); + this.options.onOpen && this.options.onOpen(res); + }); + + task.onMessage(msg => { + this._handleIncoming(msg); + }); + + task.onClose(res => { + this.log(this._label('onClose'), res); + this.connected = false; + this._stopHeartbeat(); + this.options.onClose && this.options.onClose(res); + this._tryReconnect(); + }); + + task.onError(err => { + this.log(this._label('onError'), err); + this.connected = false; + this._stopHeartbeat(); + this.options.onError && this.options.onError(err); + this._tryReconnect(); + }); + } + + // 处理收到的消息(task 或 全局都使用) + _handleIncoming(msg) { + this._lastPongAt = Date.now(); + let data = msg && msg.data; + if (this.options.parseJSON) { + try { data = JSON.parse(msg.data); } catch (e) { /* keep raw */ } + } + const type = (data && data.type) || '__default__'; + + // 过滤 ping/pong (若你想看 ping/pong,把 filterPing 设为 false) + const isPing = data && (data.type === 'ping' || data.type === 'pong' || (typeof data === 'string' && (data === 'ping' || data === 'pong'))); + if (isPing && this.options.filterPing) { + // 仍更新 lastPong,但不打印消息体,除非 showMessageBody 强制 true + if (this.options.debug && this.options.showMessageBody === false) { + this.log(this._label('onMessage'), type); + } + } else { + // 打印消息类型与(可选)格式化消息体 + if (this.options.debug) { + if (this.options.showMessageBody) { + let bodyStr; + try { bodyStr = JSON.stringify(data, null, 2); } catch (e) { bodyStr = String(data); } + this.log(this.options.lang === 'zh' ? `${this._label('onMessage')} (${type}):` : `${this._label('onMessage')} (${type}):`, '\n' + bodyStr); + } else { + this.log(this._label('onMessage'), type); + } + } + } + + // 外部回调与订阅异步派发 + if (this.options.onMessage) setTimeout(() => this.options.onMessage(data, msg), 0); + setTimeout(() => this._dispatch(type, data, msg), 0); + } + + _bindGlobalSocketEvents() { + // 解绑默认全局再绑定,避免重复 + try { uni.offSocketOpen && uni.offSocketOpen(); } catch (e) {} + try { uni.offSocketMessage && uni.offSocketMessage(); } catch (e) {} + try { uni.offSocketClose && uni.offSocketClose(); } catch (e) {} + try { uni.offSocketError && uni.offSocketError(); } catch (e) {} + + try { + uni.onSocketOpen(res => { + this.log(this._label('globalOnOpen'), res); + this.connected = true; + this.reconnectAttempts = 0; + this._lastPongAt = Date.now(); + this._startHeartbeat(); + this._flushQueue(); + this.options.onOpen && this.options.onOpen(res); + }); + } catch (e) {} + + try { + uni.onSocketMessage(msg => { + // 全局收到消息也走统一处理 + if (this.options.debug) this.log(this._label('globalOnMessage')); + this._handleIncoming(msg); + }); + } catch (e) {} + + try { + uni.onSocketClose(res => { + this.log(this._label('globalOnClose'), res); + this.connected = false; + this._stopHeartbeat(); + this.options.onClose && this.options.onClose(res); + this._tryReconnect(); + }); + } catch (e) {} + + try { + uni.onSocketError(err => { + this.log(this._label('globalOnError'), err); + this.connected = false; + this._stopHeartbeat(); + this.options.onError && this.options.onError(err); + this._tryReconnect(); + }); + } catch (e) {} + } + + _startHeartbeat() { + this._stopHeartbeat(); + if (!this.options.heartbeatInterval) return; + const pingData = typeof this.options.pingMessage === 'string' ? this.options.pingMessage : JSON.stringify(this.options.pingMessage); + this._hbTimer = setInterval(() => { + if (!this.connected) return; + try { this.send(pingData); } catch (e) { this.log('hb send err', e); } + clearTimeout(this._hbTimeoutTimer); + this._hbTimeoutTimer = setTimeout(() => { + const since = Date.now() - this._lastPongAt; + if (since > this.options.heartbeatTimeout) { + this.log(this._label('hbTimeout'), since); + try { this.close(); } catch (e) { this.log('hb close fail', e); } + } + }, this.options.heartbeatTimeout); + }, this.options.heartbeatInterval); + } + + _stopHeartbeat() { + if (this._hbTimer) { clearInterval(this._hbTimer); this._hbTimer = null; } + if (this._hbTimeoutTimer) { clearTimeout(this._hbTimeoutTimer); this._hbTimeoutTimer = null; } + } + + _tryReconnect() { + if (this.reconnectAttempts >= this.options.maxReconnectAttempts) { this.log(this._label('reconnectScheduled'), 'exhausted'); return; } + this.reconnectAttempts++; + const delay = Math.min(this.options.reconnectDelayBase * Math.pow(1.5, this.reconnectAttempts - 1), 30000); + this.log(this._label('reconnectScheduled'), delay + 'ms', 'attempt', this.reconnectAttempts); + setTimeout(() => { + this.socketTask = null; + this.connectIfForeground(); + }, delay); + } + + connectIfForeground() { + // 如果你在项目中有前台检测,这里可改为判断前台才 open() + this.open(); + } + + subscribe(type, handler) { + if (!this._subscriptions) this._subscriptions = new Map(); + if (!this._subscriptions.has(type)) this._subscriptions.set(type, new Set()); + this._subscriptions.get(type).add(handler); + return () => this.unsubscribe(type, handler); + } + + unsubscribe(type, handler) { + if (!this._subscriptions) return; + const s = this._subscriptions.get(type); if (!s) return; s.delete(handler); + if (s.size === 0) this._subscriptions.delete(type); + } + + _dispatch(type, data, raw) { + if (!this._subscriptions) return; + const handlers = this._subscriptions.get(type); + if (handlers) for (const h of Array.from(handlers)) try { h(data, raw); } catch (e) { this.log('handler err', e); } + const def = this._subscriptions.get('__default__'); + if (def) for (const h of Array.from(def)) try { h(data, raw); } catch (e) { this.log('default handler err', e); } + } +} + +export default WsRequest; diff --git a/common/websocketManager.js b/common/websocketManager.js new file mode 100644 index 0000000..9e1c30b --- /dev/null +++ b/common/websocketManager.js @@ -0,0 +1,27 @@ +// websocketManager.js +import WsRequest from '@/common/websocket.js'; + +let globalWs = null; + +const initWs = (url, options) => { + // 如果已经有 WebSocket 实例,直接返回 + if (globalWs) return globalWs; + + globalWs = new WsRequest(url, options); + return globalWs; +}; + +const connectWs = () => { + if (globalWs) { + globalWs.reconnectAttempts = 0; // 重置重连计数 + globalWs.open(); // 打开 WebSocket 连接 + } +}; + +const closeWs = () => { + if (globalWs) { + globalWs.close(); // 关闭 WebSocket 连接 + } +}; + +export { initWs, connectWs, closeWs }; diff --git a/component/public/exit.vue b/component/public/exit.vue index 486149e..8295eb0 100644 --- a/component/public/exit.vue +++ b/component/public/exit.vue @@ -53,6 +53,7 @@ } const go = () => { uni.setStorageSync('token', 1); + uni.setStorageSync('userInfo', null); uni.redirectTo({ url: '/pages/login/login' diff --git a/main.js b/main.js index 60486b4..a3c8d2c 100644 --- a/main.js +++ b/main.js @@ -1,40 +1,32 @@ -import App from './App' -// 引入 uView UI -import uView from './uni_modules/vk-uview-ui'; - - -// #ifndef VUE3 -import Vue from 'vue' -import './uni.promisify.adaptor' -Vue.config.productionTip = false -App.mpType = 'app' -const app = new Vue({ - ...App -}) -app.$mount() -// #endif - // #ifdef VUE3 -import { - createSSRApp -} from 'vue' +import { createSSRApp } from 'vue' +import App from './App' +import uView from './uni_modules/vk-uview-ui' import donghua from '@/component/public/donghua.vue' import errorshow from '@/component/public/errorshow.vue' -import tanchuang from '@/pages/procurement/components/tanchuang.vue'; -// import arrowkeys from '@/component/public/newgame/arrowkeys.vue' -export function createApp() { - const app = createSSRApp(App) +import tanchuang from '@/pages/procurement/components/tanchuang.vue' +// import WsRequest from '@/common/websocket.js' // default 导入,文件必须有 export default - // 使用 uView UI - app.use(uView) - app.component('donghua', donghua) - app.component('tanchuang', tanchuang) - app.component('errorshow', errorshow) - - - // app.component('arrowkeys', arrowkeys) - return { - app - } +export function createApp() { + const app = createSSRApp(App) + + // // 延后创建实例(构造不会阻塞主线程) + // const websocket = new WsRequest( + // 'wss://www.focusnu.com/ws101/sdWebsocket/1942419556028956674', + // { + // debug: true, + // heartbeatInterval: 25000 + // } + // ) + + // app.config.globalProperties.$socket = websocket + // app.provide('socket', websocket) + + app.use(uView) + app.component('donghua', donghua) + app.component('tanchuang', tanchuang) + app.component('errorshow', errorshow) + + return { app } } -// #endif \ No newline at end of file +// #endif diff --git a/pages/NursingNew/component/api.js b/pages/NursingNew/component/api.js index 09c5989..b53ad20 100644 --- a/pages/NursingNew/component/api.js +++ b/pages/NursingNew/component/api.js @@ -8,7 +8,13 @@ export const electricityMeterlist = () => { method: 'get' }) } - +// 获得护理单元主页大图 +export const queryWorkCareList = (data) => { + return request({ + url: `${uni.getStorageSync('serverUrl')}/api/pad/care/queryWorkCareList?workType=${data.workType}&employeeId=${data.employeeId}&nuId=${data.nuId}`, + method: 'get' + }) +} // 智能电表设备信息清零 export const electricityMetereleReset = (cid,address) => { return request({ diff --git a/pages/NursingNew/component/equipment.vue b/pages/NursingNew/component/equipment.vue index 03e02ce..007532b 100644 --- a/pages/NursingNew/component/equipment.vue +++ b/pages/NursingNew/component/equipment.vue @@ -1453,10 +1453,10 @@ }) } // 重新刷新动画 - let donghua = typeNowtarget.value; + // let donghua = typeNowtarget.value; typeNowtarget.value = -1; setTimeout(()=>{ - typeNowtarget.value = donghua + typeNowtarget.value = 0 },500) // rightmessage.value = res.result.cameraInfoEntityList[0] diff --git a/pages/NursingNew/component/index.vue b/pages/NursingNew/component/index.vue index c8a4890..e66748e 100644 --- a/pages/NursingNew/component/index.vue +++ b/pages/NursingNew/component/index.vue @@ -100,8 +100,17 @@ :interval="120" /> - 10:00 - 10:10 - + + {{ indexmessage?.startTime.slice(11, 16) }} + - + {{ indexmessage?.endTime.slice(11, 16) }} + + + 暂无数据 + + + + 待执行 @@ -109,27 +118,27 @@ - + - - 一级压疮防护 + + {{ indexmessage?.directiveName }} - + 开始服务 - + 结束服务 - + @@ -137,7 +146,7 @@ - + - + {{ uni.getStorageSync('NUall').elderInfo?.name ? uni.getStorageSync('NUall').elderInfo?.name:`暂无长者` }} @@ -260,6 +270,7 @@ + + \ No newline at end of file diff --git a/pages/NursingNew/index.vue b/pages/NursingNew/index.vue index 1b365a3..5cf14dc 100644 --- a/pages/NursingNew/index.vue +++ b/pages/NursingNew/index.vue @@ -1,18 +1,23 @@ @@ -26,6 +31,8 @@ import { onShow } from '@dcloudio/uni-app'; import { getServiceTree, getNcPackagelist } from './component/nurse/api.js' import leftcontent from "./component/leftcontent/leftcontent.vue" + import defaultr from '@/pages/procurement/components/default.vue'; + onMounted(() => { menuIndex.value = -1; @@ -41,7 +48,6 @@ }) }) - // 通用的生成函数 function genPaths(base, prefix, count, ext = 'png', startIndex = 0, pad = false) { return Array.from({ length: count }, (_, i) => { @@ -52,27 +58,30 @@ }) } const tabbrarr = ref([ - {name:'首页',url:'/static/shouye/sy/h0.png',urls:'/static/shouye/sy/h1.png'}, - {name:'护嘱',url:'/static/shouye/sy/n0.png',urls:'/static/shouye/sy/n1.png'}, - {name:'医嘱',url:'/static/shouye/sy/y0.png',urls:'/static/shouye/sy/y1.png'}, - {name:'后勤',url:'/static/shouye/sy/l0.png',urls:'/static/shouye/sy/l1.png'}, - {name:'物联',url:'/static/shouye/sy/g0.png',urls:'/static/shouye/sy/g1.png'}, - {name:'返回',url:'/static/shouye/sy/f0.png',urls:'/static/shouye/sy/f1.png'}, + { name: '首页', url: '/static/shouye/sy/h0.png', urls: '/static/shouye/sy/h1.png' }, + { name: '护嘱', url: '/static/shouye/sy/n0.png', urls: '/static/shouye/sy/n1.png' }, + { name: '医嘱', url: '/static/shouye/sy/y0.png', urls: '/static/shouye/sy/y1.png' }, + { name: '后勤', url: '/static/shouye/sy/l0.png', urls: '/static/shouye/sy/l1.png' }, + { name: '物联', url: '/static/shouye/sy/g0.png', urls: '/static/shouye/sy/g1.png' }, + { name: '返回', url: '/static/shouye/sy/f0.png', urls: '/static/shouye/sy/f1.png' }, ]) - const navurl =(e)=>{ + const navurl = (e) => { changeMenu(e) } - // 当前选中的菜单索引 const menuIndex = ref(-1); const menuIndexshow = ref(false); const menuIndexshowsecond = ref(false); const menuIndexshowfourth = ref(false); const menuIndexshowfifth = ref(false); + const messageopit = ref(false); // 变更菜单 const changeMenu = (index : number) => { + if (index === menuIndex.value) { + return + } menuIndex.value = index; menuIndexshow.value = false menuIndexshowsecond.value = false @@ -89,7 +98,11 @@ break; case 1: menuIndexshowsecond.value = true + nomesssageshow() + break; + case 2: + nomesssageshow() break; case 3: menuIndexshowfourth.value = true @@ -121,12 +134,15 @@ }); - - + const nomesssageshow = () => { + messageopit.value = false; + setTimeout(() => { + messageopit.value = true; + }, 200) + } \ No newline at end of file diff --git a/pages/Warehouse/index/component/index.vue b/pages/Warehouse/index/component/index.vue index 9f9da56..2759e79 100644 --- a/pages/Warehouse/index/component/index.vue +++ b/pages/Warehouse/index/component/index.vue @@ -36,7 +36,7 @@ - + @@ -568,6 +568,7 @@ .big-img { width: 550rpx; height: 550rpx; + z-index: 2; } .server-name { diff --git a/pages/login/login.vue b/pages/login/login.vue index fe9737d..36d0ebe 100644 --- a/pages/login/login.vue +++ b/pages/login/login.vue @@ -150,6 +150,7 @@ import twoseven from '@/pages/login/twoseven.vue' import { isRel, getLoginCode, loginApp } from './api.js' import huakuai from '@/component/public/huakuai.vue' + import { initWs, connectWs } from '@/common/websocketManager.js'; const zyupgrade = ref(null); const isTarget = ref(false); @@ -202,18 +203,18 @@ const getImg = () => { if (/^\d{11}$/.test(form.username)) { isRel(form.username).then((res : any) => { - console.log("啥啊",res) + console.log("啥啊", res) if (res.result.code == `0`) { uni.setStorageSync('serverUrl', res.result.orgList[0].serverUrl); uni.setStorageSync('orgList', res.result.orgList); uni.setStorageSync('orgListName', res.result.orgList[0].departName); uni.setStorageSync('orgListCode', res.result.orgList[0].orgCode); - + allserve.value = res.result.orgList time.value = Date.now(); getLoginCode(time.value).then((res : any) => { - console.log("啥啊",res) + console.log("啥啊", res) form.captcha = res.message canclick.value = true }) @@ -367,6 +368,14 @@ }) } const gotoindex = () => { + if (uni.getStorageSync('userInfo')) { + initWs(`wss://www.focusnu.com/ws101/sdWebsocket/${uni.getStorageSync('userInfo').employessId}`, { + debug: true, + heartbeatInterval: 25000, + autoConnect: false, // 不自动连接 + }); + connectWs(); // 主动连接 WebSocket + } jumpTo(`/pages/login/animationpage`) } diff --git a/request/index.js b/request/index.js index af36782..0d0eb1c 100644 --- a/request/index.js +++ b/request/index.js @@ -1,6 +1,7 @@ // 全局请求封装 -// const base_url = 'https://www.focusnu.com/opeapi' -const base_url = 'http://192.168.2.37:8081/opeapi' +const base_url = 'https://www.focusnu.com/opeapi' +// const base_url = 'http://192.168.2.37:8081/opeapi' +// const base_url = 'http://192.168.2.27:8091/opeapi' // const base_url = 'http://localhost:8091/opeapi' // 请求超出时间 const timeout = 5000 diff --git a/static/index/newruler/watch.png b/static/index/newruler/watch.png new file mode 100644 index 0000000000000000000000000000000000000000..3104114ba9fbd13bff3f0be1127ffdb03ff33038 GIT binary patch literal 2796 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 X7hmMI5m!9~_7%XH+hds+pPT;$-6|lo literal 0 HcmV?d00001