1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333 |
- <!DOCTYPE html>
- <html lang="">
- <head>
- <meta charset="utf-8">
- <title></title>
- <link href="assets/css/common.css" rel="stylesheet" type="text/css" />
- <link href="assets/css/style.css" rel="stylesheet" type="text/css" />
- <link href="assets/css/element-ui.css" rel="stylesheet" type="text/css" />
- <script type="text/javascript" src="assets/js/base.js"></script>
- </head>
- <body>
- <div id="app">
- <!-- 左边 -->
- <div v-if="sleepReportFrom.report_content" class="l-con" id="l-con">
- <div class="l-con-scroll">
- <!-- 当前用户 -->
- <div class="max-title">
- <span>睡眠报告</span>
- <ul>
- <li class="cur">{{ myFullName }}</li>
- <li>{{ myNickName }}</li>
- </ul>
- </div>
- <!-- 睡眠评分 -->
- <div v-if="sleepReportFrom.report_content" class="item-1">
- <div class="item-1-setting">
- <div class="set-time">
- <div class="in1">
- <el-date-picker v-model="selectDay" type="date" placeholder="选择日期" :clearable="false"
- @change="changeDate" @focus="isShow($event)" :picker-options="pickerOptions"></el-date-picker>
- </div>
- <div class="in2">
- <el-select v-model="selectIndex" placeholder="请选择" @change="pickerChange">
- <el-option v-for="(item,index) in todayTimeList" :key="'t'+index" :label="item.name"
- :value="item.id"></el-option>
- </el-select>
- </div>
- </div>
- <div class="score">
- <span>{{ sleepReportFrom.score_desc }}</span>
- <b v-bind:class="sleepReportFrom.report_content.score.state >= 3 ?
- 'text-green' : sleepReportFrom.report_content.score.state === 2 ? 'text-yellow' : 'text-red'">{{
- sleepReportFrom.score_value }}</b>
- <p>香睡指数</p>
- </div>
- </div>
- <!-- <div class="tip">+25</div>-->
- <div class="sleep-time">
- <div class="duration">
- <img src="assets/image/time_ico1.png" alt="">
- <span>睡眠总时长</span>
- <p>
- {{ formateSeconds(sleepReportFrom.total_duration, 0) }}
- </p>
- </div>
- <div class="hour">
- <img src="assets/image/time_ico2.png" alt="">
- <span>睡眠时间</span>
- <p>{{ sleepReportFrom.gobed_time + '~' + sleepReportFrom.outbed_time }}</p>
- </div>
- </div>
- </div>
- <!-- 各项睡眠监测数据统计 -->
- <div v-if="sleepReportFrom.report_content" class="item-2">
- <div class="count">
- <div class="title">各项睡眠监测数据统计</div>
- <ul>
- <li class="green">
- <span>上床时间</span>
- <p><b>{{ sleepReportFrom.gobed_time }}</b></p>
- </li>
- <li class="green">
- <span>在床时间</span>
- <p>{{ formateSeconds(sleepReportFrom.inbed_duration, 0) }}</p>
- </li>
- <li class="green">
- <span>深睡时长</span>
- <p><b>{{ formateSeconds(sleepReportFrom.deep_duration, 0) }}</b></p>
- </li>
- <li v-bind:class="sleepReportFrom.report_content.sleep_eff.state === 3 ? 'green' :
- sleepReportFrom.report_content.sleep_eff.state === 2 ? 'yellow' : 'red'">
- <span>睡眠效率</span>
- <p>{{ sleepReportFrom.report_content.sleep_eff.value }}</p>
- </li>
- <li v-bind:class="sleepReportFrom.report_content.avg_rh.state === 3 ? 'green' :
- sleepReportFrom.report_content.avg_rh.state === 2 ? 'yellow' : 'red'">
- <span>平均心率</span>
- <p><b>{{ sleepReportFrom.report_content.avg_rh.value }}</b>次/分</p>
- </li>
- <li v-bind:class="sleepReportFrom.report_content.avg_hx.state === 3 ? 'green' :
- sleepReportFrom.report_content.avg_hx.state === 2 ? 'yellow' : 'red'">
- <span>平均呼吸率</span>
- <p><b>{{ sleepReportFrom.report_content.avg_hx.value }}</b>次/分</p>
- </li>
- <li class="tip red">
- <span>温馨提示</span>
- <p><b>本次睡眠,您有{{ errCount }}项指标不及格。</b></p>
- </li>
- <li class="small" v-bind:class="sleepReportFrom.report_content.move_count.state === 3 ? 'green' :
- sleepReportFrom.report_content.move_count.state === 2 ? 'yellow' : 'red'">
- <span>体动次数<b style="float: right;color: white;margin-right: 10px;font-size: 12px">{{
- sleepReportFrom.report_content.move_count.value }}次</b></span>
- </li>
- <li class="small" v-bind:class="sleepReportFrom.report_content.snoring_count.state === 3 ? 'green' :
- sleepReportFrom.report_content.snoring_count.state === 2 ? 'yellow' : 'red'">
- <span>打鼾次数<b style="float: right;color: white;margin-right: 10px;font-size: 12px">{{
- sleepReportFrom.report_content.snoring_count.value }}次</b></span>
- </li>
- <li class="small" v-bind:class="sleepReportFrom.report_content.outbed_count.state === 3 ? 'green' :
- sleepReportFrom.report_content.outbed_count.state === 2 ? 'yellow' : 'red'">
- <span>离床次数<b style="float: right;color: white;margin-right: 10px;font-size: 12px">{{
- sleepReportFrom.report_content.outbed_count.value }}次</b></span>
- </li>
- </ul>
- </div>
- <div class="efficiency">
- <span>睡眠效率</span>
- <p>{{ sleepReportFrom.report_content.sleep_eff.value }}</p>
- </div>
- <div class="stability">
- <span>安稳度</span>
- <div class="sta-r">
- <em>入睡时长</em>
- <p>{{ formateSeconds(sleepReportFrom.rs_duration, 0) }}</p>
- </div>
- </div>
- </div>
- <!-- 离床次数 -->
- <div class="item-3">
- <div class="leave">
- <span>离床次数</span>
- <p><b>{{ sleepReportFrom.report_content.outbed_count.value }}</b>次</p>
- </div>
- <div id="leave-report" style="height:200px;"></div>
- </div>
- <!-- 体动次数 -->
- <div class="item-4">
- <div class="movement">
- <span>体动次数</span>
- <p><b>{{ sleepReportFrom.report_content.move_count.value }}</b>次</p>
- </div>
- <div id="movement-report" style="height:200px;"></div>
- </div>
- <!-- 心脏系统 -->
- <div class="item-5">
- <div class="heart">
- <span>心脏系统</span>
- </div>
- <div class="heart-info">
- <span>心率</span>
- <em>平均心率</em>
- <p><b>{{ sleepReportFrom.report_content.avg_rh.value }}</b>次/分</p>
- </div>
- <div id="heart-report" style="height:200px;"></div>
- </div>
- <!-- 呼吸系统 -->
- <div class="item-6">
- <div class="breathe">
- <span>呼吸系统</span>
- </div>
- <div class="breathe-info">
- <span>呼吸率</span>
- <em>平均呼吸率</em>
- <p><b>{{ sleepReportFrom.report_content.avg_hx.value }}</b>次/分</p>
- </div>
- <div id="breathe-report" style="height:200px;"></div>
- <div class="breathe-info">
- <span class="cur">打鼾</span>
- <p><b>{{ sleepReportFrom.report_content.snoring_count.value }}</b>次</p>
- </div>
- <div id="snore-report" style="height:200px;"></div>
- <div class="breathe-info">
- <span class="cur">呼吸暂停</span>
- <!-- <p><b>0</b>次</p>-->
- </div>
- <div id="suspend-report" style="height:200px;"></div>
- <!-- <div class="warn">-->
- <!-- <span>风险</span>-->
- <!-- <p>本次睡眠,您有1项指标不及格。</p>-->
- <!-- </div>-->
- </div>
- <!-- 深浅睡眠 -->
- <div class="item-7">
- <div class="depth">
- <span>深浅睡眠</span>
- </div>
- <div class="depth-info">
- <ul>
- <li>
- <span>清醒</span>
- {{ formateSeconds(sleepReportFrom.awake_duration, 1) }}
- </li>
- <li>
- <span>浅睡</span>
- {{ formateSeconds(sleepReportFrom.light_duration, 1) }}
- </li>
- <li>
- <span>中睡</span>
- {{ formateSeconds(sleepReportFrom.in_duration, 1) }}
- </li>
- <li>
- <span>深睡</span>
- {{ formateSeconds(sleepReportFrom.deep_duration, 1) }}
- </li>
- </ul>
- </div>
- <div id="depth-report" style="height:200px;"></div>
- </div>
- </div>
- </div>
- <div v-else class="l-con">
- <div class="l-con-scroll image-wrapper_2">
- <!-- <p style="text-align: center;margin-top: 100px;color: white">暂无数据</p>-->
- </div>
- </div>
- <!-- 左边 -->
- <!-- 中间 -->
- <div class="c-con">
- <div class="title">{{centerTit}}
- <el-link v-if="boolCheck" style="margin-left: 10px" type="primary" @click="drawer = true">切换代理</el-link>
- </div>
- <div class="state">
- <ul>
- <li>
- <span>共计</span>
- {{ frameList.length }}床
- </li>
- <li>
- <span>使用</span>
- {{ countFrom.used }}床
- </li>
- <li>
- <span>空余</span>
- {{ frameList.length - countFrom.used }}床
- </li>
- <li>
- <span>在床</span>
- {{ countFrom.inBed }}人
- </li>
- <li>
- <span>离床</span>
- {{ frameList.length - countFrom.inBed }}人
- </li>
- </ul>
- </div>
- <div class="list">
- <dl v-for="(item, index) in frameList" :key="'i'+index" v-bind:class="[getStatusClass(item)]"
- @click="changeLookBed(item)">
- <dt>
- <span>{{ item.full_name }}</span>
- </dt>
- <dd>
- <div class="list-l">
- <span v-if="item.nickname">{{ formartName(item.nickname) }}</span>
- <span v-else style="color: #FF9650">空置</span>
- <em>{{ getTimeByImei(item.imei) }}</em>
- </div>
- <div class="list-r">
- <p class="list-r-p1">
- <span>{{ item.heart ? item.heart : '--' }}</span>
- <b>心率</b>
- </p>
- <p class="list-r-p2">
- <span>{{ item.breathe ? item.breathe : '--' }}</span>
- <!-- <b>呼吸率</b>-->
- <b>呼吸</b>
- </p>
- </div>
- </dd>
- </dl>
- <!-- <dl class="offline warn">-->
- <!-- <dt>-->
- <!-- <span>02房01床</span>-->
- <!-- </dt>-->
- <!-- <dd>-->
- <!-- <div class="list-l">-->
- <!-- <span>王娟</span>-->
- <!-- <em>20:37</em>-->
- <!-- </div>-->
- <!-- <div class="list-r">-->
- <!-- <p class="list-r-p1">-->
- <!-- <span class="red">128</span>-->
- <!-- <b>心率</b>-->
- <!-- </p>-->
- <!-- <p class="list-r-p2">-->
- <!-- <span>18</span>-->
- <!-- <b>呼吸率</b>-->
- <!-- </p>-->
- <!-- </div>-->
- <!-- </dd>-->
- <!-- </dl>-->
- </div>
- </div>
- <!-- 中间 -->
- <!-- 右边 -->
- <div class="r-con" id="r-con">
- <!-- 报警 -->
- <div class="warn">
- <div class="title">实时报警</div>
- <!-- <div class="dddd"></div> -->
- <div class="state">
- <a>心率异常</a>
- <a>呼吸异常</a>
- <a>疑似呼吸暂停</a>
- <a>疑似生命异常</a>
- <a>紧急求助</a>
- <a>离线</a>
- <a>离床</a>
- </div>
- <div class="panel">
- <ul>
- <li v-for="(item, index) in warnList" :key="'w'+index" v-bind:class="[item.warn_class]">
- <span>{{ item.named }}</span>
- {{ item.warn_time }}
- </li>
- <li v-for="(item, index) in todayWarnLogs" :key="'e'+index" v-bind:class="[item.warn_class]">
- <span>{{ item.named }}</span>
- {{ item.warn_time }}
- </li>
- </ul>
- </div>
- </div>
- <!-- 昨天睡眠 -->
- <div class="yesterday-sleep">
- <div class="title">昨天睡眠报告分析</div>
- <div id="yesterday-sleep-report" style="height:300px;margin:20px 0 0 0;"></div>
- </div>
- <!-- 昨天告警 -->
- <div class="yesterday-warn">
- <div class="title">昨天告警情况</div>
- <div id="yesterday-warn-report" style="height:300px;margin:20px 0 0 0;"></div>
- </div>
- </div>
- <!-- 右边 -->
- <!-- 切换代理-->
- <el-drawer title="切换代理" :visible.sync="drawer">
- <div style="margin: 10px">
- <el-button style="margin: 10px" icon="el-icon-search" size="mini"
- @click="onLook(shopInfo.shop_id)">查看自己</el-button>
- <el-input placeholder="输入关键字进行过滤" v-model="filterText"></el-input>
- <el-tree class="filter-tree" :data="agentList" default-expand-all :filter-node-method="filterNode" ref="tree">
- <span slot-scope="{ node, data }" class="custom-tree-node">
- <el-tooltip :content="data.shop_name" :open-delay="300" placement="top" effect="dark">
- <span class="over-ellipsis">{{ data.shop_name }}</span>
- </el-tooltip>
- <span class="top-right">
- <el-tooltip content="查看" :open-delay="300" placement="top" effect="dark">
- <el-button type="text" size="mini" icon="el-icon-search"
- @click.stop="() => onLook(data.shop_id)"></el-button>
- </el-tooltip>
- </span>
- </span>
- </el-tree>
- </div>
- </el-drawer>
- <!-- 切换代理-->
- </div>
- <script type="text/javascript">
- // import autofit from './node_modules/autofit.js'
- //vue挂载
- const app = new Vue({
- el: "#app",
- data: {
- centerTit: '守护之影睡眠监测系统',
- myWebsocket: null,
- connected: false,
- connecting: false,
- timer: null,
- alwaysTimer: null,
- breakTimer: null,
- frameList: [],
- mySns: '',
- closed: false,
- shopId: null,
- countFrom: {
- used: 0,
- inBed: 0
- },
- bedTimeData: [], // 在床、离床时间数据
- nowDate: '',
- warnList: [], // 告警列表
- todayWarnLogs: [], // 进入告警列表
- sleepReportFrom: {
- total_duration: 0,
- inbed_duration: 0,
- deep_duration: 0,
- rs_duration: 0
- },
- sleepReportList: [],
- todayTimeList: [],
- errCount: 0,
- selectDay: '',
- pickerOptions: {},
- selected: [],
- selectYearMonth: {
- year: '',
- month: ''
- },
- params: {
- sn: '',
- reportTime: -1
- },
- setClick: false,
- selectIndex: 0,
- myFullName: '',
- myNickName: '',
- code: null, // 看板设置唯一码
- shopInfo: null,
- drawer: false,
- agentList: [], // 代理列表
- filterText: '',
- defaultProps: {
- children: 'children',
- label: 'label'
- },
- serverUrl: null,
- boolCheck: false,
- boolAgent: false
- },
- watch: {
- filterText(val) {
- this.$refs.tree.filter(val);
- }
- },
- mounted() {
- autofit.init({
- dh: 1080,
- dw: 1920,
- el: "body",
- resize: true
- })
- this.pickerOptions = {
- disabledDate(time) {
- return time.getTime() > Date.now();
- },
- cellClassName: (time) => {
- if (this.selected.includes(this.unixToDate2(time / 1000, "yyyy-MM-dd"))) {
- return 'badge'
- }
- }
- }
- this.code = this.getUrlQuery("code")
- if (!this.shopId && !this.code) {
- this.$message.error('机构参数错误,请联系管理员')
- return
- }
- const now = new Date().setHours(0, 0, 0, 0)
- this.nowDate = new Date(now)
- this.API_GetSetting()
- // 左右自动上下轮播
- // const lcon = document.getElementById('l-con');
- // this.autoScroll(300, 5000, 5000, lcon);
- // 获取床位设备列表
- },
- methods: {
- API_GetSetting() {
- const _this = this
- get("/bulletin_board_mattress/get_setting_by_code/" + this.code).then(res => {
- // console.log('res======', res)
- if (res) {
- this.serverUrl = 'http://' + res.server_url
- this.shopId = res.shop_id
- this.API_GetShopInfo()
- if (baseUrl.indexOf(res.server_url) > -1) {
- console.log('------------------------')
- _this.boolAgent = true
- }
- } else {
- _this.$message.error('看板参数不正确,请确定')
- }
- }).catch(err => {
- console.log('err====', err)
- })
- },
- API_GetShopInfo() {
- const _this = this
- const url = this.serverUrl + '/bulletin_board_mattress/get_shop_by_id/' + this.shopId
- get(url).then(res => {
- // console.log('res======', res)
- if (res) {
- this.shopInfo = res
- this.centerTit = res.shop_name + '睡眠监测看板'
- this.API_GetFrameList()
- setInterval(() => {
- console.log('刷新一次')
- _this.API_GetFrameList()
- setTimeout(() => {
- console.log('刷新一次11111111')
- _this.mySns = ''
- _this.sendSns()
- }, 5000)
- }, 60000 * 60) // 一个小时刷新一次
- if (this.shopInfo.shop_type === '4' || this.shopInfo.shop_type === '6') {
- _this.boolCheck = true
- _this.API_GetAgentList()
- }
- } else {
- _this.$message.error('机构参数不正确,请确定')
- }
- }).catch(err => {
- console.log('err====', err)
- })
- },
- API_GetFrameList() {
- const url = this.serverUrl + '/bulletin_board_mattress/get_mattress_info/' + this.shopId
- get(url).then(res => {
- console.log('res======', res)
- this.frameList = res
- if (res.length === 0) {
- this.sendSns()
- this.countFrom = {
- used: 0,
- inBed: 0
- }
- } else {
- this.countFrom.used = res.filter(item => item.nickname).length
- this.sendSns()
- // websocket连接
- this.initWebSocket()
- this.changeLookBed(res[0])
- }
- }).catch(err => {
- console.log('err====', err)
- })
- },
- initWebSocket: function () {
- if (this.connected || this.connecting) {
- console.log('webSocket已连接或者正在连接')
- return
- }
- this.connecting = true
- let time = Math.round(new Date()) + "" + Math.round(Math.random() * 100);
- console.log(time)
- let wsUrl = baseUrl.replace('http', 'ws')
- this.myWebsocket = new WebSocket(wsUrl + '/sleep_report/monitor/' + time)
- this.myWebsocket.onopen = this.websocketOnopen
- this.myWebsocket.onerror = this.websocketOnerror
- this.myWebsocket.onmessage = this.websocketOnmessage
- this.myWebsocket.onclose = this.websocketClose
- },
- websocketOnopen: function () {
- console.log('webSocket连接成功...')
- this.connecting = false
- this.connected = true
- // 清理重连定时器
- clearInterval(this.breakTimer)
- this.breakTimer = null
- // 心跳
- let _this = this
- this.timer = setInterval(function () { //每隔60秒钟发送一次心跳,避免websocket连接因超时而自动断开
- _this.myWebsocket.send('ping')
- // 监测床垫掉线
- _this.frameList.forEach(item => {
- item.boolOnline = false
- })
- setTimeout(function () {
- _this.frameList.forEach(item => {
- if (!item.boolOnline) {
- item.status = ''
- const i = _this.bedTimeData.findIndex(t => t.imei === item.imei)
- if (i !== -1) {
- // 修改离床状态
- _this.bedTimeData.splice(i, 1)
- if (_this.countFrom.inBed > 0) {
- _this.countFrom.inBed--
- }
- }
- // 修改心率与呼吸率
- item.heart = 0
- item.breathe = 0
- }
- })
- }, 5000)
- }, 55000) // 60秒的心跳包
- // this.alwaysTimer = setInterval(function () { // 监测床垫掉线
- // }, 30000)
- // 发送设备列表
- this.sendSns()
- },
- websocketOnerror: function (e) {
- console.log('webSocket连接失败...')
- this.connecting = false
- this.connected = false
- },
- websocketOnmessage: function (e) {
- // console.log('收到消息:', e)
- let msg = e.data
- // console.log('收到消息:', msg)
- switch (msg.length) {
- case 1:
- // 判断是否连接
- this.isConnect = true
- break
- case 234:
- const imei = msg.substring(2, 14)
- // 实时睡眠数据
- let index = this.frameList.findIndex(item => item.imei === imei)
- if (index === -1) {
- return
- }
- this.frameList[index].boolOnline = true
- this.frameList[index].heart = parseInt(msg.substring(22, 24), 16)
- this.frameList[index].breathe = parseInt(msg.substring(24, 26), 16)
- switch (msg.substring(26, 28)) {
- case "04": // 离床
- this.frameList[index].status = '离床'
- this.setBedTimeData(imei, false)
- break;
- case "03":
- case "05":
- case "06":
- this.frameList[index].status = '在床'
- this.setBedTimeData(imei, true)
- break;
- default:
- break;
- }
- break
- default: // 报警信息
- const data = JSON.parse(e.data)
- let i = this.frameList.findIndex(item => item.imei === data.sn)
- if (i === -1) {
- return
- }
- // this.warnList.push(data)
- this.$set(this.frameList[i], 'boolWarn', true)
- setTimeout(() => {
- this.$set(this.frameList[i], 'boolWarn', false)
- }, 10000) // 10秒后恢复正常
- this.setWarnData(data, !this.boolAgent ? this.frameList[i].full_name : this.frameList[i].nickname)
- break
- }
- },
- websocketClose: function (e) {
- console.log('connection closed (' + e.code + ')', ' 连接断开...')
- const _this = this
- this.connected = false
- this.closed = true
- // 清理心跳定时器
- clearInterval(this.timer)
- clearInterval(this.alwaysTimer)
- this.timer = null
- this.alwaysTimer = null
- if (!this.breakTimer) {
- this.breakTimer = setInterval(function () {
- console.log('正在重连...')
- _this.initWebSocket();
- }, 15000); // 5秒重连一次
- }
- },
- // 获取睡眠报告
- API_GetSleepReport() {
- const _this = this
- this.todayTimeList = []
- post("/bulletin_board_mattress/get_new_report_by_sn", this.params).then(res => {
- let size = 0, i = 0
- if (res.data.length > 0) {
- res.data.forEach((item, index) => {
- if (item.total_duration > size) {
- size = item.total_duration
- i = index
- _this.selectIndex = i
- }
- _this.todayTimeList.push({name: item.gobed_time + '~' + item.outbed_time, id: index})
- })
- _this.sleepReportFrom = Object.assign({}, res.data[i])
- _this.sleepReportFrom.report_content = JSON.parse(_this.sleepReportFrom.report_content)
- _this.selectDay = _this.unixToDate2(_this.sleepReportFrom.report_time, "yyyy-MM-dd")
- _this.sleepReportList = res.data
- if (_this.params.reportTime === -1) {
- let str = _this.selectDay.split("-")
- _this.selectYearMonth.year = str[0]
- _this.selectYearMonth.month = str[1]
- _this.getDaysTag()
- }
- _this.qualifiedCount(_this.sleepReportFrom.report_content)
- _this.initAllChar(_this.sleepReportFrom)
- } else {
- this.myFullName = ''
- this.myNickName = ''
- this.$message({
- message: '暂无睡眠报告',
- type: 'warning'
- })
- }
- }).catch(err => {
- console.log('err====', err)
- })
- },
- // 获取日期点
- getDaysTag() {
- post("/bulletin_board_mattress/get_sleep_report_days_tag_by_sn", this.selectYearMonth).then(res => {
- this.selected = []
- res.data.forEach(p => {
- this.selected.push(this.selectYearMonth.year + '-' + this.selectYearMonth.month + '-' + p.flog_time)
- })
- }).catch(err => {
- console.log('err====', err)
- })
- },
- // 发送webSocket设备列表
- sendSns() {
- if (this.connected) {
- if (this.frameList.length > 0) {
- let sns = []
- this.frameList.forEach(item => {
- if (item.imei) {
- sns.push(item.imei)
- }
- })
- if (sns.length === 0) {
- return
- }
- const data = sns.join(',')
- if (!this.mySns) {
- this.mySns = data
- } else {
- if (data === this.mySns && !this.closed) {
- return
- } else {
- this.closed = false
- this.mySns = data
- }
- }
- console.log('发送imei给服务器...', data)
- this.myWebsocket.send(data)
- this.API_GetRightData()
- } else {
- this.mySns = ''
- this.myWebsocket.send('')
- }
- }
- },
- // 获取看板右边数据
- API_GetRightData() {
- const params = {
- sns: this.mySns,
- time: this.nowDate.getTime() / 1000
- }
- post("/bulletin_board_mattress/get_right_data", params).then(res => {
- // 实时报警数据(进入报警)
- if (res.data.todayWarnLogs) {
- res.data.todayWarnLogs.forEach(item => {
- let i = this.frameList.findIndex(t => t.imei === item.sn)
- if (i !== -1) {
- item.named = !this.boolAgent ? this.frameList[i].full_name : this.frameList[i].nickname
- }
- const now = new Date(item.warn_time * 1000)
- item.warn_time = `${now.getHours()}:${now.getMinutes()}`
- switch (item.warn_type) {
- case 0:
- item.warn_class = 'jj'
- break
- case 1:
- item.warn_class = 'xl'
- break
- case 3:
- item.warn_class = 'hx'
- break
- case 4:
- item.warn_class = 'lc'
- break
- default:
- break
- }
- })
- this.todayWarnLogs = res.data.todayWarnLogs
- }
- // 昨天睡眠报表
- if (res.data.yesterdayReportChar) {
- let count = 0
- res.data.yesterdayReportChar.forEach(item => {
- count += parseInt(item.value)
- })
- this.setPieData('yesterday-sleep-report', count, res.data.yesterdayReportChar, ['#4085F7', '#53B389', '#D09464', '#D1D075'], '份')
- }
- // 昨天告警报表
- if (res.data.yesterdayWarnChar) {
- let count = 0
- res.data.yesterdayWarnChar.forEach(item => {
- count += parseInt(item.value)
- switch (item.name) {
- case '0':
- item.name = '紧急呼叫'
- break;
- case '1':
- item.name = '心率异常'
- break
- case '2':
- item.name = '呼吸异常'
- break
- case '3':
- item.name = '长时离床'
- break
- default:
- break;
- }
- })
- this.setPieData('yesterday-warn-report', count, res.data.yesterdayWarnChar, ['#972AF0', '#A66B55', '#119EEE', '#A5317E'], '次')
- }
- }).catch(err => {
- console.log('err====', err)
- })
- },
- /*
- * stepLength:一次滚动步长
- * speed:滚动速度
- * delay:停留时间
- * element:Element对象
- * element.offsetHeight 元素的像素高度(包括边框和填充)
- * element.scrollTop 元素的内容垂直滚动的像素
- * element.scrollHeight 元素的高度(包括带滚动条的隐蔽的地方)
- */
- autoScroll: function (stepLength, speed, delay, element) {
- let interval
- //let step = 1
- element.scrollTop = 0
- function start() {
- interval = setInterval(scrolling, speed)
- element.scrollTop += stepLength
- }
- function scrolling() {
- var sTop = element.scrollTop;
- element.scrollTop += stepLength;
- if (sTop === element.scrollTop || sTop == 0 || element.scrollTop === (element.scrollHeight - element
- .offsetHeight)) {
- stepLength *= -1 // 转换方向
- clearInterval(interval)
- setTimeout(start, delay)
- }
- }
- if (element.offsetHeight !== element.scrollHeight) { // 元素内容没有溢出时,不触发
- setTimeout(start, delay)
- }
- },
- // 计算睡眠不及格项
- qualifiedCount(data) {
- let count = 0
- if (data.avg_hx.state === 1) {
- count++
- } else if (data.sleep_eff.state === 1) {
- count++
- } else if (data.avg_rh.state === 1) {
- count++
- } else if (data.move_count.state === 1) {
- count++
- } else if (data.outbed_count.state === 1) {
- count++
- } else if (data.snoring_count.state === 1) {
- count++
- }
- this.errCount = count
- },
- initAllChar(data) {
- const _this = this
- setTimeout(() => {
- _this.setLineChart("leave-report", 1, data.report_content.dt_arr, data.report_content.outbed_arr)
- _this.setLineChart("movement-report", 2, data.report_content.dt_arr, data.report_content.move_arr)
- _this.setLineChart("heart-report", 3, data.report_content.dt_arr, data.report_content.rh_arr)
- _this.setLineChart("breathe-report", 4, data.report_content.dt_arr, data.report_content.hx_arr)
- _this.setLineChart("snore-report", 0, data.report_content.dt_arr, data.report_content.snoring_arr)
- _this.setLineChart("suspend-report", 6, data.report_content.dt_arr, data.report_content.hxstop_arr)
- _this.setLineChart("depth-report", -1, data.report_content.dt_arr, data.report_content.sleep_arr)
- }, 800)
- },
- // 组装折线图表
- setLineChart(refChar, type, xData, yData) {
- let options = Object.assign(this.getLineOptions(xData, yData), {})
- let myPieChart = echarts.init(document.getElementById(refChar))
- if (type <= 2) {
- options.yAxis = this.getLineYAxis1(type)
- } else {
- options.yAxis = this.getLineYAxis2()
- }
- if (type === -1) {
- options.series[0].areaStyle = {}
- }
- myPieChart.setOption(options)
- },
- // 获取折线图配置
- getLineOptions(xData, yData) {
- return {
- grid: {
- top: 30,
- right: 10,
- left: 40
- },
- xAxis: {
- type: 'category',
- data: xData,
- axisLine: {
- lineStyle: {
- color: "#323C77", //最左侧x轴颜色
- }
- },
- splitLine: {
- show: true,
- lineStyle: {
- color: "#323C77"
- }
- },
- axisLabel: {
- fontSize: 9,
- color: "#A5B6CA"
- }
- },
- yAxis: {},
- series: [
- {
- data: yData,
- type: 'line',
- smooth: true,
- showSymbol: false,
- hoverAnimation: false
- }
- ]
- }
- },
- getLineYAxis1(type) {
- let min = 0, max = 1
- if (type === -1) {
- min = 0
- max = 'dataMax'
- }
- return {
- type: 'value',
- // boundaryGap: [0, '100%'],
- min: min,
- max: max, // dataMax取数据在该轴上的最大值作为最大刻度
- splitNumber: 4,
- minInterval: 1,
- splitLine: {
- show: false, // 是否显示分隔线
- },
- axisLine: {
- show: true, // 是否显示坐标轴轴线
- lineStyle: {
- color: '#FFFFFF',
- width: 0.5, //x轴线的宽度
- }
- },
- axisLabel: {
- formatter: function (value) {
- switch (type) {
- case -1:
- let str = ''
- switch (value) {
- case 0:
- str = '清醒'
- break
- case 10:
- str = '浅睡'
- break
- case 20:
- str = '中睡'
- break
- case 30:
- str = '深睡'
- break
- default:
- break
- }
- return str
- case 0:
- return value === 0 ? '睡眠' : '打鼾'
- case 1:
- return value === 0 ? '离床' : '在床'
- case 2:
- return value === 0 ? '睡眠' : '体动'
- default:
- return value
- }
- }
- }
- }
- },
- getLineYAxis2() {
- return {
- type: 'value',
- boundaryGap: [0, '100%'],
- min: 0,
- max: 'dataMax', // 取数据在该轴上的最大值作为最大刻度
- splitLine: {
- show: false, // 是否显示分隔线
- },
- axisLine: {
- show: false, // 是否显示坐标轴轴线
- lineStyle: {
- color: '#FFFFFF'
- }
- }
- }
- },
- // 组装饼状图
- setPieData(refChar, count, data, color, unit) {
- let options = Object.assign(this.getPieOptions(count, data, color, unit), {})
- let myPieChart = echarts.init(document.getElementById(refChar))
- myPieChart.setOption(options)
- },
- // 获取饼状图配置
- getPieOptions(count, data, color, unit) {
- return {
- title: {
- text: '总计:' + count + unit,
- left: 'center',
- textStyle: {
- color: '#fff',
- fontWeight: 'normal',
- fontSize: 14
- }
- },
- tooltip: {
- trigger: 'item'
- },
- legend: {
- left: 'center',
- top: 30,
- textStyle: {
- color: '#fff'
- }
- },
- series: [
- {
- top: 65,
- type: 'pie',
- radius: ['40%', '70%'],
- label: {
- show: true,
- color: '#fff',
- fontWeight: 'normal',
- formatter(param) {
- return param.data.value + unit;
- }
- },
- color: color,
- data: data
- },
- ]
- }
- },
- // 存储实时离床、在床数据
- setBedTimeData(imei, boolInBed) {
- const i = this.bedTimeData.findIndex(item => item.imei === imei)
- if (i === -1) {
- this.bedTimeData.push({
- imei: imei,
- inBedTime: new Date(),
- status: boolInBed
- })
- if (boolInBed) {
- this.countFrom.inBed++
- }
- } else {
- if (!this.bedTimeData[i].status === boolInBed) {
- this.bedTimeData[i] = {
- imei: imei,
- inBedTime: new Date(),
- status: boolInBed
- }
- if (boolInBed) {
- this.countFrom.inBed++
- } else {
- this.countFrom.inBed--
- }
- }
- }
- },
- // 组装报警信息
- setWarnData(data, named) {
- const now = new Date(data.warn_time)
- const time = `${now.getHours()}:${now.getMinutes()}`
- let warn_class = ''
- switch (data.warn_type) {
- case 1:
- case 2:
- warn_class = 'xl'
- break
- case 3:
- case 4:
- warn_class = 'hx'
- break
- case 5:
- warn_class = 'lc'
- break
- case 6:
- warn_class = 'jj'
- break
- default:
- break
- }
- this.warnList.unshift({
- warn_time: time,
- warn_class: warn_class,
- named: named
- })
- },
- // 根据状态获取离床、在床样式
- getStatusClass(item) {
- let str = ''
- switch (item.status) {
- case '离床':
- str = 'offline'
- break
- case '在床':
- str = 'online'
- break
- default:
- break
- }
- str += item.boolWarn ? ' warn' : ''
- return str
- },
- // 根据imei获取在床、离床时间
- getTimeByImei(imei) {
- const index = this.bedTimeData.findIndex(item => item.imei === imei)
- if (index === -1) {
- return '--:--'
- } else {
- if (this.bedTimeData[index].inBedTime > this.nowDate) {
- return this.unixToDate(this.bedTimeData[index].inBedTime, 1)
- } else {
- return this.unixToDate(this.bedTimeData[index].inBedTime, 0)
- }
- }
- },
- unixToDate(date, type) {
- let year = date.getFullYear()
- let month = date.getMonth() + 1
- let day = date.getDate()
- let hours = date.getHours()
- let minutes = date.getMinutes()
- let seconds = date.getSeconds()
- if (Number(month) < 10) {
- // 10月之前都需要补0
- month = '0' + month
- }
- if (Number(day) < 10) {
- // 10天之前都需要补0
- day = '0' + day
- }
- if (Number(hours) < 10) {
- // 10小时之前都需要补0
- hours = '0' + hours
- }
- if (Number(minutes) < 10) {
- // 10分钟之前都需要补0
- minutes = '0' + minutes
- }
- let formattedDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
- if (type === 0) {
- return `${month}月${day}`
- } else {
- return `${hours}:${minutes}`
- }
- },
- /**
- * 将unix时间戳转换为指定格式
- * @param unix 时间戳【秒】
- * @param format 转换格式
- * @returns {*|string}
- */
- unixToDate2(unix, format) {
- if (!unix) return unix
- let _format = format || 'yyyy-MM-dd hh:mm:ss'
- const d = new Date(unix * 1000)
- const o = {
- 'M+': d.getMonth() + 1,
- 'd+': d.getDate(),
- 'h+': d.getHours(),
- 'm+': d.getMinutes(),
- 's+': d.getSeconds(),
- 'q+': Math.floor((d.getMonth() + 3) / 3),
- S: d.getMilliseconds()
- }
- if (/(y+)/.test(_format)) _format = _format.replace(RegExp.$1, (d.getFullYear() + '').substr(4 - RegExp.$1.length))
- for (const k in o) if (new RegExp('(' + k + ')').test(_format)) _format = _format.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
- return _format
- },
- // 将分转化为时分
- formateSeconds(endTime, type) {
- let secondTime = endTime//将传入的秒的值转化为Number
- let hourStr, minuteStr
- if (type === 0) {
- hourStr = '小时'
- minuteStr = '分钟'
- } else {
- hourStr = '时'
- minuteStr = '分'
- }
- let h = 0// 初始化小时
- if (secondTime > 60) {//如果秒数大于60,将秒数转换成整数
- h = parseInt(secondTime / 60)//获取小时,获取分钟除以60,得到整数小时
- secondTime = parseInt(secondTime % 60) //获取小时后取佘的分,获取分钟除以60取佘的分
- return h + hourStr + secondTime + minuteStr
- } else {
- return secondTime + minuteStr
- }
- },
- formartName(name) {
- if (name.length > 4) {
- return name.substring(0, 4) + '...'
- } else {
- return name
- }
- },
- // 选择日期
- changeDate(e) {
- let month = e.getMonth() + 1, day = e.getDate()
- if (Number(month) < 10) {
- // 10月之前都需要补0
- month = '0' + month
- }
- if (Number(day) < 10) {
- // 10天之前都需要补0
- day = '0' + day
- }
- const str = e.getFullYear() + '-' + month + '-' + day
- if (this.selected.findIndex(item => item === str) === -1) {
- this.$message({
- message: str + '没有睡眠报告,请选择其他日期',
- type: 'warning'
- })
- return
- }
- this.params.reportTime = Math.round(e / 1000)
- this.API_GetSleepReport()
- },
- // 获取焦点 展示日期
- async isShow(e) {
- await this.$nextTick()
- if (this.setClick) return
- document.querySelector('.el-month-table').addEventListener('click', () => {
- this.monthChange()
- })
- document.querySelectorAll("[aria-label='下个月'],[aria-label='上个月'],[aria-label='后一年'],[aria-label='前一年']")
- .forEach(item => item.addEventListener('click', () => {
- this.monthChange()
- }))
- this.setClick = true
- },
- // 切换年月后重新调接口
- async monthChange() {
- let year, month
- // 获取年月
- year = document.querySelectorAll('.el-date-picker__header-label')[0].innerHTML.slice(0, 4)
- month = document.querySelectorAll('.el-date-picker__header-label')[1].innerHTML.slice(0, -1)
- if (Number(month) < 10) {
- // 10月之前都需要补0
- month = '0' + month;
- }
- const _this = this
- _this.selectYearMonth.year = year
- _this.selectYearMonth.month = month.trim()
- this.getDaysTag()
- },
- // 选择睡眠时间段
- pickerChange(index) {
- this.sleepReportFrom = Object.assign({}, this.sleepReportList[index])
- this.sleepReportFrom.report_content = JSON.parse(this.sleepReportFrom.report_content)
- this.qualifiedCount(this.sleepReportFrom.report_content)
- this.initAllChar(this.sleepReportFrom)
- },
- changeLookBed(item) {
- this.params.sn = item.imei
- this.selectYearMonth.sn = item.imei
- this.myFullName = item.full_name
- this.myNickName = item.nickname
- this.params.reportTime = -1
- this.API_GetSleepReport()
- },
- // 获取url参数
- getUrlQuery(name) {
- let reg = new RegExp('(^|&)' + name + "=([^&]*)", "i");
- let r = decodeURI(window.location.search.substr(1)).match(reg);
- if (r != null) return r[2]; return null;
- },
- filterNode(value, data) {
- if (!value) return true;
- return data.shop_name.indexOf(value) !== -1;
- },
- // 获取代理列表
- API_GetAgentList() {
- // getAllSubordinateAgents
- get('/bulletin_board_mattress/get_child_recursion/' + this.shopId).then(res => {
- console.log('res======', res)
- this.agentList = res
- }).catch(err => {
- console.log('err====', err)
- })
- },
- onLook(shopId) {
- console.log('查看data===', shopId)
- this.shopId = shopId
- this.drawer = false
- this.API_GetFrameList()
- }
- }
- });
- </script>
- </body>
- </html>
|