Commit 62cf4308dc566da5a6fd7cbafc564eb1109827a4
Merge branch 'local_dev_ft' into 'main_dev'
perf: 优化重构app完成,优化主分包体积大小,主包不超过1.5M See merge request yunteng/thingskit-app!121
Showing
47 changed files
with
2550 additions
and
1943 deletions
Too many changes to show.
To preserve performance only 47 of 101 files are displayed.
| 1 | <script> | 1 | <script> |
| 2 | import store from '@/store'; | 2 | import store from '@/store'; |
| 3 | - // import { | ||
| 4 | - // scene | ||
| 5 | - // } from '@/config/common'; | ||
| 6 | 3 | ||
| 7 | export default { | 4 | export default { |
| 8 | //设置全局变量,解绑时从这里取 | 5 | //设置全局变量,解绑时从这里取 |
| @@ -10,27 +7,12 @@ | @@ -10,27 +7,12 @@ | ||
| 10 | openId: '' | 7 | openId: '' |
| 11 | }, | 8 | }, |
| 12 | onLaunch(e) { | 9 | onLaunch(e) { |
| 13 | - //取出缓存数据 | ||
| 14 | - // store.commit('setCacheData'); | ||
| 15 | - //获取二维码信息 | ||
| 16 | - // scene(e); | ||
| 17 | // #ifdef APP-PLUS | 10 | // #ifdef APP-PLUS |
| 18 | uni.reLaunch({ | 11 | uni.reLaunch({ |
| 19 | url: '/pages/index/splash' | 12 | url: '/pages/index/splash' |
| 20 | }) | 13 | }) |
| 21 | // #endif | 14 | // #endif |
| 22 | }, | 15 | }, |
| 23 | - onShow(e) { | ||
| 24 | - // #ifdef MP | ||
| 25 | - // mpUpData(); //检测小程序更新 | ||
| 26 | - // #endif | ||
| 27 | - // #ifdef APP-PLUS | ||
| 28 | - // uni.reLaunch({ | ||
| 29 | - // url: '/pages/index/splash' | ||
| 30 | - // }) | ||
| 31 | - // #endif | ||
| 32 | - }, | ||
| 33 | - onHide() {}, | ||
| 34 | onUnload(){ | 16 | onUnload(){ |
| 35 | uni.setStorageSync('getConfiguration', { | 17 | uni.setStorageSync('getConfiguration', { |
| 36 | isConfiguration: false | 18 | isConfiguration: false |
| 1 | +<template> | ||
| 2 | + <view class="alarm-detail-page"> | ||
| 3 | + <!-- 公共组件-每个页面必须引入 --> | ||
| 4 | + <public-module></public-module> | ||
| 5 | + <view class="alarm-detail-column"> | ||
| 6 | + <view class="u-flex detail-column"> | ||
| 7 | + <view class="column-line" v-for="(item,index) in alarmDetail" :key="index"> | ||
| 8 | + <view class="column"> | ||
| 9 | + <text class="text-org-bold">{{item.label}}</text> | ||
| 10 | + <text class="text-device-muted text-clip alarm-text" | ||
| 11 | + :style="{color:hasColor.includes(item.label)?'#DE4437':''}"> | ||
| 12 | + {{item.label===hasColor[0]? setAlarmStatus(item.value):item.label===hasColor[1]?setAlarmSeverity(item.value): | ||
| 13 | + item.label==='告警值:'?formatAlarmValueText:item.label==='告警条件:'?formatAlarmConditionText | ||
| 14 | + :item.label==='告警设备:'?formatDeviceText:item.value}} | ||
| 15 | + </text> | ||
| 16 | + </view> | ||
| 17 | + <view class="bottom-line"></view> | ||
| 18 | + </view> | ||
| 19 | + </view> | ||
| 20 | + </view> | ||
| 21 | + <!-- #ifdef MP --> | ||
| 22 | + <view class="handle-result text-org-bold" style="">处理结果</view> | ||
| 23 | + <view class="hanle-main"> | ||
| 24 | + <u--form :label-style="{ 'font-size': '0rpx' }" style="padding-left: 26rpx;" labelPosition="left" | ||
| 25 | + :model="formModel" ref="form1"> | ||
| 26 | + <u-form-item label="." prop="result" ref="item3"> | ||
| 27 | + <view style="position: relative;left: -60rpx;"> | ||
| 28 | + <u--textarea border="none" height="96" placeholder="请输入处理结果" v-model="formModel.result" count> | ||
| 29 | + </u--textarea> | ||
| 30 | + </view> | ||
| 31 | + </u-form-item> | ||
| 32 | + </u--form> | ||
| 33 | + </view> | ||
| 34 | + <!-- #endif --> | ||
| 35 | + <!-- #ifdef APP-PLUS --> | ||
| 36 | + <view class="handle-result text-org-bold">处理结果</view> | ||
| 37 | + <view class="hanle-main"> | ||
| 38 | + <view> | ||
| 39 | + <u--textarea border="none" height="96" placeholder="请输入处理结果" v-model="formModel.result" count> | ||
| 40 | + </u--textarea> | ||
| 41 | + </view> | ||
| 42 | + </view> | ||
| 43 | + <!-- #endif --> | ||
| 44 | + <view class="bottom-button"> | ||
| 45 | + <view v-if="handleText.includes(alarmDetail[7].value)" class="u-flex button-item"> | ||
| 46 | + <u-button @click="handleSubmit" type="primary" shape="circle" text="处理"></u-button> | ||
| 47 | + </view> | ||
| 48 | + <view v-if="clearText.includes(alarmDetail[7].value)" class="u-flex button-item"> | ||
| 49 | + <u-button @click="handleRemove" type="error" shape="circle" text="清除"></u-button> | ||
| 50 | + </view> | ||
| 51 | + </view> | ||
| 52 | + </view> | ||
| 53 | +</template> | ||
| 54 | + | ||
| 55 | +<script> | ||
| 56 | + import { | ||
| 57 | + mapActions | ||
| 58 | + } from 'vuex' | ||
| 59 | + import api from '@/api/index.js' | ||
| 60 | + import { | ||
| 61 | + alarmSeverity, | ||
| 62 | + alarmStatus, | ||
| 63 | + operationNumberOrDate, | ||
| 64 | + operationString, | ||
| 65 | + operationBoolean | ||
| 66 | + } from '@/pages/alarm/config/data.js'; | ||
| 67 | + import { | ||
| 68 | + useShowToast, | ||
| 69 | + useNavigateBack | ||
| 70 | + } from '@/plugins/utils.js' | ||
| 71 | + | ||
| 72 | + export default { | ||
| 73 | + data() { | ||
| 74 | + return { | ||
| 75 | + handleText: ['ACTIVE_UNACK', 'CLEARED_UNACK'], | ||
| 76 | + clearText: ['ACTIVE_UNACK', 'ACTIVE_ACK'], | ||
| 77 | + hasColor: ['告警级别:', '告警状态:'], | ||
| 78 | + alarmSeverity, | ||
| 79 | + alarmStatus, | ||
| 80 | + operationNumberOrDate, | ||
| 81 | + operationString, | ||
| 82 | + operationBoolean, | ||
| 83 | + formModel: { | ||
| 84 | + result: '' | ||
| 85 | + }, | ||
| 86 | + detailId: '', | ||
| 87 | + alarmDetail: [], | ||
| 88 | + formatDeviceText: '', | ||
| 89 | + formatAlarmValueText: '', | ||
| 90 | + formatAlarmConditionText: '', | ||
| 91 | + }; | ||
| 92 | + }, | ||
| 93 | + onLoad(e) { | ||
| 94 | + if (e.data !== null) { | ||
| 95 | + let params = JSON.parse(decodeURIComponent(e.data)); | ||
| 96 | + const {deviceName,severity,organizationName,details,type,createdTime,status,id} = params | ||
| 97 | + this.detailId = id | ||
| 98 | + this.alarmDetail = [{label: '告警场景:',value: type},{label: '告警级别:',value: severity},{label: '所属组织:',value: organizationName},{label: '告警设备:',value: ''},{label: '告警条件:',value: ''},{label: '告警值:',value: ''},{label: '告警时间:',value: createdTime},{label: '告警状态:',value: status},] | ||
| 99 | + this.formatAlarmDevice(details) | ||
| 100 | + this.formatAlarmValue(details) | ||
| 101 | + this.formatAlarmCondition(details) | ||
| 102 | + } | ||
| 103 | + // 隐藏原生的tabbar | ||
| 104 | + uni.hideTabBar(); | ||
| 105 | + }, | ||
| 106 | + methods: { | ||
| 107 | + ...mapActions(['updateBadgeTotal']), | ||
| 108 | + setAlarmStatus(value) { | ||
| 109 | + return this.alarmSeverity.find(item => item.value === value).label | ||
| 110 | + }, | ||
| 111 | + setAlarmSeverity(value) { | ||
| 112 | + return this.alarmStatus.find(item => item.value === value).label | ||
| 113 | + }, | ||
| 114 | + returnPrevPage(title) { | ||
| 115 | + useShowToast(title) | ||
| 116 | + let pages = getCurrentPages(); //获取所有页面栈实例列表 | ||
| 117 | + let nowPage = pages[pages.length - 1]; //当前页页面实例 | ||
| 118 | + let prevPage = pages[pages.length - 2]; //上一页页面实例 | ||
| 119 | + prevPage.$vm.detailStatus = true; | ||
| 120 | + }, | ||
| 121 | + async handleSubmit() { | ||
| 122 | + if (this.formModel.result == '') return uni.$u.toast('请输入处理结果'); | ||
| 123 | + const res = await api.alarmApi.postAlarmAckApi(this.detailId) | ||
| 124 | + if (res == '') { | ||
| 125 | + this.returnPrevPage('处理成功~') | ||
| 126 | + setTimeout(() => { | ||
| 127 | + useNavigateBack(1) | ||
| 128 | + }, 500); | ||
| 129 | + } | ||
| 130 | + }, | ||
| 131 | + async handleRemove() { | ||
| 132 | + const res = await api.alarmApi.postAlarmClearApi(this.detailId) | ||
| 133 | + if (res == '') { | ||
| 134 | + this.returnPrevPage('清除成功~') | ||
| 135 | + setTimeout(async () => { | ||
| 136 | + useNavigateBack(1) | ||
| 137 | + const res = await uni.$u.http.get('/yt/homepage/app?login=true'); | ||
| 138 | + if (res) { | ||
| 139 | + //异步实时更新告警徽标数 | ||
| 140 | + await this.updateBadgeTotal(res.totalAlarm?.activedAlarm); | ||
| 141 | + } | ||
| 142 | + }, 500); | ||
| 143 | + } | ||
| 144 | + }, | ||
| 145 | + //告警值处理 | ||
| 146 | + async formatAlarmValue(e) { | ||
| 147 | + const keys = Object.keys(e) | ||
| 148 | + const dataFormat = await this.handleAlarmDetailFormat(keys); | ||
| 149 | + const values = keys.reduce((acc, curr) => { | ||
| 150 | + dataFormat.forEach((dataItem => { | ||
| 151 | + if (dataItem.tbDeviceId === curr) { | ||
| 152 | + const findAttribute = dataItem.attribute.find(findItem => findItem.identifier === e[curr].key) | ||
| 153 | + acc.push( | ||
| 154 | + `${findAttribute.name}:${e[curr].realValue}${!findAttribute.detail?.dataType?.specs?.unit?.key?'':findAttribute.detail?.dataType?.specs?.unit?.key}` | ||
| 155 | + ) | ||
| 156 | + } | ||
| 157 | + })) | ||
| 158 | + return acc | ||
| 159 | + }, []) | ||
| 160 | + this.formatAlarmValueText = values.join(',') | ||
| 161 | + }, | ||
| 162 | + //告警条件处理 | ||
| 163 | + formatAlarmCondition(e) { | ||
| 164 | + const keys = Object.keys(e) | ||
| 165 | + const values = keys.reduce((acc, curr) => { | ||
| 166 | + acc.push({ | ||
| 167 | + login: e[curr].logic, | ||
| 168 | + logicValue: e[curr].logicValue | ||
| 169 | + }) | ||
| 170 | + return acc | ||
| 171 | + }, []) | ||
| 172 | + const operation = [...operationNumberOrDate, ...operationString, ...operationBoolean] | ||
| 173 | + const format = values.map(item => { | ||
| 174 | + const findOperation = operation.find(findItem => findItem.value === item.login)?.symbol | ||
| 175 | + return findOperation + item.logicValue | ||
| 176 | + }) | ||
| 177 | + this.formatAlarmConditionText = format.filter(Boolean).join(',') | ||
| 178 | + }, | ||
| 179 | + //告警设备处理 | ||
| 180 | + async formatAlarmDevice(e) { | ||
| 181 | + const keys = Object.keys(e) | ||
| 182 | + const dataFormat = await this.handleAlarmDetailFormat(keys); | ||
| 183 | + if (!dataFormat) this.formatDeviceText = '' | ||
| 184 | + if (Array.isArray(dataFormat) && dataFormat.length === 0) this.formatDeviceText = '' | ||
| 185 | + this.formatDeviceText = dataFormat.map(item => item.name).join(',') | ||
| 186 | + }, | ||
| 187 | + async handleAlarmDetailFormat(keys) { | ||
| 188 | + const temp = []; | ||
| 189 | + for (let item of keys) { | ||
| 190 | + if (item === 'key' || item === 'data') return; //旧数据则终止 | ||
| 191 | + const deviceDetailRes = await api.deviceApi.getDeviceDetail(item); | ||
| 192 | + const { deviceProfileId } = deviceDetailRes; | ||
| 193 | + if (!deviceProfileId) return; | ||
| 194 | + const attributeRes = await api.deviceApi.getAttribute(deviceProfileId); | ||
| 195 | + const dataFormat = this.handleDataFormat(deviceDetailRes, attributeRes); | ||
| 196 | + temp.push(dataFormat); | ||
| 197 | + } | ||
| 198 | + return temp; | ||
| 199 | + }, | ||
| 200 | + handleDataFormat(deviceDetail, attributes) { | ||
| 201 | + const { name,tbDeviceId } = deviceDetail; | ||
| 202 | + const attribute = attributes.map((item) => ({ | ||
| 203 | + identifier: item.identifier, | ||
| 204 | + name: item.name, | ||
| 205 | + detail: item.detail | ||
| 206 | + })); | ||
| 207 | + return { | ||
| 208 | + name, | ||
| 209 | + tbDeviceId, | ||
| 210 | + attribute, | ||
| 211 | + }; | ||
| 212 | + } | ||
| 213 | + } | ||
| 214 | + }; | ||
| 215 | +</script> | ||
| 216 | + | ||
| 217 | +<style lang="scss" scoped> | ||
| 218 | + @import './static/alarmDetail.scss'; | ||
| 219 | + | ||
| 220 | + /deep/ .u-button--primary { | ||
| 221 | + background-color: #377dff !important; | ||
| 222 | + border-color: #377dff !important; | ||
| 223 | + } | ||
| 224 | +</style> |
alarm-subpackage/alarm-detail/static/alarmDetail.scss
renamed from
alarmSubPage/alarmDetailPage/static/alarmDetail.scss
| @@ -6,57 +6,67 @@ | @@ -6,57 +6,67 @@ | ||
| 6 | .alarm-detail-column { | 6 | .alarm-detail-column { |
| 7 | border-radius: 10px; | 7 | border-radius: 10px; |
| 8 | width: 688rpx; | 8 | width: 688rpx; |
| 9 | - height: 573rpx; | 9 | + height: 688rpx; |
| 10 | background-color: #ffffff; | 10 | background-color: #ffffff; |
| 11 | .detail-column { | 11 | .detail-column { |
| 12 | - height: 573rpx; | ||
| 13 | - justify-content: space-between; | 12 | + width:750rpx; |
| 14 | flex-direction: column; | 13 | flex-direction: column; |
| 15 | align-items: center; | 14 | align-items: center; |
| 16 | - .column { | ||
| 17 | - flex-direction: row; | 15 | + .column-line{ |
| 18 | display:flex; | 16 | display:flex; |
| 19 | - // justify-content: space-between; | ||
| 20 | - margin-top: 10rpx; | ||
| 21 | - line-height: 68rpx; | ||
| 22 | - width: 614rpx; | ||
| 23 | - height: 90rpx; | ||
| 24 | - text-align: left; | ||
| 25 | - border-bottom: 0.1rpx solid #f0f0f0; | ||
| 26 | - .device-name{ | ||
| 27 | - width:222rpx; | ||
| 28 | - } | ||
| 29 | - .text { | ||
| 30 | - color: #333333; | ||
| 31 | - font-size: 15px; | ||
| 32 | - } | ||
| 33 | - .image { | ||
| 34 | - width: 30rpx; | ||
| 35 | - height: 30rpx; | ||
| 36 | - } | ||
| 37 | - .text-alarm-level { | ||
| 38 | - color: #333333; | ||
| 39 | - font-size: 14px; | ||
| 40 | - } | ||
| 41 | - .text-alarm-level-lg { | ||
| 42 | - color: #333333; | ||
| 43 | - font-size: 15px; | ||
| 44 | - } | ||
| 45 | - .text-alarm-lg { | ||
| 46 | - color: #666666; | ||
| 47 | - font-size: 14px; | ||
| 48 | - } | ||
| 49 | - .text-alarm-status { | ||
| 50 | - color: #de4437; | ||
| 51 | - font-size: 14px; | 17 | + flex-direction: column; |
| 18 | + .column { | ||
| 19 | + display:flex; | ||
| 20 | + margin-top: 10rpx; | ||
| 21 | + line-height: 68rpx; | ||
| 22 | + width:700rpx; | ||
| 23 | + height: 74rpx; | ||
| 24 | + align-items: center; | ||
| 25 | + .device-name{ | ||
| 26 | + width:222rpx; | ||
| 27 | + } | ||
| 28 | + .alarm-text{ | ||
| 29 | + width:460rpx; | ||
| 30 | + overflow-x: scroll; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + .text { | ||
| 34 | + color: #333333; | ||
| 35 | + font-size: 15px; | ||
| 36 | + } | ||
| 37 | + .image { | ||
| 38 | + width: 30rpx; | ||
| 39 | + height: 30rpx; | ||
| 40 | + } | ||
| 41 | + .text-alarm-level { | ||
| 42 | + color: #333333; | ||
| 43 | + font-size: 14px; | ||
| 44 | + } | ||
| 45 | + .text-alarm-level-lg { | ||
| 46 | + color: #333333; | ||
| 47 | + font-size: 15px; | ||
| 48 | + } | ||
| 49 | + .text-alarm-lg { | ||
| 50 | + color: #666666; | ||
| 51 | + font-size: 14px; | ||
| 52 | + } | ||
| 53 | + .text-alarm-status { | ||
| 54 | + color: #de4437; | ||
| 55 | + font-size: 14px; | ||
| 56 | + } | ||
| 52 | } | 57 | } |
| 58 | + .bottom-line{ | ||
| 59 | + border-bottom: 0.1rpx solid #f0f0f0; | ||
| 60 | + width:650rpx; | ||
| 61 | + } | ||
| 53 | } | 62 | } |
| 63 | + | ||
| 54 | } | 64 | } |
| 55 | } | 65 | } |
| 56 | .handle-result { | 66 | .handle-result { |
| 57 | color: #333333; | 67 | color: #333333; |
| 58 | font-size: 15px; | 68 | font-size: 15px; |
| 59 | - margin-top: 20rpx; | 69 | + margin-top: 32rpx; |
| 60 | } | 70 | } |
| 61 | .hanle-main { | 71 | .hanle-main { |
| 62 | margin-top: 30rpx; | 72 | margin-top: 30rpx; |
| @@ -65,3 +75,13 @@ | @@ -65,3 +75,13 @@ | ||
| 65 | height: 273rpx; | 75 | height: 273rpx; |
| 66 | background-color: #ffffff; | 76 | background-color: #ffffff; |
| 67 | } | 77 | } |
| 78 | +.bottom-button{ | ||
| 79 | + margin-top: 44rpx; | ||
| 80 | + display: flex; | ||
| 81 | + align-items: center; | ||
| 82 | + gap:40rpx; | ||
| 83 | + justify-content: center; | ||
| 84 | + .button-item{ | ||
| 85 | + width: 260rpx; | ||
| 86 | + } | ||
| 87 | +} |
alarmSubPage/alarmDetailPage/alarmDetail.vue
deleted
100644 → 0
| 1 | -<template> | ||
| 2 | - <view class="alarm-detail-page"> | ||
| 3 | - <!-- 公共组件-每个页面必须引入 --> | ||
| 4 | - <public-module></public-module> | ||
| 5 | - <view class="alarm-detail-column"> | ||
| 6 | - <view class="u-flex detail-column"> | ||
| 7 | - <view class="u-flex column"> | ||
| 8 | - <text | ||
| 9 | - class="text-clip device-name text-org-bold">{{ list.deviceName == null ? '暂无数据' : list.deviceName }}</text> | ||
| 10 | - <image class="image" src="/static/alarm-device.png"></image> | ||
| 11 | - </view> | ||
| 12 | - <view class="column"> | ||
| 13 | - <text class="text-org-bold ">告警级别:</text> | ||
| 14 | - <text class="text-device-muted" style="color:#DE4437"> | ||
| 15 | - {{ | ||
| 16 | - list.severity == 'CRITICAL' | ||
| 17 | - ? '危险' | ||
| 18 | - : list.severity == 'MAJOR' | ||
| 19 | - ? '重要' | ||
| 20 | - : list.severity == 'MINOR' | ||
| 21 | - ? '次要' | ||
| 22 | - : list.severity == 'WARNING' | ||
| 23 | - ? '警告' | ||
| 24 | - : '不确定' | ||
| 25 | - }} | ||
| 26 | - </text> | ||
| 27 | - </view> | ||
| 28 | - <view class="column"> | ||
| 29 | - <text class="text-org-bold">所属组织:</text> | ||
| 30 | - <text | ||
| 31 | - class="text-device-muted">{{ list.organizationName == null ? '暂无数据' : list.organizationName }}</text> | ||
| 32 | - </view> | ||
| 33 | - <view class="column"> | ||
| 34 | - <text class="text-org-bold">告警值:</text> | ||
| 35 | - <text | ||
| 36 | - class="text-device-muted text-clip">{{ list.details == null ? '暂无数据' : formatDetailText(list.details.data) }}</text> | ||
| 37 | - </view> | ||
| 38 | - <view class="column"> | ||
| 39 | - <text class="text-org-bold">告警场景:</text> | ||
| 40 | - <text | ||
| 41 | - class="text-device-muted text-clip">{{ list.type == null ? '暂无数据' : list.type }}</text> | ||
| 42 | - </view> | ||
| 43 | - <view class="column"> | ||
| 44 | - <text class="text-org-bold">告警时间:</text> | ||
| 45 | - <text class="text-device-muted">{{ list.createdTime }}</text> | ||
| 46 | - </view> | ||
| 47 | - <view class="column"> | ||
| 48 | - <text class="text-org-bold">告警状态:</text> | ||
| 49 | - <text class="text-device-muted" style="color: #DE4437;"> | ||
| 50 | - {{ | ||
| 51 | - list.status == 'CLEARED_UNACK' | ||
| 52 | - ? '清除未确认' | ||
| 53 | - : list.status == 'ACTIVE_UNACK' | ||
| 54 | - ? '激活未确认' | ||
| 55 | - : list.status == 'CLEARED_ACK' | ||
| 56 | - ? '清除已确认' | ||
| 57 | - : '激活已确认' | ||
| 58 | - }} | ||
| 59 | - </text> | ||
| 60 | - </view> | ||
| 61 | - </view> | ||
| 62 | - </view> | ||
| 63 | - <!-- #ifdef MP --> | ||
| 64 | - <view class="handle-result text-org-bold" style="">处理结果</view> | ||
| 65 | - <view class="hanle-main"> | ||
| 66 | - <u--form :label-style="{ 'font-size': '0rpx' }" style="padding-left: 26rpx;" labelPosition="left" | ||
| 67 | - :model="formModel" ref="form1"> | ||
| 68 | - <u-form-item label="." prop="result" ref="item3"> | ||
| 69 | - <view style="position: relative;left: -60rpx;"> | ||
| 70 | - <u--textarea border="none" height="96" placeholder="请输入处理结果" v-model="formModel.result" count> | ||
| 71 | - </u--textarea> | ||
| 72 | - </view> | ||
| 73 | - </u-form-item> | ||
| 74 | - </u--form> | ||
| 75 | - </view> | ||
| 76 | - <!-- #endif --> | ||
| 77 | - <!-- #ifdef APP-PLUS --> | ||
| 78 | - <view class="handle-result text-org-bold">处理结果</view> | ||
| 79 | - <view class="hanle-main"> | ||
| 80 | - <view> | ||
| 81 | - <u--textarea border="none" height="96" placeholder="请输入处理结果" v-model="formModel.result" count> | ||
| 82 | - </u--textarea> | ||
| 83 | - </view> | ||
| 84 | - </view> | ||
| 85 | - <!-- #endif --> | ||
| 86 | - <view style="margin-top: 44rpx;display: flex;align-items: center;justify-content: space-between;"> | ||
| 87 | - <view :style="[ | ||
| 88 | - { position: list.status !== 'CLEARED_ACK' && list.status !== 'ACTIVE_ACK' ? 'relative' : '' }, | ||
| 89 | - { right: list.status !== 'CLEARED_ACK' && list.status !== 'ACTIVE_ACK' ? '-210rpx' : '' } | ||
| 90 | - ]" v-if="list.status !== 'CLEARED_ACK' && list.status !== 'ACTIVE_ACK'" class="u-flex" style="width: 260rpx"> | ||
| 91 | - <u-button @click="handleSubmit" type="primary" shape="circle" text="处理"></u-button> | ||
| 92 | - </view> | ||
| 93 | - <view style="width: 30rpx;"></view> | ||
| 94 | - <view | ||
| 95 | - :style="[{ position: list.status == 'ACTIVE_ACK' ? 'relative' : '' }, { right: list.status == 'ACTIVE_ACK' ? '207rpx' : '' }]" | ||
| 96 | - v-if="list.status == 'ACTIVE_ACK'" class="u-flex" style="width: 260rpx"> | ||
| 97 | - <u-button @click="handleRemove" type="error" shape="circle" text="清除"></u-button> | ||
| 98 | - </view> | ||
| 99 | - </view> | ||
| 100 | - </view> | ||
| 101 | -</template> | ||
| 102 | - | ||
| 103 | -<script> | ||
| 104 | - import { | ||
| 105 | - mapActions | ||
| 106 | - } from 'vuex' | ||
| 107 | - import api from '@/api/index.js' | ||
| 108 | - | ||
| 109 | - export default { | ||
| 110 | - data() { | ||
| 111 | - return { | ||
| 112 | - formModel: { | ||
| 113 | - result: '' | ||
| 114 | - }, | ||
| 115 | - list: {} | ||
| 116 | - }; | ||
| 117 | - }, | ||
| 118 | - onLoad(e) { | ||
| 119 | - if (e.data !== null) { | ||
| 120 | - let params = JSON.parse(e.data); | ||
| 121 | - this.list = params; | ||
| 122 | - } | ||
| 123 | - // 隐藏原生的tabbar | ||
| 124 | - uni.hideTabBar(); | ||
| 125 | - }, | ||
| 126 | - methods: { | ||
| 127 | - //处理 | ||
| 128 | - async handleSubmit() { | ||
| 129 | - if (this.formModel.result == '') return uni.$u.toast('请输入处理结果'); | ||
| 130 | - const res = await api.alarmApi.postAlarmAckApi(this.list.id) | ||
| 131 | - if (res == '') { | ||
| 132 | - uni.showToast({ | ||
| 133 | - title: '处理成功~', | ||
| 134 | - icon: 'none' | ||
| 135 | - }); | ||
| 136 | - let pages = getCurrentPages(); //获取所有页面栈实例列表 | ||
| 137 | - let nowPage = pages[pages.length - 1]; //当前页页面实例 | ||
| 138 | - let prevPage = pages[pages.length - 2]; //上一页页面实例 | ||
| 139 | - prevPage.$vm.detailStatus = true; | ||
| 140 | - setTimeout(() => { | ||
| 141 | - uni.navigateBack({ | ||
| 142 | - delta: 1 | ||
| 143 | - }); | ||
| 144 | - }, 500); | ||
| 145 | - } | ||
| 146 | - }, | ||
| 147 | - // 清除 | ||
| 148 | - async handleRemove() { | ||
| 149 | - const res = await api.alarmApi.postAlarmClearApi(this.list.id) | ||
| 150 | - if (res == '') { | ||
| 151 | - uni.showToast({ | ||
| 152 | - title: '清除成功~', | ||
| 153 | - icon: 'none' | ||
| 154 | - }); | ||
| 155 | - let pages = getCurrentPages(); //获取所有页面栈实例列表 | ||
| 156 | - let nowPage = pages[pages.length - 1]; //当前页页面实例 | ||
| 157 | - let prevPage = pages[pages.length - 2]; //上一页页面实例 | ||
| 158 | - prevPage.$vm.detailStatus = true; | ||
| 159 | - setTimeout(async () => { | ||
| 160 | - uni.navigateBack({ | ||
| 161 | - delta: 1 | ||
| 162 | - }); | ||
| 163 | - const res = await uni.$u.http.get('/yt/homepage/app?login=true'); | ||
| 164 | - if (res) { | ||
| 165 | - //异步实时更新告警徽标数 | ||
| 166 | - await this.updateBadgeTotal(res.totalAlarm?.activedAlarm); | ||
| 167 | - } | ||
| 168 | - }, 500); | ||
| 169 | - } | ||
| 170 | - }, | ||
| 171 | - ...mapActions(['updateBadgeTotal']), | ||
| 172 | - formatDetailText(e) { | ||
| 173 | - //去除字符串双引号 | ||
| 174 | - const jsonStr = JSON.stringify(e); | ||
| 175 | - const str = jsonStr.substring(1, jsonStr.length - 1); | ||
| 176 | - const newStr = str.replace(/\"/g, ''); | ||
| 177 | - return newStr.slice(0,26); | ||
| 178 | - } | ||
| 179 | - } | ||
| 180 | - }; | ||
| 181 | -</script> | ||
| 182 | - | ||
| 183 | -<style lang="scss" scoped> | ||
| 184 | - @import './static/alarmDetail.scss'; | ||
| 185 | - | ||
| 186 | - /deep/ .u-button--primary { | ||
| 187 | - background-color: #377dff !important; | ||
| 188 | - border-color: #377dff !important; | ||
| 189 | - } | ||
| 190 | -</style> |
| @@ -11,6 +11,30 @@ const getDeviceApi = (urlParams, data) => { | @@ -11,6 +11,30 @@ const getDeviceApi = (urlParams, data) => { | ||
| 11 | return uni.$u.http.post(`/yt/device?page=${page}&pageSize=${pageSize}`, data); | 11 | return uni.$u.http.post(`/yt/device?page=${page}&pageSize=${pageSize}`, data); |
| 12 | }; | 12 | }; |
| 13 | 13 | ||
| 14 | -export default { | ||
| 15 | - getDeviceApi | 14 | +// 设备详情 |
| 15 | +const getDeviceDetail = (id) => { | ||
| 16 | + return uni.$u.http.get(`/yt/device/${id}`); | ||
| 17 | +}; | ||
| 18 | + | ||
| 19 | +//设备属性 | ||
| 20 | +const getAttribute = (deviceProfileId) => { | ||
| 21 | + return uni.$u.http.get(`/yt/device/attributes/${deviceProfileId}`); | ||
| 22 | +}; | ||
| 23 | + | ||
| 24 | +//命令下发 | ||
| 25 | +const issueCommand = (type, tbDeviceId, data) => { | ||
| 26 | + return uni.$u.http.post(`/rpc/${type==='OneWay'?'oneway':'twoway'}/${tbDeviceId}`, data) | ||
| 16 | } | 27 | } |
| 28 | + | ||
| 29 | +//获取命令下发记录 | ||
| 30 | +const getRpcRecord = (params) => { | ||
| 31 | + return uni.$u.http.get('/yt/rpc', params); | ||
| 32 | +}; | ||
| 33 | + | ||
| 34 | +export default { | ||
| 35 | + getDeviceApi, | ||
| 36 | + getDeviceDetail, | ||
| 37 | + getAttribute, | ||
| 38 | + issueCommand, | ||
| 39 | + getRpcRecord | ||
| 40 | +} |
| @@ -20,9 +20,16 @@ const getConfigurationApi = (params = {}) => { | @@ -20,9 +20,16 @@ const getConfigurationApi = (params = {}) => { | ||
| 20 | .get('/yt/configuration/center', params) | 20 | .get('/yt/configuration/center', params) |
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | +//获取组织列表 | ||
| 24 | +const getMeOrgListApi = () => { | ||
| 25 | + return uni.$u.http | ||
| 26 | + .get('/yt/organization/me/list') | ||
| 27 | +} | ||
| 28 | + | ||
| 23 | export default { | 29 | export default { |
| 24 | getHomeStatisticsApi, | 30 | getHomeStatisticsApi, |
| 25 | getCameraApi, | 31 | getCameraApi, |
| 26 | byCameraIdGetDetailApi, | 32 | byCameraIdGetDetailApi, |
| 27 | - getConfigurationApi | 33 | + getConfigurationApi, |
| 34 | + getMeOrgListApi | ||
| 28 | } | 35 | } |
| @@ -3,12 +3,18 @@ const getPlateCustomApi = () => { | @@ -3,12 +3,18 @@ const getPlateCustomApi = () => { | ||
| 3 | return uni.$u.http.get("/yt/app_design/get") | 3 | return uni.$u.http.get("/yt/app_design/get") |
| 4 | }; | 4 | }; |
| 5 | 5 | ||
| 6 | -//第三方账号绑定API | 6 | +//第三方账号登录API |
| 7 | const getThirdLoginApi = (code) => { | 7 | const getThirdLoginApi = (code) => { |
| 8 | return uni.$u.http.get(`/yt/third/login/${code}`) | 8 | return uni.$u.http.get(`/yt/third/login/${code}`) |
| 9 | }; | 9 | }; |
| 10 | 10 | ||
| 11 | -//获取个人信息API | 11 | +//第三方账号绑定API |
| 12 | +const postThirdLoginApi = (data = {}) => { | ||
| 13 | + return uni.$u.http | ||
| 14 | + .post("/yt/third/bind", data) | ||
| 15 | +}; | ||
| 16 | + | ||
| 17 | +//设置个人信息API | ||
| 12 | const setUserInfoApi = () => { | 18 | const setUserInfoApi = () => { |
| 13 | return uni.$u.http.get("/yt/user/me/info") | 19 | return uni.$u.http.get("/yt/user/me/info") |
| 14 | }; | 20 | }; |
| @@ -52,6 +58,18 @@ const deleteBindApi = (data = {}) => { | @@ -52,6 +58,18 @@ const deleteBindApi = (data = {}) => { | ||
| 52 | return uni.$u.http.delete('/yt/third', data) | 58 | return uni.$u.http.delete('/yt/third', data) |
| 53 | } | 59 | } |
| 54 | 60 | ||
| 61 | +//获取手机验证码API | ||
| 62 | +const postPhoneCodeApi = (phone, data = {}) => { | ||
| 63 | + return uni.$u.http | ||
| 64 | + .post(`/yt/noauth/send_login_code/${phone}`, data) | ||
| 65 | +} | ||
| 66 | + | ||
| 67 | +//手机登录API | ||
| 68 | +const postPhoneLoginApi = (data = {}) => { | ||
| 69 | + return uni.$u.http | ||
| 70 | + .post('/yt/auth/code/login', data) | ||
| 71 | +} | ||
| 72 | + | ||
| 55 | export default { | 73 | export default { |
| 56 | getPlateCustomApi, | 74 | getPlateCustomApi, |
| 57 | getThirdLoginApi, | 75 | getThirdLoginApi, |
| @@ -62,5 +80,8 @@ export default { | @@ -62,5 +80,8 @@ export default { | ||
| 62 | postCodeApi, | 80 | postCodeApi, |
| 63 | postResetCodeApi, | 81 | postResetCodeApi, |
| 64 | postPersonalInfoApi, | 82 | postPersonalInfoApi, |
| 65 | - deleteBindApi | 83 | + deleteBindApi, |
| 84 | + postPhoneCodeApi, | ||
| 85 | + postPhoneLoginApi, | ||
| 86 | + postThirdLoginApi | ||
| 66 | } | 87 | } |
components/common/header-org.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <view class="header-org"> | ||
| 3 | + <view @click="$emit('openOrg')" class="org-item"> | ||
| 4 | + <view class="u-flex org-contact"><text class="text">组织关系</text></view> | ||
| 5 | + <view class="u-flex org-device"> | ||
| 6 | + <image class="device-image" :src="imageSrc"></image> | ||
| 7 | + <text class="device-text">摄像头数:{{ total }}</text> | ||
| 8 | + </view> | ||
| 9 | + </view> | ||
| 10 | + <view class="org-item"> | ||
| 11 | + <image class="image" src="/static/arrow-right.png"></image> | ||
| 12 | + </view> | ||
| 13 | + </view> | ||
| 14 | +</template> | ||
| 15 | + | ||
| 16 | +<script> | ||
| 17 | + export default { | ||
| 18 | + props: { | ||
| 19 | + total: Number, | ||
| 20 | + imageSrc: String | ||
| 21 | + } | ||
| 22 | + } | ||
| 23 | +</script> | ||
| 24 | + | ||
| 25 | +<style lang="scss" scoped> | ||
| 26 | + .header-org { | ||
| 27 | + width: 750rpx; | ||
| 28 | + height: 150rpx; | ||
| 29 | + margin-top: 1rpx; | ||
| 30 | + background-color: #fff; | ||
| 31 | + display: flex; | ||
| 32 | + flex-direction: row; | ||
| 33 | + justify-content: space-between; | ||
| 34 | + position: fixed; | ||
| 35 | + z-index: 999999; | ||
| 36 | + top: -1rpx; | ||
| 37 | + | ||
| 38 | + .org-item { | ||
| 39 | + width: 350rpx; | ||
| 40 | + height: 200rpx; | ||
| 41 | + | ||
| 42 | + .org-contact { | ||
| 43 | + flex-direction: row; | ||
| 44 | + margin-top: 26rpx; | ||
| 45 | + margin-left: 15rpx; | ||
| 46 | + | ||
| 47 | + .text { | ||
| 48 | + color: #333333; | ||
| 49 | + font-size: 15px; | ||
| 50 | + margin-left: 14rpx; | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + .org-device { | ||
| 55 | + margin-top: 23rpx; | ||
| 56 | + margin-left: 15rpx; | ||
| 57 | + flex-direction: row; | ||
| 58 | + | ||
| 59 | + .device-image { | ||
| 60 | + margin-left: 14rpx; | ||
| 61 | + width: 30rpx; | ||
| 62 | + height: 30rpx; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + .device-text { | ||
| 66 | + margin-left: 10rpx; | ||
| 67 | + color: #666666; | ||
| 68 | + font-size: 12px; | ||
| 69 | + } | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + .image { | ||
| 73 | + width: 6px; | ||
| 74 | + height: 10px; | ||
| 75 | + float: right; | ||
| 76 | + margin-right: 34rpx; | ||
| 77 | + margin-top: 37rpx; | ||
| 78 | + } | ||
| 79 | + } | ||
| 80 | + } | ||
| 81 | +</style> |
components/common/header-search.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <u-sticky> | ||
| 3 | + <view class="device-top"> | ||
| 4 | + <view class="search"> | ||
| 5 | + <view> | ||
| 6 | + <view class="search-left"> | ||
| 7 | + <slot></slot> | ||
| 8 | + </view> | ||
| 9 | + </view> | ||
| 10 | + <view @click="$emit('openSearchDialog')" class="search-right"> | ||
| 11 | + <text>筛选</text> | ||
| 12 | + <image src="../../static/shaixuan.png" /> | ||
| 13 | + </view> | ||
| 14 | + </view> | ||
| 15 | + <u-line /> | ||
| 16 | + <view class="org"> | ||
| 17 | + <u-cell @click="$emit('openOrg')" isLink title="组织关系" :border="false"> | ||
| 18 | + <view slot="label" class="label" style="display: flex; align-items: center;margin-top: 20rpx;"> | ||
| 19 | + <image src="../../static/org.png" style="width: 24rpx;height: 28rpx;"></image> | ||
| 20 | + <view style="margin-left: 10rpx; color: #666;"> | ||
| 21 | + {{totalText}} | ||
| 22 | + <text style="margin-left: 20rpx;">{{ total }}</text> | ||
| 23 | + </view> | ||
| 24 | + </view> | ||
| 25 | + </u-cell> | ||
| 26 | + </view> | ||
| 27 | + </view> | ||
| 28 | + </u-sticky> | ||
| 29 | +</template> | ||
| 30 | + | ||
| 31 | +<script> | ||
| 32 | + export default { | ||
| 33 | + props: { | ||
| 34 | + total: Number, | ||
| 35 | + totalText: [Number, String] | ||
| 36 | + } | ||
| 37 | + } | ||
| 38 | +</script> | ||
| 39 | + | ||
| 40 | +<style lang="scss" scoped> | ||
| 41 | + /deep/ .u-button--primary { | ||
| 42 | + background-color: #377dff !important; | ||
| 43 | + border-color: #377dff !important; | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + /deep/ .u-button--info { | ||
| 47 | + background-color: #e3e3e5 !important; | ||
| 48 | + border-color: #e3e3e5 !important; | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + /deep/ .u-cell__right-icon-wrap { | ||
| 52 | + margin-top: -55rpx !important; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + /deep/ .uni-calendar--fixed { | ||
| 56 | + bottom: 172rpx !important; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + .pop-no-scroll { | ||
| 60 | + overflow: hidden; | ||
| 61 | + position: fixed; | ||
| 62 | + height: 100%; | ||
| 63 | + width: 100%; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + .device-top { | ||
| 67 | + padding: 10rpx 30rpx; | ||
| 68 | + background-color: #fff; | ||
| 69 | + | ||
| 70 | + .search { | ||
| 71 | + display: flex; | ||
| 72 | + justify-content: space-between; | ||
| 73 | + padding-bottom: 10rpx; | ||
| 74 | + | ||
| 75 | + .search-left { | ||
| 76 | + width: 580rpx; | ||
| 77 | + background-color: #f8f9fa; | ||
| 78 | + border-radius: 200rpx; | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + .search-right { | ||
| 82 | + display: flex; | ||
| 83 | + align-items: center; | ||
| 84 | + | ||
| 85 | + text { | ||
| 86 | + color: #333; | ||
| 87 | + font-size: 14px; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + image { | ||
| 91 | + width: 40rpx; | ||
| 92 | + height: 40rpx; | ||
| 93 | + } | ||
| 94 | + } | ||
| 95 | + } | ||
| 96 | + } | ||
| 97 | +</style> |
| @@ -228,7 +228,6 @@ export default { | @@ -228,7 +228,6 @@ export default { | ||
| 228 | if (pageLen == 1 && !mainPagePath.includes(currentPages[0].route)) { | 228 | if (pageLen == 1 && !mainPagePath.includes(currentPages[0].route)) { |
| 229 | this.firstPage = true; | 229 | this.firstPage = true; |
| 230 | this.iconLeft = 'home'; | 230 | this.iconLeft = 'home'; |
| 231 | - console.log(this.firstPage, 'this.firstPage'); | ||
| 232 | } | 231 | } |
| 233 | }, | 232 | }, |
| 234 | methods: { | 233 | methods: { |
| @@ -273,7 +272,6 @@ export default { | @@ -273,7 +272,6 @@ export default { | ||
| 273 | //设置手机状态栏颜色 | 272 | //设置手机状态栏颜色 |
| 274 | settingColor() { | 273 | settingColor() { |
| 275 | let navColor = this.navFontColor; | 274 | let navColor = this.navFontColor; |
| 276 | - console.log(navColor, 'settingColor'); | ||
| 277 | let frontColor = '#000000'; | 275 | let frontColor = '#000000'; |
| 278 | if (whiteList.includes(navColor)) { | 276 | if (whiteList.includes(navColor)) { |
| 279 | frontColor = '#ffffff'; | 277 | frontColor = '#ffffff'; |
| @@ -9,10 +9,10 @@ import { | @@ -9,10 +9,10 @@ import { | ||
| 9 | * socketPrefix websocket前缀 ((https, wss),( http, ws)) | 9 | * socketPrefix websocket前缀 ((https, wss),( http, ws)) |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | -const baseUrl = "https://demo.thingskit.com/api"; | ||
| 13 | -const baseDrawioUrl = "https://demo.thingskit.com/thingskit-scada"; | ||
| 14 | -const baseWebSocketUrl = "demo.thingskit.com"; | ||
| 15 | -const socketPrefix = "wss"; | 12 | +const baseUrl = "http://222.180.200.114:48080/api"; |
| 13 | +const baseDrawioUrl = "http://222.180.200.114:9527/thingskit-scada"; | ||
| 14 | +const baseWebSocketUrl = "222.180.200.114:48080"; | ||
| 15 | +const socketPrefix = "ws"; | ||
| 16 | 16 | ||
| 17 | let systemInfo = { | 17 | let systemInfo = { |
| 18 | ...getTabbarHeight(), | 18 | ...getTabbarHeight(), |
| @@ -51,4 +51,4 @@ const courtConfig = { | @@ -51,4 +51,4 @@ const courtConfig = { | ||
| 51 | sk: "", | 51 | sk: "", |
| 52 | }, | 52 | }, |
| 53 | }; | 53 | }; |
| 54 | -export default Object.assign({}, courtConfig); | 54 | +export default Object.assign({}, courtConfig); |
| @@ -103,11 +103,11 @@ uni.$u.http.interceptors.response.use( | @@ -103,11 +103,11 @@ uni.$u.http.interceptors.response.use( | ||
| 103 | const routers = getCurrentPages(); | 103 | const routers = getCurrentPages(); |
| 104 | const currentRoute = routers[routers.length - 1].route; | 104 | const currentRoute = routers[routers.length - 1].route; |
| 105 | const isLoginPage = currentRoute.includes( | 105 | const isLoginPage = currentRoute.includes( |
| 106 | - "publicLoginSubPage/public/login" | 106 | + "login-subpackage/public/login" |
| 107 | ); | 107 | ); |
| 108 | !isLoginPage && | 108 | !isLoginPage && |
| 109 | uni.reLaunch({ | 109 | uni.reLaunch({ |
| 110 | - url: "/publicLoginSubPage/public/login", | 110 | + url: "/login-subpackage/public/login", |
| 111 | }); | 111 | }); |
| 112 | // 清空登录信息 | 112 | // 清空登录信息 |
| 113 | store.commit("emptyUserInfo"); | 113 | store.commit("emptyUserInfo"); |
constant/index.js
0 → 100644
device-subpackage/device-detail/api/index.js
renamed from
deviceSubPage/deviceDetailPage/api/index.js
| 1 | -// 获取某个Key的历史数据 | ||
| 2 | -const getUrlParams = (params) => { | ||
| 3 | - return Object.keys(params).reduce((prev, next, currentIndex) => { | ||
| 4 | - if (params[next]) { | ||
| 5 | - return prev += `${!currentIndex ? '?' : '&'}${next}=${params[next]}` | ||
| 6 | - } | ||
| 7 | - return prev | ||
| 8 | - }, '') | ||
| 9 | -} | ||
| 10 | - | ||
| 11 | -export function getHistoryData(params) { | ||
| 12 | - let { | ||
| 13 | - entityId | ||
| 14 | - } = params | ||
| 15 | - params = getUrlParams(params) | ||
| 16 | - return uni.$u.http.get( | ||
| 17 | - `/plugins/telemetry/DEVICE/${entityId}/values/timeseries${params}` | ||
| 18 | - ); | ||
| 19 | -} | ||
| 20 | - | ||
| 21 | - | ||
| 22 | - | ||
| 23 | -// 获取当前设备的key | ||
| 24 | -export function getDeviceKeys(id) { | ||
| 25 | - return uni.$u.http.get(`/plugins/telemetry/DEVICE/${id}/keys/timeseries`); | ||
| 26 | -}; | ||
| 27 | - | ||
| 28 | -export function issueCommand(type, tbDeviceId, data) { | ||
| 29 | - return uni.$u.http.post(`/rpc/${type==='OneWay'?'oneway':'twoway'}/${tbDeviceId}`, data) | 1 | +// 获取某个Key的历史数据 |
| 2 | +const getUrlParams = (params) => { | ||
| 3 | + return Object.keys(params).reduce((prev, next, currentIndex) => { | ||
| 4 | + if (params[next]) { | ||
| 5 | + return prev += `${!currentIndex ? '?' : '&'}${next}=${params[next]}` | ||
| 6 | + } | ||
| 7 | + return prev | ||
| 8 | + }, '') | ||
| 30 | } | 9 | } |
| 10 | + | ||
| 11 | +export function getHistoryData(params) { | ||
| 12 | + let { | ||
| 13 | + entityId | ||
| 14 | + } = params | ||
| 15 | + params = getUrlParams(params) | ||
| 16 | + return uni.$u.http.get( | ||
| 17 | + `/plugins/telemetry/DEVICE/${entityId}/values/timeseries${params}` | ||
| 18 | + ); | ||
| 19 | +} | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +// 获取当前设备的key | ||
| 24 | +export function getDeviceKeys(id) { | ||
| 25 | + return uni.$u.http.get(`/plugins/telemetry/DEVICE/${id}/keys/timeseries`); | ||
| 26 | +}; |
| 1 | +<template> | ||
| 2 | + <view class="alert-page"> | ||
| 3 | + <!-- 告警头部 --> | ||
| 4 | + <view class="filter-button" @click="openSearchDialog"> | ||
| 5 | + <text>筛选</text> | ||
| 6 | + <image src="/static/shaixuan.png" /> | ||
| 7 | + </view> | ||
| 8 | + <!-- 告警分页 --> | ||
| 9 | + <mescroll-uni height="700rpx;" ref="mescrollRef" @init="mescrollInit" :up="upOption" :down="downOption" | ||
| 10 | + @down="downCallback" @up="upCallback"> | ||
| 11 | + <alarm-item :list="list" @openAlertDetail="openAlertDetail"></alarm-item> | ||
| 12 | + <mescroll-empty v-if="!list.length" /> | ||
| 13 | + </mescroll-uni> | ||
| 14 | + <view style="height: 20rpx"></view> | ||
| 15 | + <!-- 告警筛选 --> | ||
| 16 | + <alarm-popup ref="alarmPopupRef" :show="show" @close="close" @queryCondition="getQueryCondition"></alarm-popup> | ||
| 17 | + </view> | ||
| 18 | +</template> | ||
| 19 | +<script> | ||
| 20 | + import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js'; | ||
| 21 | + import api from '@/api/index.js' | ||
| 22 | + import alarmItem from '@/pages/alarm/components/alarm-item.vue' | ||
| 23 | + import alarmPopup from '@/pages/alarm/components/alarm-popup.vue' | ||
| 24 | + import { | ||
| 25 | + useNavigateTo | ||
| 26 | + } from '@/plugins/utils.js' | ||
| 27 | + | ||
| 28 | + export default { | ||
| 29 | + mixins: [MescrollMixin], | ||
| 30 | + components: { | ||
| 31 | + alarmItem, | ||
| 32 | + alarmPopup | ||
| 33 | + }, | ||
| 34 | + props: { | ||
| 35 | + deviceId: { | ||
| 36 | + type: String, | ||
| 37 | + default: '' | ||
| 38 | + } | ||
| 39 | + }, | ||
| 40 | + data() { | ||
| 41 | + return { | ||
| 42 | + show: false, | ||
| 43 | + list: [], | ||
| 44 | + total: 0, | ||
| 45 | + downOption: { | ||
| 46 | + auto: true //是否在初始化后,自动执行downCallback; 默认true | ||
| 47 | + }, | ||
| 48 | + upOption: { | ||
| 49 | + auto: false // 不自动加载 | ||
| 50 | + }, | ||
| 51 | + page: { | ||
| 52 | + num: 0, | ||
| 53 | + size: 10 | ||
| 54 | + }, | ||
| 55 | + conditions: {}, | ||
| 56 | + }; | ||
| 57 | + }, | ||
| 58 | + methods: { | ||
| 59 | + disabledScroll() { | ||
| 60 | + return; | ||
| 61 | + }, | ||
| 62 | + getQueryCondition(value) { | ||
| 63 | + this.conditions = value | ||
| 64 | + this.conditions.deviceId = this.deviceId | ||
| 65 | + this.loadData(1, this.conditions); | ||
| 66 | + this.close() | ||
| 67 | + }, | ||
| 68 | + resetQuery() { | ||
| 69 | + this.page.num = 1; | ||
| 70 | + this.$nextTick(() => { | ||
| 71 | + this.$refs.alarmPopupRef.resetQuery() | ||
| 72 | + }) | ||
| 73 | + this.conditions = {} | ||
| 74 | + }, | ||
| 75 | + downCallback() { | ||
| 76 | + this.list = []; | ||
| 77 | + this.page.num = 1; | ||
| 78 | + this.resetQuery(); | ||
| 79 | + this.loadData(this.page.num, { | ||
| 80 | + deviceId: this.deviceId | ||
| 81 | + }); | ||
| 82 | + }, | ||
| 83 | + upCallback() { | ||
| 84 | + const deviceId = { | ||
| 85 | + deviceId: this.deviceId | ||
| 86 | + } | ||
| 87 | + const condition = Object.values(this.conditions) | ||
| 88 | + if (condition.length === 0) { | ||
| 89 | + this.page.num += 1; | ||
| 90 | + this.loadData(this.page.num, { | ||
| 91 | + ...deviceId | ||
| 92 | + }); | ||
| 93 | + } else if (condition.filter(Boolean).length > 0) { | ||
| 94 | + this.page.num += 1; | ||
| 95 | + this.loadData(this.page.num, { | ||
| 96 | + ...this.conditions, | ||
| 97 | + ...deviceId | ||
| 98 | + }); | ||
| 99 | + } else { | ||
| 100 | + this.page.num += 1; | ||
| 101 | + this.loadData(this.page.num, { | ||
| 102 | + ...deviceId | ||
| 103 | + }); | ||
| 104 | + } | ||
| 105 | + }, | ||
| 106 | + async loadData(page, param) { | ||
| 107 | + let that = this; | ||
| 108 | + let params = { | ||
| 109 | + page, | ||
| 110 | + pageSize: 10, | ||
| 111 | + ...param | ||
| 112 | + }; | ||
| 113 | + const res = await api.alarmApi.getAlarmApi({ | ||
| 114 | + params, | ||
| 115 | + custom: { | ||
| 116 | + load: false | ||
| 117 | + } | ||
| 118 | + }) | ||
| 119 | + if (!res) return | ||
| 120 | + uni.stopPullDownRefresh(); | ||
| 121 | + that.mescroll.endByPage(res.items.length, res.total); //必传参数(当前页的数据个数, 总页数) | ||
| 122 | + that.alarmTotal = res.total; | ||
| 123 | + if (page == 1) { | ||
| 124 | + that.list = res.items; | ||
| 125 | + } else { | ||
| 126 | + that.list = that.list.concat(res.items); | ||
| 127 | + } | ||
| 128 | + }, | ||
| 129 | + openSearchDialog() { | ||
| 130 | + this.show = true; | ||
| 131 | + this.resetQuery(); | ||
| 132 | + }, | ||
| 133 | + close() { | ||
| 134 | + this.show = false; | ||
| 135 | + }, | ||
| 136 | + openAlertDetail(e) { | ||
| 137 | + useNavigateTo('/alarm-subpackage/alarm-detail/alarm-detail?data=', e) | ||
| 138 | + } | ||
| 139 | + } | ||
| 140 | + }; | ||
| 141 | +</script> | ||
| 142 | + | ||
| 143 | +<style lang="scss" scoped> | ||
| 144 | + .filter-button { | ||
| 145 | + margin: 0 20rpx; | ||
| 146 | + font-size: 12px; | ||
| 147 | + width: 160rpx; | ||
| 148 | + height: 64rpx; | ||
| 149 | + border-radius: 32rpx; | ||
| 150 | + display: flex; | ||
| 151 | + justify-content: center; | ||
| 152 | + align-items: center; | ||
| 153 | + background: #f0f1f2; | ||
| 154 | + color: #666; | ||
| 155 | + | ||
| 156 | + image { | ||
| 157 | + width: 28rpx; | ||
| 158 | + height: 28rpx; | ||
| 159 | + margin-left: 4rpx; | ||
| 160 | + } | ||
| 161 | + } | ||
| 162 | +</style> |
device-subpackage/device-detail/components/basic-info.vue
renamed from
deviceSubPage/deviceDetailPage/tabDetail/basicInfo.vue
| 1 | -<template> | ||
| 2 | - <view class="basic-page"> | ||
| 3 | - <!-- 公共组件-每个页面必须引入 --> | ||
| 4 | - <public-module /> | ||
| 5 | - <view class="basic-title"> | ||
| 6 | - <view class="u-flex"> | ||
| 7 | - <view style="padding-left: 32rpx;"> | ||
| 8 | - <u-icon v-if="deviceDetail.deviceInfo.longitude !== ''" @click="handleClick" name="map-fill"> | ||
| 9 | - </u-icon> | ||
| 10 | - </view> | ||
| 11 | - <view class="text-clip" style="margin-left: 20rpx;width:370rpx"> | ||
| 12 | - {{ deviceDetail.alias? deviceDetail.alias: deviceDetail.name }} | ||
| 13 | - </view> | ||
| 14 | - <view style="margin-left: 20rpx; font-size: 14px;" | ||
| 15 | - :style="{ color: deviceDetail.deviceState === 'INACTIVE' ? '#666' : deviceDetail.deviceState === 'ONLINE' ? '#377DFF' : '#DE4437' }"> | ||
| 16 | - {{ deviceStatus }} | ||
| 17 | - </view> | ||
| 18 | - </view> | ||
| 19 | - <view style="margin-right: 20rpx;" | ||
| 20 | - v-if="deviceDetail.deviceState === 'ONLINE' && deviceDetail.deviceType !== 'SENSOR'"> | ||
| 21 | - <!-- #ifdef MP --> | ||
| 22 | - <u-button type="primary" shape="circle" size="mini" text="下发命令" @click="showModalBtn" /> | ||
| 23 | - <!-- #endif --> | ||
| 24 | - <!-- #ifdef APP-PLUS --> | ||
| 25 | - <view class="cu-item" @tap="showModal" data-target="Modal"> | ||
| 26 | - <text>下发命令</text> | ||
| 27 | - </view> | ||
| 28 | - <!-- #endif --> | ||
| 29 | - </view> | ||
| 30 | - </view> | ||
| 31 | - <view class="detail"> | ||
| 32 | - <view class="detail-item"> | ||
| 33 | - <view class="detail-label">设备编号</view> | ||
| 34 | - <view class="detail-value">{{ deviceDetail.sn }}</view> | ||
| 35 | - </view> | ||
| 36 | - <u-line length="90%" margin="0 auto"></u-line> | ||
| 37 | - <view class="detail-item"> | ||
| 38 | - <view class="detail-label">设备类型</view> | ||
| 39 | - <view class="detail-value">{{ deviceType }}</view> | ||
| 40 | - </view> | ||
| 41 | - <u-line length="90%" margin="0 auto"></u-line> | ||
| 42 | - <view class="detail-item"> | ||
| 43 | - <view class="detail-label">所属组织</view> | ||
| 44 | - <view class="detail-value">{{ deviceDetail.organizationDTO.name }}</view> | ||
| 45 | - </view> | ||
| 46 | - <u-line length="90%" margin="0 auto"></u-line> | ||
| 47 | - <view class="detail-item"> | ||
| 48 | - <view class="detail-label">最后连接时间</view> | ||
| 49 | - <view class="detail-value">{{ formatLastOnlineTime }}</view> | ||
| 50 | - </view> | ||
| 51 | - <u-line length="90%" margin="0 auto"></u-line> | ||
| 52 | - <view class="detail-item"> | ||
| 53 | - <view class="detail-label">是否告警</view> | ||
| 54 | - <view class="detail-value">{{ alarmStatus }}</view> | ||
| 55 | - </view> | ||
| 56 | - <u-line length="90%" margin="0 auto"></u-line> | ||
| 57 | - <view class="detail-item"> | ||
| 58 | - <view class="detail-label">设备描述</view> | ||
| 59 | - <view class="detail-value">{{ deviceDetail.description }}</view> | ||
| 60 | - </view> | ||
| 61 | - </view> | ||
| 62 | - <!-- 下发命令 --> | ||
| 63 | - <!-- #ifdef APP-PLUS --> | ||
| 64 | - <view v-show="showNodal" class="cu-modal" :class="modalName=='Modal'?'show':''"> | ||
| 65 | - <view class="cu-dialog" style=""> | ||
| 66 | - <view class="modal_main"> | ||
| 67 | - <view class='nav-list margin-top'> | ||
| 68 | - <view style="width: 100%; padding: 0 30rpx;"> | ||
| 69 | - <view style="text-align: center; font-weight:700;margin-top: 40rpx;">命令下发</view> | ||
| 70 | - <view style="height: 20rpx;"></view> | ||
| 71 | - <view class="u-flex"> | ||
| 72 | - <text | ||
| 73 | - style="color: #333; font-size: 14px;font-weight:700;margin-right: 30rpx;">下发类型:</text> | ||
| 74 | - <view> | ||
| 75 | - <radio-group style="display: flex;" @change="radioChange"> | ||
| 76 | - <label class="uni-list-cell uni-list-cell-pd" v-for="(item, index) in items" | ||
| 77 | - :key="item.value"> | ||
| 78 | - <view style="display: flex"> | ||
| 79 | - <view style="margin-left: 10rpx;"> | ||
| 80 | - <radio :value="item.value" :checked="index === current" /> | ||
| 81 | - </view> | ||
| 82 | - <view style="width:10rpx"></view> | ||
| 83 | - <view style="margin-left: 10rpx;">{{item.name}}</view> | ||
| 84 | - </view> | ||
| 85 | - </label> | ||
| 86 | - </radio-group> | ||
| 87 | - </view> | ||
| 88 | - </view> | ||
| 89 | - <view style="margin-top: 15rpx"> | ||
| 90 | - <view class="cusAppplusContent"> | ||
| 91 | - <textarea v-model="inputCommandVal" placeholder="请输入下发内容(json格式)" /> | ||
| 92 | - </view> | ||
| 93 | - </view> | ||
| 94 | - <view class="button-group"> | ||
| 95 | - <view> | ||
| 96 | - <view class="cusAppplusCancelBtn" @click="cancelCommand"><text | ||
| 97 | - style="color: #333333">取消</text> | ||
| 98 | - </view> | ||
| 99 | - </view> | ||
| 100 | - <view> | ||
| 101 | - <view class="cusAppplusConfrimBtn" @click="confirmCommand"> | ||
| 102 | - <text style="color:white">确认</text> | ||
| 103 | - </view> | ||
| 104 | - </view> | ||
| 105 | - </view> | ||
| 106 | - <view style="height:30rpx"></view> | ||
| 107 | - </view> | ||
| 108 | - </view> | ||
| 109 | - </view> | ||
| 110 | - </view> | ||
| 111 | - </view> | ||
| 112 | - <!-- #endif --> | ||
| 113 | - <!-- #ifdef MP --> | ||
| 114 | - <u-modal :show="showModel" closeOnClickOverlay :showConfirmButton="false" width="720rpx" @close="hiddenModal" | ||
| 115 | - @touchmove.stop.prevent="disabledScroll"> | ||
| 116 | - <view style="width: 100%; padding: 0 30rpx;"> | ||
| 117 | - <view style="text-align: center; font-weight:700;margin-bottom: 40rpx;">命令下发</view> | ||
| 118 | - <view class="u-flex"> | ||
| 119 | - <text style="color: #333; font-size: 14px;font-weight:700;margin-right: 30rpx;">下发类型:</text> | ||
| 120 | - | ||
| 121 | - <u-radio-group v-model="commandType" placement="row"> | ||
| 122 | - <u-radio activeColor="#3388FF" label="单向" name="OneWay"></u-radio> | ||
| 123 | - <view style="margin: 0 20rpx;"></view> | ||
| 124 | - <u-radio activeColor="#3388FF" label="双向" name="TwoWay"></u-radio> | ||
| 125 | - </u-radio-group> | ||
| 126 | - </view> | ||
| 127 | - <view style="margin-top: 28rpx;width: 100%;"> | ||
| 128 | - <div class="u-flex u-row-between"> | ||
| 129 | - <u--textarea :placeholder="`请输入下发内容${isShowTCP?'(字符串格式)':'(json格式)'}`" v-model="inputCommandVal" /> | ||
| 130 | - <u-icon v-if="!isShowTCP" @click="handleCopy(copyTextValue)" name="question-circle" color="#2979ff" size="28" | ||
| 131 | - class="ml-10"> | ||
| 132 | - </u-icon> | ||
| 133 | - </div> | ||
| 134 | - </view> | ||
| 135 | - | ||
| 136 | - <view class="button-group"> | ||
| 137 | - <view> | ||
| 138 | - <u-button :customStyle="{ color: '#333' }" color="#e3e3e5" shape="circle" text="取消" | ||
| 139 | - @click="cancelCommand"></u-button> | ||
| 140 | - </view> | ||
| 141 | - <view> | ||
| 142 | - <u-button color="#3388ff" shape="circle" text="确认" @click="confirmCommand"></u-button> | ||
| 143 | - </view> | ||
| 144 | - </view> | ||
| 145 | - </view> | ||
| 146 | - </u-modal> | ||
| 147 | - <!-- #endif --> | ||
| 148 | - </view> | ||
| 149 | -</template> | ||
| 150 | - | ||
| 151 | -<script> | ||
| 152 | - import { | ||
| 153 | - formatToDate | ||
| 154 | - } from '@/plugins/utils.js'; | ||
| 155 | - import { | ||
| 156 | - issueCommand | ||
| 157 | - } from '../api/index.js'; | ||
| 158 | - export default { | ||
| 159 | - props: { | ||
| 160 | - deviceDetail: { | ||
| 161 | - type: Object, | ||
| 162 | - default: () => ({}) | ||
| 163 | - } | ||
| 164 | - }, | ||
| 165 | - data() { | ||
| 166 | - return { | ||
| 167 | - copyTextValue: { | ||
| 168 | - "method": "methodThingskit", | ||
| 169 | - "params": { | ||
| 170 | - "pin": 7, | ||
| 171 | - "value": 1 | ||
| 172 | - } | ||
| 173 | - }, | ||
| 174 | - showNodal: false, | ||
| 175 | - items: [{ | ||
| 176 | - value: 'OneWay', | ||
| 177 | - name: '单向', | ||
| 178 | - checked: 'true' | ||
| 179 | - }, | ||
| 180 | - { | ||
| 181 | - value: 'TwoWay', | ||
| 182 | - name: '双向' | ||
| 183 | - }, | ||
| 184 | - ], | ||
| 185 | - current: 0, | ||
| 186 | - modalName: null, | ||
| 187 | - showModel: false, | ||
| 188 | - commandType: 'OneWay', | ||
| 189 | - commandValue: {}, | ||
| 190 | - inputCommandVal: '', | ||
| 191 | - isShowTCP:false,//用于下发命令时判断是否是TCP/UDP | ||
| 192 | - }; | ||
| 193 | - }, | ||
| 194 | - computed: { | ||
| 195 | - deviceStatus(){ | ||
| 196 | - return this.deviceDetail.deviceState === 'INACTIVE' ? '待激活' : this.deviceDetail.deviceState === 'ONLINE' ? '在线' : '离线' | ||
| 197 | - }, | ||
| 198 | - deviceType() { | ||
| 199 | - return this.deviceDetail.deviceType === 'DIRECT_CONNECTION' ? | ||
| 200 | - '直连设备' : | ||
| 201 | - this.deviceDetail.deviceType === 'GATEWAY' ? | ||
| 202 | - '网关设备' : | ||
| 203 | - this.deviceDetail.deviceType === 'SENSOR' ? | ||
| 204 | - '网关子设备' : | ||
| 205 | - ''; | ||
| 206 | - }, | ||
| 207 | - alarmStatus() { | ||
| 208 | - return this.deviceDetail.alarmStatus === '0' ? '否' : '是'; | ||
| 209 | - }, | ||
| 210 | - formatLastOnlineTime() { | ||
| 211 | - return formatToDate(Number(this.deviceDetail.lastOnlineTime), 'YYYY-MM-DD HH:mm:ss'); | ||
| 212 | - } | ||
| 213 | - }, | ||
| 214 | - onLoad(e) { | ||
| 215 | - // 隐藏原生的tabbar | ||
| 216 | - uni.hideTabBar(); | ||
| 217 | - }, | ||
| 218 | - mounted() {}, | ||
| 219 | - beforeCreate() { | ||
| 220 | - this.modalName = null | ||
| 221 | - }, | ||
| 222 | - methods: { | ||
| 223 | - handleCopy(value) { | ||
| 224 | - uni.showModal({ | ||
| 225 | - content: JSON.stringify(value), | ||
| 226 | - confirmText: '复制内容', | ||
| 227 | - showCancel:false, | ||
| 228 | - success: () => { | ||
| 229 | - uni.setClipboardData({ | ||
| 230 | - data: JSON.stringify(value), | ||
| 231 | - success: () => { | ||
| 232 | - uni.showToast({ | ||
| 233 | - title: '复制成功' | ||
| 234 | - }) | ||
| 235 | - } | ||
| 236 | - }); | ||
| 237 | - }, | ||
| 238 | - | ||
| 239 | - }); | ||
| 240 | - }, | ||
| 241 | - radioChange: function(evt) { | ||
| 242 | - for (let i = 0; i < this.items.length; i++) { | ||
| 243 | - if (this.items[i].value === evt.detail.value) { | ||
| 244 | - this.current = i; | ||
| 245 | - break; | ||
| 246 | - } | ||
| 247 | - } | ||
| 248 | - this.commandType = evt.detail.value | ||
| 249 | - }, | ||
| 250 | - handleClick() { | ||
| 251 | - const data = { | ||
| 252 | - longitude: this.deviceDetail.deviceInfo.longitude || 0, | ||
| 253 | - latitude: this.deviceDetail.deviceInfo.latitude || 0 | ||
| 254 | - }; | ||
| 255 | - uni.navigateTo({ | ||
| 256 | - url: '/deviceSubPage/deviceDetailPage/devicePosition?data=' + JSON.stringify(data) | ||
| 257 | - }); | ||
| 258 | - }, | ||
| 259 | - showModal(e) { | ||
| 260 | - this.modalName = e.currentTarget.dataset.target | ||
| 261 | - const {transportType} = this.deviceDetail.deviceProfile | ||
| 262 | - this.isShowTCP = transportType=='TCP'?true:false | ||
| 263 | - this.showNodal = true | ||
| 264 | - }, | ||
| 265 | - showModalBtn() { | ||
| 266 | - this.showModel = true; | ||
| 267 | - this.inputCommandVal = ''; | ||
| 268 | - const {transportType} = this.deviceDetail.deviceProfile | ||
| 269 | - this.isShowTCP = transportType=='TCP'?true:false | ||
| 270 | - }, | ||
| 271 | - disabledScroll() { | ||
| 272 | - return; | ||
| 273 | - }, | ||
| 274 | - hiddenModal() { | ||
| 275 | - this.showModel = false; | ||
| 276 | - this.inputCommandVal = ''; | ||
| 277 | - // #ifdef APP-PLUS | ||
| 278 | - this.modalName = null | ||
| 279 | - this.showNodal = false | ||
| 280 | - // #endif | ||
| 281 | - }, | ||
| 282 | - async confirmCommand() { | ||
| 283 | - try { | ||
| 284 | - this.commandValue.method = 'methodThingskit'; | ||
| 285 | - this.commandValue.persistent = true; | ||
| 286 | - this.commandValue.additionalInfo = { | ||
| 287 | - cmdType: 'API' | ||
| 288 | - }; | ||
| 289 | - if(this.isShowTCP){//TCP的格式只能是字符串 | ||
| 290 | - const zg = /^[0-9a-zA-Z]*$/ | ||
| 291 | - if(!zg.test(this.inputCommandVal)) { | ||
| 292 | - uni.$u.toast('输入的内容只能是字母和数字的组合') | ||
| 293 | - return | ||
| 294 | - } | ||
| 295 | - this.commandValue.params = this.inputCommandVal | ||
| 296 | - }else{ | ||
| 297 | - const commandJsonValue = JSON.parse(this.inputCommandVal); | ||
| 298 | - this.commandValue.params = commandJsonValue | ||
| 299 | - } | ||
| 300 | - await issueCommand(this.commandType, this.deviceDetail.tbDeviceId, this.commandValue); | ||
| 301 | - this.hiddenModal(); | ||
| 302 | - uni.$u.toast('下发成功~'); | ||
| 303 | - } catch (e) { | ||
| 304 | - uni.$u.toast('下发失败~'); | ||
| 305 | - } | ||
| 306 | - }, | ||
| 307 | - cancelCommand() { | ||
| 308 | - this.hiddenModal(); | ||
| 309 | - // #ifdef APP-PLUS | ||
| 310 | - this.modalName = null | ||
| 311 | - this.showNodal = false | ||
| 312 | - // #endif | ||
| 313 | - } | ||
| 314 | - } | ||
| 315 | - }; | ||
| 316 | -</script> | ||
| 317 | - | ||
| 318 | -<style lang="scss" scoped> | ||
| 319 | - @import url('../styles/modal.css'); | ||
| 320 | - | ||
| 321 | - .cusAppplusContent { | ||
| 322 | - width: 625rpx; | ||
| 323 | - height: 400rpx; | ||
| 324 | - background: #FFFFFF; | ||
| 325 | - box-shadow: 2px 2px 4px 0px rgba(0, 0, 0, 0.03); | ||
| 326 | - border-radius: 10px; | ||
| 327 | - | ||
| 328 | - } | ||
| 329 | - | ||
| 330 | - .cusAppplusCancelBtn { | ||
| 331 | - background: #e3e3e5; | ||
| 332 | - border-radius: 38rpx; | ||
| 333 | - height: 85rpx; | ||
| 334 | - line-height: 85rpx | ||
| 335 | - } | ||
| 336 | - | ||
| 337 | - .cusAppplusConfrimBtn { | ||
| 338 | - background: #3388ff; | ||
| 339 | - border-radius: 38rpx; | ||
| 340 | - height: 85rpx; | ||
| 341 | - line-height: 85rpx | ||
| 342 | - } | ||
| 343 | - | ||
| 344 | - .cu-item { | ||
| 345 | - background: #3388FF; | ||
| 346 | - border-radius: 12px; | ||
| 347 | - width: 120rpx; | ||
| 348 | - height: 48rpx; | ||
| 349 | - text-align: center; | ||
| 350 | - line-height: 40rpx; | ||
| 351 | - | ||
| 352 | - text { | ||
| 353 | - font-size: 12px; | ||
| 354 | - font-family: PingFangSC-Regular, PingFang SC; | ||
| 355 | - font-weight: 400; | ||
| 356 | - color: #FFFFFF; | ||
| 357 | - } | ||
| 358 | - } | ||
| 359 | - | ||
| 360 | - | ||
| 361 | - | ||
| 362 | - .basic-page { | ||
| 363 | - padding: 0 30rpx; | ||
| 364 | - | ||
| 365 | - .basic-title { | ||
| 366 | - display: flex; | ||
| 367 | - justify-content: space-between; | ||
| 368 | - align-items: center; | ||
| 369 | - height: 140rpx; | ||
| 370 | - background-color: #fff; | ||
| 371 | - border-radius: 20rpx; | ||
| 372 | - } | ||
| 373 | - | ||
| 374 | - .detail { | ||
| 375 | - background-color: #fff; | ||
| 376 | - margin-top: 30rpx; | ||
| 377 | - border-radius: 20rpx; | ||
| 378 | - width: 690rpx; | ||
| 379 | - | ||
| 380 | - .detail-item { | ||
| 381 | - padding: 30rpx; | ||
| 382 | - display: flex; | ||
| 383 | - align-items: center; | ||
| 384 | - | ||
| 385 | - .detail-label { | ||
| 386 | - color: #333; | ||
| 387 | - font-size: 15px; | ||
| 388 | - } | ||
| 389 | - | ||
| 390 | - .detail-value { | ||
| 391 | - color: #666; | ||
| 392 | - font-size: 14px; | ||
| 393 | - margin-left: 30rpx; | ||
| 394 | - } | ||
| 395 | - } | ||
| 396 | - } | ||
| 397 | - } | ||
| 398 | - | ||
| 399 | - /deep/ .u-modal__content { | ||
| 400 | - padding: 30rpx 0 !important; | ||
| 401 | - } | ||
| 402 | - | ||
| 403 | - .button-group { | ||
| 404 | - display: flex; | ||
| 405 | - margin-top: 40rpx; | ||
| 406 | - justify-content: space-between; | ||
| 407 | - | ||
| 408 | - view { | ||
| 409 | - width: 300rpx; | ||
| 410 | - } | ||
| 411 | - } | ||
| 412 | -</style> | 1 | +<template> |
| 2 | + <view class="basic-page"> | ||
| 3 | + <!-- 公共组件-每个页面必须引入 --> | ||
| 4 | + <public-module></public-module> | ||
| 5 | + <!-- 基础信息头部 --> | ||
| 6 | + <view class="basic-header"> | ||
| 7 | + <view class="u-flex"> | ||
| 8 | + <view class="pl-3"> | ||
| 9 | + <u-icon v-if="deviceDetail.deviceInfo.longitude !== ''" @click="handleClick" | ||
| 10 | + name="map-fill"></u-icon> | ||
| 11 | + </view> | ||
| 12 | + <view class="basic-text text-clip ml-2"> | ||
| 13 | + {{ deviceDetail.alias ? deviceDetail.alias : deviceDetail.name }} | ||
| 14 | + </view> | ||
| 15 | + <view class="basic-text-status ml-2" :style="{ color: formatTextStatus(deviceDetail.deviceState) }"> | ||
| 16 | + {{ deviceStatus }} | ||
| 17 | + </view> | ||
| 18 | + </view> | ||
| 19 | + <!-- 命令下发 设备在线并且不是网关子设备 --> | ||
| 20 | + <view class="mr-2" v-if="deviceDetail.deviceState === 'ONLINE' && deviceDetail.deviceType !== 'SENSOR'"> | ||
| 21 | + <!-- #ifdef MP --> | ||
| 22 | + <u-button type="primary" shape="circle" size="mini" text="下发命令" @click="handleMpShowModal" /> | ||
| 23 | + <!-- #endif --> | ||
| 24 | + <!-- #ifdef APP-PLUS --> | ||
| 25 | + <view class="cu-item" @tap="handleAppShowModal" data-target="Modal"> | ||
| 26 | + <text>下发命令</text> | ||
| 27 | + </view> | ||
| 28 | + <!-- #endif --> | ||
| 29 | + </view> | ||
| 30 | + </view> | ||
| 31 | + <!-- 设备详情 --> | ||
| 32 | + <view class="detail"> | ||
| 33 | + <view class="detail-item"> | ||
| 34 | + <view class="detail-label">设备编号</view> | ||
| 35 | + <view class="detail-value">{{ deviceDetail.sn }}</view> | ||
| 36 | + </view> | ||
| 37 | + <u-line length="90%" margin="0 auto"></u-line> | ||
| 38 | + <view class="detail-item"> | ||
| 39 | + <view class="detail-label">设备类型</view> | ||
| 40 | + <view class="detail-value">{{ deviceType }}</view> | ||
| 41 | + </view> | ||
| 42 | + <u-line length="90%" margin="0 auto"></u-line> | ||
| 43 | + <view class="detail-item"> | ||
| 44 | + <view class="detail-label">所属组织</view> | ||
| 45 | + <view class="detail-value">{{ deviceDetail.organizationDTO.name }}</view> | ||
| 46 | + </view> | ||
| 47 | + <u-line length="90%" margin="0 auto"></u-line> | ||
| 48 | + <view class="detail-item"> | ||
| 49 | + <view class="detail-label">最后连接时间</view> | ||
| 50 | + <view class="detail-value">{{ formatLastOnlineTime }}</view> | ||
| 51 | + </view> | ||
| 52 | + <u-line length="90%" margin="0 auto"></u-line> | ||
| 53 | + <view class="detail-item"> | ||
| 54 | + <view class="detail-label">是否告警</view> | ||
| 55 | + <view class="detail-value">{{ alarmStatus }}</view> | ||
| 56 | + </view> | ||
| 57 | + <u-line length="90%" margin="0 auto"></u-line> | ||
| 58 | + <view class="detail-item"> | ||
| 59 | + <view class="detail-label">设备描述</view> | ||
| 60 | + <view class="detail-value">{{ deviceDetail.description }}</view> | ||
| 61 | + </view> | ||
| 62 | + </view> | ||
| 63 | + <!-- 命令下发 --> | ||
| 64 | + <!-- #ifdef APP-PLUS --> | ||
| 65 | + <!-- 原生弹窗 封装成子组件无效 --> | ||
| 66 | + <view v-show="showNativeModal" class="cu-modal" :class="modalName == 'Modal' ? 'show' : ''"> | ||
| 67 | + <view class="cu-dialog"> | ||
| 68 | + <view class="app-command-content"> | ||
| 69 | + <view class="app-command-text"> | ||
| 70 | + <text>命令下发</text> | ||
| 71 | + </view> | ||
| 72 | + <view class="app-command-type"> | ||
| 73 | + <text>下发类型</text> | ||
| 74 | + <view class="mr-2"> | ||
| 75 | + <radio-group @change="radioChange" class="flex mr-1"> | ||
| 76 | + <label v-for="(item, index) in commandTypeList" :key="item.value"> | ||
| 77 | + <view class="flex"> | ||
| 78 | + <view class="ml-1"> | ||
| 79 | + <radio :value="item.value" :checked="index === current" /> | ||
| 80 | + </view> | ||
| 81 | + <view style="width:10rpx"></view> | ||
| 82 | + <view class="ml-1">{{item.name}}</view> | ||
| 83 | + </view> | ||
| 84 | + </label> | ||
| 85 | + </radio-group> | ||
| 86 | + </view> | ||
| 87 | + </view> | ||
| 88 | + <view class="app-command-body"> | ||
| 89 | + <textarea class="app-command-textarea" v-model="inputCommandContent" | ||
| 90 | + :placeholder="`请输入下发内容${isShowTCP?'(字符串格式)':'(json格式)'}`" /> | ||
| 91 | + <u-icon @click="handleCopy(copyTextValue)" v-if="!isShowTCP" name="question-circle" | ||
| 92 | + color="#2979ff" size="28" class="ml-10"> | ||
| 93 | + </u-icon> | ||
| 94 | + </view> | ||
| 95 | + <view class="app-command-buttons"> | ||
| 96 | + <view class="cancel-button" @click="cancelCommand"><text class="cancel-text">取消</text></view> | ||
| 97 | + <view @click="handleAppCommand" class="confrim-button"><text class="confrim-text">确认</text> | ||
| 98 | + </view> | ||
| 99 | + </view> | ||
| 100 | + </view> | ||
| 101 | + </view> | ||
| 102 | + </view> | ||
| 103 | + <!-- #endif --> | ||
| 104 | + <!-- #ifdef MP --> | ||
| 105 | + <!-- u-modal在app端弹窗层级无法覆盖背景色 --> | ||
| 106 | + <mp-command-issuance ref="mpCommandIssuanceRef" :isShowTCP="isShowTCP" :showModal="mpShowModal" | ||
| 107 | + @hideModal="hideMpModal" @cancelCommand="cancelCommand" | ||
| 108 | + @confirmCommand="confirmCommand"></mp-command-issuance> | ||
| 109 | + <!-- #endif --> | ||
| 110 | + </view> | ||
| 111 | +</template> | ||
| 112 | + | ||
| 113 | +<script> | ||
| 114 | + import {formatToDate} from '@/plugins/utils.js'; | ||
| 115 | + import {issueCommand} from '../api/index.js'; | ||
| 116 | + import api from '@/api/index.js'; | ||
| 117 | + import mpCommandIssuance from './mp-command-issuance.vue'; | ||
| 118 | + import {commandTypeList} from '../config/data.js' | ||
| 119 | + import {useShowModal} from '@/plugins/utils.js' | ||
| 120 | + | ||
| 121 | + export default { | ||
| 122 | + components: { | ||
| 123 | + mpCommandIssuance, | ||
| 124 | + }, | ||
| 125 | + props: { | ||
| 126 | + deviceDetail: { | ||
| 127 | + type: Object, | ||
| 128 | + default: () => ({}) | ||
| 129 | + } | ||
| 130 | + }, | ||
| 131 | + data() { | ||
| 132 | + return { | ||
| 133 | + showNativeModal: false, | ||
| 134 | + current: 0, | ||
| 135 | + commandTypeList, | ||
| 136 | + commandTypeStr: 'OneWay', | ||
| 137 | + inputCommandContent: '', | ||
| 138 | + mpShowModal: false, | ||
| 139 | + commandValue: {}, | ||
| 140 | + isShowTCP: false, //用于下发命令时判断是否是TCP/UDP | ||
| 141 | + modalName: null, | ||
| 142 | + copyTextValue: { | ||
| 143 | + "method": "methodThingskit", | ||
| 144 | + "params": { | ||
| 145 | + "pin": 7, | ||
| 146 | + "value": 1 | ||
| 147 | + } | ||
| 148 | + } | ||
| 149 | + }; | ||
| 150 | + }, | ||
| 151 | + computed: { | ||
| 152 | + deviceStatus() { | ||
| 153 | + return this.deviceDetail.deviceState === 'INACTIVE' ? '待激活' : this.deviceDetail.deviceState === 'ONLINE' ? | ||
| 154 | + '在线' : '离线'; | ||
| 155 | + }, | ||
| 156 | + deviceType() { | ||
| 157 | + return this.deviceDetail.deviceType === 'DIRECT_CONNECTION' ? | ||
| 158 | + '直连设备' : | ||
| 159 | + this.deviceDetail.deviceType === 'GATEWAY' ? | ||
| 160 | + '网关设备' : | ||
| 161 | + this.deviceDetail.deviceType === 'SENSOR' ? | ||
| 162 | + '网关子设备' : | ||
| 163 | + ''; | ||
| 164 | + }, | ||
| 165 | + alarmStatus() { | ||
| 166 | + return this.deviceDetail.alarmStatus === '0' ? '否' : '是'; | ||
| 167 | + }, | ||
| 168 | + formatLastOnlineTime() { | ||
| 169 | + return formatToDate(Number(this.deviceDetail.lastOnlineTime), 'YYYY-MM-DD HH:mm:ss'); | ||
| 170 | + } | ||
| 171 | + }, | ||
| 172 | + beforeCreate() { | ||
| 173 | + this.modalName = null | ||
| 174 | + }, | ||
| 175 | + onLoad() { | ||
| 176 | + // 隐藏原生的tabbar | ||
| 177 | + uni.hideTabBar(); | ||
| 178 | + this.modalName = null | ||
| 179 | + }, | ||
| 180 | + methods: { | ||
| 181 | + handleCopy(value) { | ||
| 182 | + useShowModal(JSON.stringify(value), '命令下发', '复制内容').then(res => { | ||
| 183 | + uni.setClipboardData({ | ||
| 184 | + data: JSON.stringify(value), | ||
| 185 | + success: () => { | ||
| 186 | + uni.showToast({ | ||
| 187 | + title: '复制成功' | ||
| 188 | + }) | ||
| 189 | + } | ||
| 190 | + }); | ||
| 191 | + }) | ||
| 192 | + }, | ||
| 193 | + radioChange: function(evt) { | ||
| 194 | + for (let i = 0; i < this.commandTypeList.length; i++) { | ||
| 195 | + if (this.items[i].value === evt.detail.value) { | ||
| 196 | + this.current = i; | ||
| 197 | + break; | ||
| 198 | + } | ||
| 199 | + } | ||
| 200 | + this.commandTypeStr = evt.detail.value | ||
| 201 | + }, | ||
| 202 | + formatTextStatus(deviceState) { | ||
| 203 | + return deviceState === 'INACTIVE' ? '#666' : deviceState === 'ONLINE' ? '#377DFF' : '#DE4437'; | ||
| 204 | + }, | ||
| 205 | + handleClick() { | ||
| 206 | + const data = { | ||
| 207 | + longitude: this.deviceDetail.deviceInfo.longitude || 0, | ||
| 208 | + latitude: this.deviceDetail.deviceInfo.latitude || 0 | ||
| 209 | + }; | ||
| 210 | + uni.navigateTo({ | ||
| 211 | + url: '/device-subpackage/device-detail/device-position?data=' + JSON.stringify(data) | ||
| 212 | + }); | ||
| 213 | + }, | ||
| 214 | + disabledScroll() { | ||
| 215 | + return; | ||
| 216 | + }, | ||
| 217 | + handleAppShowModal(e) { | ||
| 218 | + this.modalName = e.currentTarget.dataset.target; | ||
| 219 | + this.showNativeModal = true | ||
| 220 | + }, | ||
| 221 | + handleMpShowModal() { | ||
| 222 | + const { | ||
| 223 | + transportType | ||
| 224 | + } = this.deviceDetail.deviceProfile; | ||
| 225 | + this.isShowTCP = transportType == 'TCP' ? true : false; | ||
| 226 | + this.mpShowModal = true; | ||
| 227 | + }, | ||
| 228 | + hideMpModal() { | ||
| 229 | + this.mpShowModal = false; | ||
| 230 | + }, | ||
| 231 | + hideAppModal() { | ||
| 232 | + this.modalName = null; | ||
| 233 | + this.showNativeModal = false | ||
| 234 | + }, | ||
| 235 | + confirmCommand(commandType, inputCommandVal) { | ||
| 236 | + this.handleCommand(commandType, inputCommandVal) | ||
| 237 | + }, | ||
| 238 | + cancelCommand() { | ||
| 239 | + this.hideMpModal(); | ||
| 240 | + this.hideAppModal(); | ||
| 241 | + this.commandTypeStr = 'OneWay' | ||
| 242 | + this.inputCommandContent = '' | ||
| 243 | + this.$nextTick(() => { | ||
| 244 | + this.$refs.mpCommandIssuanceRef.reset() | ||
| 245 | + }) | ||
| 246 | + }, | ||
| 247 | + handleAppCommand() { | ||
| 248 | + this.handleCommand(this.commandTypeStr, this.inputCommandContent) | ||
| 249 | + }, | ||
| 250 | + async handleCommand(commandType, inputCommandVal) { | ||
| 251 | + if (!inputCommandVal) return uni.$u.toast('请输入下发内容~'); | ||
| 252 | + if (this.isShowTCP) { | ||
| 253 | + //TCP的格式只能是字符串 | ||
| 254 | + const zg = /^[0-9a-zA-Z]*$/; | ||
| 255 | + if (!zg.test(inputCommandVal)) { | ||
| 256 | + uni.$u.toast('输入的内容只能是字母和数字的组合'); | ||
| 257 | + return; | ||
| 258 | + } | ||
| 259 | + this.commandValue.params = inputCommandVal; | ||
| 260 | + } else { | ||
| 261 | + this.commandValue.params = JSON.parse(inputCommandVal); | ||
| 262 | + } | ||
| 263 | + this.commandValue.persistent = true; | ||
| 264 | + this.commandValue.additionalInfo = { | ||
| 265 | + cmdType: 'API' | ||
| 266 | + }; | ||
| 267 | + this.commandValue.method = 'methodThingskit'; | ||
| 268 | + this.commandValue.params = inputCommandVal; | ||
| 269 | + await api.deviceApi.issueCommand(commandType, this.deviceDetail.tbDeviceId, this.commandValue); | ||
| 270 | + this.cancelCommand(); | ||
| 271 | + uni.$u.toast('下发成功~'); | ||
| 272 | + | ||
| 273 | + }, | ||
| 274 | + | ||
| 275 | + } | ||
| 276 | + }; | ||
| 277 | +</script> | ||
| 278 | + | ||
| 279 | +<style lang="scss" scoped> | ||
| 280 | + @import url('../static/modal.css'); | ||
| 281 | + | ||
| 282 | + .app-command-content { | ||
| 283 | + .app-command-text { | ||
| 284 | + display: flex; | ||
| 285 | + justify-content: center; | ||
| 286 | + align-items: center; | ||
| 287 | + | ||
| 288 | + text { | ||
| 289 | + font-weight: 700; | ||
| 290 | + } | ||
| 291 | + } | ||
| 292 | + | ||
| 293 | + .app-command-type { | ||
| 294 | + display: flex; | ||
| 295 | + margin-top: 20rpx; | ||
| 296 | + margin-left: 20rpx; | ||
| 297 | + | ||
| 298 | + text { | ||
| 299 | + font-weight: 700; | ||
| 300 | + } | ||
| 301 | + } | ||
| 302 | + | ||
| 303 | + .app-command-body { | ||
| 304 | + display: flex; | ||
| 305 | + align-items: center; | ||
| 306 | + justify-content: space-between; | ||
| 307 | + margin-top: 20rpx; | ||
| 308 | + margin-left: 20rpx; | ||
| 309 | + | ||
| 310 | + .app-command-textarea { | ||
| 311 | + width: 625rpx; | ||
| 312 | + height: 400rpx; | ||
| 313 | + background: #FFFFFF; | ||
| 314 | + box-shadow: 2px 2px 4px 0px rgba(0, 0, 0, 0.03); | ||
| 315 | + border-radius: 10px; | ||
| 316 | + } | ||
| 317 | + } | ||
| 318 | + | ||
| 319 | + .app-command-buttons { | ||
| 320 | + display: flex; | ||
| 321 | + align-items: center; | ||
| 322 | + justify-content: space-evenly; | ||
| 323 | + height: 85rpx; | ||
| 324 | + margin-top: 20rpx; | ||
| 325 | + margin-bottom: 20rpx; | ||
| 326 | + | ||
| 327 | + .cancel-button { | ||
| 328 | + width: 300rpx; | ||
| 329 | + background: #e3e3e5; | ||
| 330 | + height: 85rpx; | ||
| 331 | + border-radius: 38rpx; | ||
| 332 | + line-height: 85rpx; | ||
| 333 | + | ||
| 334 | + .cancel-text { | ||
| 335 | + color: #333333 | ||
| 336 | + } | ||
| 337 | + } | ||
| 338 | + | ||
| 339 | + .confrim-button { | ||
| 340 | + width: 300rpx; | ||
| 341 | + background: #3388ff; | ||
| 342 | + border-radius: 38rpx; | ||
| 343 | + height: 85rpx; | ||
| 344 | + line-height: 85rpx; | ||
| 345 | + | ||
| 346 | + .confrim-text { | ||
| 347 | + color: white | ||
| 348 | + } | ||
| 349 | + } | ||
| 350 | + } | ||
| 351 | + } | ||
| 352 | + | ||
| 353 | + .basic-page { | ||
| 354 | + padding: 0 30rpx; | ||
| 355 | + | ||
| 356 | + .basic-header { | ||
| 357 | + display: flex; | ||
| 358 | + justify-content: space-between; | ||
| 359 | + align-items: center; | ||
| 360 | + height: 140rpx; | ||
| 361 | + background-color: #fff; | ||
| 362 | + border-radius: 20rpx; | ||
| 363 | + | ||
| 364 | + .basic-text { | ||
| 365 | + width: 370rpx; | ||
| 366 | + } | ||
| 367 | + | ||
| 368 | + .cu-item { | ||
| 369 | + background: #3388ff; | ||
| 370 | + border-radius: 12px; | ||
| 371 | + width: 120rpx; | ||
| 372 | + height: 48rpx; | ||
| 373 | + text-align: center; | ||
| 374 | + line-height: 40rpx; | ||
| 375 | + | ||
| 376 | + text { | ||
| 377 | + font-size: 12px; | ||
| 378 | + font-family: PingFangSC-Regular, PingFang SC; | ||
| 379 | + font-weight: 400; | ||
| 380 | + color: #ffffff; | ||
| 381 | + } | ||
| 382 | + } | ||
| 383 | + | ||
| 384 | + .basic-text-status { | ||
| 385 | + font-size: 14px; | ||
| 386 | + } | ||
| 387 | + } | ||
| 388 | + | ||
| 389 | + .detail { | ||
| 390 | + background-color: #fff; | ||
| 391 | + margin-top: 30rpx; | ||
| 392 | + border-radius: 20rpx; | ||
| 393 | + width: 690rpx; | ||
| 394 | + | ||
| 395 | + .detail-item { | ||
| 396 | + padding: 30rpx; | ||
| 397 | + display: flex; | ||
| 398 | + align-items: center; | ||
| 399 | + | ||
| 400 | + .detail-label { | ||
| 401 | + color: #333; | ||
| 402 | + font-size: 15px; | ||
| 403 | + } | ||
| 404 | + | ||
| 405 | + .detail-value { | ||
| 406 | + color: #666; | ||
| 407 | + font-size: 14px; | ||
| 408 | + margin-left: 30rpx; | ||
| 409 | + } | ||
| 410 | + } | ||
| 411 | + } | ||
| 412 | + } | ||
| 413 | + | ||
| 414 | + /deep/ .u-modal__content { | ||
| 415 | + padding: 30rpx 0 !important; | ||
| 416 | + } | ||
| 417 | +</style> |
device-subpackage/device-detail/components/command-detail.vue
renamed from
deviceSubPage/deviceDetailPage/tabDetail/CommandDetail.vue
| 1 | -<template> | ||
| 2 | - <view class="command-detail"> | ||
| 3 | - <view class="detail-top">{{ commandDetail.deviceName }}</view> | ||
| 4 | - <view class="detail"> | ||
| 5 | - <view class="detail-item"> | ||
| 6 | - <view class="detail-label">设备类型</view> | ||
| 7 | - <view class="detail-value">{{ deviceType }}</view> | ||
| 8 | - </view> | ||
| 9 | - <u-line length="90%" margin="0 auto"></u-line> | ||
| 10 | - <view class="detail-item"> | ||
| 11 | - <view class="detail-label">设备编号</view> | ||
| 12 | - <view class="detail-value">{{ commandDetail.deviceSn }}</view> | ||
| 13 | - </view> | ||
| 14 | - <u-line length="90%" margin="0 auto"></u-line> | ||
| 15 | - <view class="detail-item"> | ||
| 16 | - <view class="detail-label">所属组织</view> | ||
| 17 | - <view class="detail-value">{{ commandDetail.organizationName }}</view> | ||
| 18 | - </view> | ||
| 19 | - <u-line length="90%" margin="0 auto"></u-line> | ||
| 20 | - <view class="detail-item"> | ||
| 21 | - <view class="detail-label">命令下发时间</view> | ||
| 22 | - <view class="detail-value">{{ format(commandDetail.createTime) }}</view> | ||
| 23 | - </view> | ||
| 24 | - <u-line length="90%" margin="0 auto"></u-line> | ||
| 25 | - <view class="detail-item"> | ||
| 26 | - <view class="detail-label">命令类型</view> | ||
| 27 | - <view class="detail-value">{{ commandDetail.additionalInfo.cmdType===1?'服务':'自定义' }}</view> | ||
| 28 | - </view> | ||
| 29 | - <u-line length="90%" margin="0 auto" v-if="commandDetail.additionalInfo.cmdType"></u-line> | ||
| 30 | - <view class="detail-item"> | ||
| 31 | - <view class="detail-label">响应类型</view> | ||
| 32 | - <view class="detail-value">{{ commandDetail.request.oneway ? '单向' : '双向' }}</view> | ||
| 33 | - </view> | ||
| 34 | - <u-line length="90%" margin="0 auto"></u-line> | ||
| 35 | - <view class="detail-item"> | ||
| 36 | - <view class="detail-label">命令状态</view> | ||
| 37 | - <view class="detail-value">{{ commandDetail.statusName }}</view> | ||
| 38 | - </view> | ||
| 39 | - <u-line length="90%" margin="0 auto"></u-line> | ||
| 40 | - <view class="detail-item" v-if="!commandDetail.request.oneway"> | ||
| 41 | - <view class="detail-label">响应结果</view> | ||
| 42 | - <view class="detail-value">{{ commandDetail.response?JSON.stringify(commandDetail.response):'无' }}</view> | ||
| 43 | - </view> | ||
| 44 | - <!-- <view class="detail-item" v-if="!commandDetail.request.oneway"> | ||
| 45 | - <view class="detail-label">响应失败内容</view> | ||
| 46 | - <view class="detail-value" style="width: 400rpx;" v-if="commandDetail.response.status!=='SUCCESS'"> | ||
| 47 | - <u--textarea placeholder="响应失败内容" v-model="failContent" /> | ||
| 48 | - </view> | ||
| 49 | - </view> --> | ||
| 50 | - </view> | ||
| 51 | - <view class="command">命令内容</view> | ||
| 52 | - <u-textarea :value="formatValue(commandDetail.request.body)" disabled></u-textarea> | ||
| 53 | - <view style="height: 50rpx;"></view> | ||
| 54 | - </view> | ||
| 55 | -</template> | ||
| 56 | - | ||
| 57 | -<script> | ||
| 58 | - import { | ||
| 59 | - formatToDate | ||
| 60 | - } from '@/plugins/utils.js'; | ||
| 61 | - export default { | ||
| 62 | - data() { | ||
| 63 | - return { | ||
| 64 | - commandDetail: {}, | ||
| 65 | - failContent: "" | ||
| 66 | - }; | ||
| 67 | - }, | ||
| 68 | - computed: { | ||
| 69 | - deviceType() { | ||
| 70 | - return this.commandDetail.deviceType === 'DIRECT_CONNECTION' ? | ||
| 71 | - '直连设备' : | ||
| 72 | - this.commandDetail.deviceType === 'GATEWAY' ? | ||
| 73 | - '网关设备' : | ||
| 74 | - this.commandDetail.deviceType === 'SENSOR' ? | ||
| 75 | - '网关子设备' : | ||
| 76 | - ''; | ||
| 77 | - } | ||
| 78 | - }, | ||
| 79 | - methods: { | ||
| 80 | - format(date) { | ||
| 81 | - return formatToDate(date, 'YYYY-MM-DD HH:mm:ss'); | ||
| 82 | - }, | ||
| 83 | - formatValue(value) { | ||
| 84 | - try { | ||
| 85 | - const val = JSON.parse(value['params']); | ||
| 86 | - //微信小程序端object无法显示,格式化为字符串 | ||
| 87 | - const stringifyVal = JSON.stringify(val['params']) | ||
| 88 | - const formatVal = stringifyVal | ||
| 89 | - .replace(/\\"/g, '"') | ||
| 90 | - .replace(/]"/g, ']') | ||
| 91 | - .replace(/"\[/g, '['); | ||
| 92 | - return formatVal | ||
| 93 | - } catch (e) { | ||
| 94 | - console.error("命令记录页面格式化无返回值", e); | ||
| 95 | - return value['params'] | ||
| 96 | - } | ||
| 97 | - } | ||
| 98 | - }, | ||
| 99 | - onLoad(options) { | ||
| 100 | - const { | ||
| 101 | - data | ||
| 102 | - } = options; | ||
| 103 | - this.commandDetail = JSON.parse(data); | ||
| 104 | - if (this.commandDetail.response.status === 'SUCCESS') return | ||
| 105 | - this.failContent = JSON.stringify(this.commandDetail.response.error) | ||
| 106 | - } | ||
| 107 | - }; | ||
| 108 | -</script> | ||
| 109 | - | ||
| 110 | -<style lang="scss" scoped> | ||
| 111 | - .command-detail { | ||
| 112 | - padding: 0 30rpx; | ||
| 113 | - height: 100vh; | ||
| 114 | - background-color: #f8f9fa; | ||
| 115 | - | ||
| 116 | - .detail-top { | ||
| 117 | - height: 118rpx; | ||
| 118 | - width: 690rpx; | ||
| 119 | - display: flex; | ||
| 120 | - align-items: center; | ||
| 121 | - background-color: #fff; | ||
| 122 | - color: #333; | ||
| 123 | - border-radius: 20rpx; | ||
| 124 | - font-size: 15px; | ||
| 125 | - margin-top: 30rpx; | ||
| 126 | - padding: 30rpx; | ||
| 127 | - } | ||
| 128 | - | ||
| 129 | - .detail { | ||
| 130 | - background-color: #fff; | ||
| 131 | - margin-top: 30rpx; | ||
| 132 | - border-radius: 20rpx; | ||
| 133 | - width: 690rpx; | ||
| 134 | - | ||
| 135 | - .detail-item { | ||
| 136 | - padding: 30rpx; | ||
| 137 | - display: flex; | ||
| 138 | - align-items: center; | ||
| 139 | - | ||
| 140 | - .detail-label { | ||
| 141 | - color: #333; | ||
| 142 | - font-size: 15px; | ||
| 143 | - } | ||
| 144 | - | ||
| 145 | - .detail-value { | ||
| 146 | - color: #666; | ||
| 147 | - font-size: 14px; | ||
| 148 | - margin-left: 30rpx; | ||
| 149 | - } | ||
| 150 | - } | ||
| 151 | - } | ||
| 152 | - | ||
| 153 | - .command { | ||
| 154 | - margin: 30rpx 0; | ||
| 155 | - } | ||
| 156 | - } | ||
| 157 | -</style> | 1 | +<template> |
| 2 | + <view class="command-detail"> | ||
| 3 | + <view class="detail-top">{{ commandDetail.deviceName }}</view> | ||
| 4 | + <view class="detail"> | ||
| 5 | + <view class="detail-item"> | ||
| 6 | + <view class="detail-label">设备类型</view> | ||
| 7 | + <view class="detail-value">{{ deviceType }}</view> | ||
| 8 | + </view> | ||
| 9 | + <u-line length="90%" margin="0 auto"></u-line> | ||
| 10 | + <view class="detail-item"> | ||
| 11 | + <view class="detail-label">设备编号</view> | ||
| 12 | + <view class="detail-value">{{ commandDetail.deviceSn }}</view> | ||
| 13 | + </view> | ||
| 14 | + <u-line length="90%" margin="0 auto"></u-line> | ||
| 15 | + <view class="detail-item"> | ||
| 16 | + <view class="detail-label">所属组织</view> | ||
| 17 | + <view class="detail-value">{{ commandDetail.organizationName }}</view> | ||
| 18 | + </view> | ||
| 19 | + <u-line length="90%" margin="0 auto"></u-line> | ||
| 20 | + <view class="detail-item"> | ||
| 21 | + <view class="detail-label">命令下发时间</view> | ||
| 22 | + <view class="detail-value">{{ format(commandDetail.createTime) }}</view> | ||
| 23 | + </view> | ||
| 24 | + <u-line length="90%" margin="0 auto"></u-line> | ||
| 25 | + <view class="detail-item"> | ||
| 26 | + <view class="detail-label">命令类型</view> | ||
| 27 | + <view class="detail-value">{{ commandDetail.additionalInfo.cmdType===1?'服务':'自定义' }}</view> | ||
| 28 | + </view> | ||
| 29 | + <u-line length="90%" margin="0 auto" v-if="commandDetail.additionalInfo.cmdType"></u-line> | ||
| 30 | + <view class="detail-item"> | ||
| 31 | + <view class="detail-label">响应类型</view> | ||
| 32 | + <view class="detail-value">{{ commandDetail.request.oneway ? '单向' : '双向' }}</view> | ||
| 33 | + </view> | ||
| 34 | + <u-line length="90%" margin="0 auto"></u-line> | ||
| 35 | + <view class="detail-item"> | ||
| 36 | + <view class="detail-label">命令状态</view> | ||
| 37 | + <view class="detail-value">{{ commandDetail.statusName }}</view> | ||
| 38 | + </view> | ||
| 39 | + <u-line length="90%" margin="0 auto"></u-line> | ||
| 40 | + <view class="detail-item" v-if="!commandDetail.request.oneway"> | ||
| 41 | + <view class="detail-label">响应结果</view> | ||
| 42 | + <view class="detail-value">{{ commandDetail.response?JSON.stringify(commandDetail.response):'无' }} | ||
| 43 | + </view> | ||
| 44 | + </view> | ||
| 45 | + </view> | ||
| 46 | + <view class="command">命令内容</view> | ||
| 47 | + <u-textarea :value="formatValue(commandDetail.request.body)" disabled></u-textarea> | ||
| 48 | + <view style="height: 50rpx;"></view> | ||
| 49 | + </view> | ||
| 50 | +</template> | ||
| 51 | + | ||
| 52 | +<script> | ||
| 53 | + import { | ||
| 54 | + formatToDate | ||
| 55 | + } from '@/plugins/utils.js'; | ||
| 56 | + export default { | ||
| 57 | + data() { | ||
| 58 | + return { | ||
| 59 | + commandDetail: {}, | ||
| 60 | + failContent: "" | ||
| 61 | + }; | ||
| 62 | + }, | ||
| 63 | + computed: { | ||
| 64 | + deviceType() { | ||
| 65 | + return this.commandDetail.deviceType === 'DIRECT_CONNECTION' ? | ||
| 66 | + '直连设备' : | ||
| 67 | + this.commandDetail.deviceType === 'GATEWAY' ? | ||
| 68 | + '网关设备' : | ||
| 69 | + this.commandDetail.deviceType === 'SENSOR' ? | ||
| 70 | + '网关子设备' : | ||
| 71 | + ''; | ||
| 72 | + } | ||
| 73 | + }, | ||
| 74 | + methods: { | ||
| 75 | + format(date) { | ||
| 76 | + return formatToDate(date, 'YYYY-MM-DD HH:mm:ss'); | ||
| 77 | + }, | ||
| 78 | + formatValue(value) { | ||
| 79 | + try { | ||
| 80 | + const val = JSON.parse(value['params']); | ||
| 81 | + //微信小程序端object无法显示,格式化为字符串 | ||
| 82 | + const stringifyVal = JSON.stringify(val['params']) | ||
| 83 | + const formatVal = stringifyVal | ||
| 84 | + .replace(/\\"/g, '"') | ||
| 85 | + .replace(/]"/g, ']') | ||
| 86 | + .replace(/"\[/g, '['); | ||
| 87 | + return formatVal | ||
| 88 | + } catch (e) { | ||
| 89 | + return value['params'] | ||
| 90 | + } | ||
| 91 | + } | ||
| 92 | + }, | ||
| 93 | + onLoad(options) { | ||
| 94 | + const { data } = options; | ||
| 95 | + this.commandDetail = JSON.parse(decodeURIComponent(data)); | ||
| 96 | + if (this.commandDetail.response.status === 'SUCCESS') return | ||
| 97 | + this.failContent = JSON.stringify(this.commandDetail.response.error) | ||
| 98 | + } | ||
| 99 | + }; | ||
| 100 | +</script> | ||
| 101 | + | ||
| 102 | +<style lang="scss" scoped> | ||
| 103 | + @import "../static/command-detail.scss"; | ||
| 104 | +</style> |
| 1 | +<template> | ||
| 2 | + <view class="command-record"> | ||
| 3 | + <!-- 命令记录筛选--> | ||
| 4 | + <view class="filter-button" @click="openSearchDialog"> | ||
| 5 | + <text>筛选</text> | ||
| 6 | + <image src="/static/shaixuan.png" /> | ||
| 7 | + </view> | ||
| 8 | + <!-- 命令记录分页 --> | ||
| 9 | + <mescroll-uni ref="mescrollRef" @init="mescrollInit" :down="downOption" @down="downCallback" @up="upCallback" | ||
| 10 | + height="700px"> | ||
| 11 | + <view @click="openCommandDetail(item)" class="list-item" v-for="(item, index) in list" :key="index"> | ||
| 12 | + <view class="item"> | ||
| 13 | + <view class="item-first"> | ||
| 14 | + <text>{{ item.deviceName }}</text> | ||
| 15 | + <!-- 业务 单向是没有响应状态 --> | ||
| 16 | + <view v-if="!item.request.oneway"> | ||
| 17 | + <view class="item-right item-success" v-if="item.response">响应成功</view> | ||
| 18 | + <view class="item-right item-fail" v-else>响应失败</view> | ||
| 19 | + </view> | ||
| 20 | + </view> | ||
| 21 | + <view> | ||
| 22 | + 命令类型: | ||
| 23 | + <text class="ml-16">{{ item.additionalInfo.cmdType===1?'服务':'自定义' }}</text> | ||
| 24 | + </view> | ||
| 25 | + <view v-if="item.statusName"> | ||
| 26 | + 命令状态: | ||
| 27 | + <text :style="{color:formatCommandStatus(item.status)}" class="ml-16"> | ||
| 28 | + {{ item.statusName }} | ||
| 29 | + </text> | ||
| 30 | + </view> | ||
| 31 | + <view class="item-first"> | ||
| 32 | + <view> | ||
| 33 | + 响应类型: | ||
| 34 | + <text class="ml-16">{{ !item.request.oneway?'双向':'单向' }}</text> | ||
| 35 | + </view> | ||
| 36 | + <view class="time">{{ format(item.createTime) }}</view> | ||
| 37 | + </view> | ||
| 38 | + </view> | ||
| 39 | + </view> | ||
| 40 | + </mescroll-uni> | ||
| 41 | + <!-- 命令记录弹窗筛选 --> | ||
| 42 | + <u-popup @close="close" closeable bgColor="#fff" :show="show" mode="bottom" :round="20"> | ||
| 43 | + <view class="filter" @touchmove.stop.prevent="disabledScroll"> | ||
| 44 | + <view class="filter-title"><text>筛选条件</text></view> | ||
| 45 | + <query-item :filterList="issueStatus" title="下发状态" | ||
| 46 | + @clickTag="currentIndex => handleClickTag(currentIndex, issueStatus)"></query-item> | ||
| 47 | + <view class="flex-column"> | ||
| 48 | + <view class="mt-3 command-time-text">命令下发时间</view> | ||
| 49 | + <view class="mt-3"> | ||
| 50 | + <uni-datetime-picker return-type="timestamp" v-model="range" type="datetimerange" | ||
| 51 | + rangeSeparator="至" /> | ||
| 52 | + </view> | ||
| 53 | + </view> | ||
| 54 | + <view class="h-30"></view> | ||
| 55 | + <view class="button-group"> | ||
| 56 | + <view> | ||
| 57 | + <u-button :customStyle="{ color: '#333' }" color="#e3e3e5" shape="circle" text="重置" | ||
| 58 | + @click="resetFilter"></u-button> | ||
| 59 | + </view> | ||
| 60 | + <view> | ||
| 61 | + <u-button color="#3388ff" shape="circle" text="确认" @click="confirmFilter"></u-button> | ||
| 62 | + </view> | ||
| 63 | + </view> | ||
| 64 | + </view> | ||
| 65 | + </u-popup> | ||
| 66 | + </view> | ||
| 67 | +</template> | ||
| 68 | +<script> | ||
| 69 | + import queryItem from '@/pages/device/components/query-item.vue'; | ||
| 70 | + import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js'; | ||
| 71 | + import { | ||
| 72 | + formatToDate | ||
| 73 | + } from '@/plugins/utils.js'; | ||
| 74 | + import { | ||
| 75 | + debounce | ||
| 76 | + } from '@/plugins/throttle.js'; | ||
| 77 | + import { | ||
| 78 | + issueStatus | ||
| 79 | + } from '../config/data.js' | ||
| 80 | + import api from '@/api/index.js' | ||
| 81 | + import { | ||
| 82 | + useNavigateTo | ||
| 83 | + } from '@/plugins/utils.js' | ||
| 84 | + | ||
| 85 | + export default { | ||
| 86 | + mixins: [MescrollMixin], | ||
| 87 | + components: { | ||
| 88 | + queryItem | ||
| 89 | + }, | ||
| 90 | + props: { | ||
| 91 | + tbDeviceId: { | ||
| 92 | + type: String, | ||
| 93 | + default: '' | ||
| 94 | + } | ||
| 95 | + }, | ||
| 96 | + data() { | ||
| 97 | + return { | ||
| 98 | + show: false, | ||
| 99 | + list: [], | ||
| 100 | + total: 0, | ||
| 101 | + range: [], | ||
| 102 | + formTime: { | ||
| 103 | + status: '', | ||
| 104 | + startTime: '', | ||
| 105 | + endTime: '' | ||
| 106 | + }, | ||
| 107 | + status: '', | ||
| 108 | + issueStatus, | ||
| 109 | + downOption: { | ||
| 110 | + auto: false //是否在初始化后,自动执行downCallback; 默认true | ||
| 111 | + }, | ||
| 112 | + page: { | ||
| 113 | + num: 0, | ||
| 114 | + size: 10 | ||
| 115 | + } | ||
| 116 | + }; | ||
| 117 | + }, | ||
| 118 | + methods: { | ||
| 119 | + formatCommandStatus(status) { | ||
| 120 | + return status == 'EXPIRED' ? | ||
| 121 | + 'red' : | ||
| 122 | + status == 'DELIVERED' ? | ||
| 123 | + 'blue' : | ||
| 124 | + status == 'QUEUED' ? | ||
| 125 | + '#00C9A7' : | ||
| 126 | + status == 'TIMEOUT' ? | ||
| 127 | + 'red' : | ||
| 128 | + status == 'SENT' ? | ||
| 129 | + '#00C9A7' : '' | ||
| 130 | + }, | ||
| 131 | + downCallback() { | ||
| 132 | + for (let i in this.formTime) Reflect.set(this.formTime, i, '') | ||
| 133 | + this.list = []; | ||
| 134 | + this.page.num = 1; | ||
| 135 | + this.loadData(this.page.num, { | ||
| 136 | + tbDeviceId: this.tbDeviceId | ||
| 137 | + }); | ||
| 138 | + }, | ||
| 139 | + format(date) { | ||
| 140 | + return formatToDate(date, 'YYYY-MM-DD HH:mm:ss'); | ||
| 141 | + }, | ||
| 142 | + disabledScroll() { | ||
| 143 | + return; | ||
| 144 | + }, | ||
| 145 | + upCallback() { | ||
| 146 | + const tbDeviceId = { | ||
| 147 | + tbDeviceId: this.tbDeviceId | ||
| 148 | + } | ||
| 149 | + const condition = Object.values(this.formTime) | ||
| 150 | + if (condition.length === 0) { | ||
| 151 | + this.page.num += 1; | ||
| 152 | + this.loadData(this.page.num, { | ||
| 153 | + ...tbDeviceId | ||
| 154 | + }); | ||
| 155 | + } else if (condition.filter(Boolean).length > 0) { | ||
| 156 | + this.page.num += 1; | ||
| 157 | + this.loadData(this.page.num, { | ||
| 158 | + ...this.formTime, | ||
| 159 | + ...tbDeviceId | ||
| 160 | + }); | ||
| 161 | + } else { | ||
| 162 | + this.page.num += 1; | ||
| 163 | + this.loadData(this.page.num, { | ||
| 164 | + ...tbDeviceId | ||
| 165 | + }); | ||
| 166 | + } | ||
| 167 | + }, | ||
| 168 | + async loadData(pageNo, params = {}) { | ||
| 169 | + let httpData = { | ||
| 170 | + ...params, | ||
| 171 | + page: pageNo, | ||
| 172 | + pageSize: 10 | ||
| 173 | + }; | ||
| 174 | + const res = await api.deviceApi.getRpcRecord({ | ||
| 175 | + params: httpData, | ||
| 176 | + custom: { | ||
| 177 | + load: false | ||
| 178 | + } | ||
| 179 | + }) | ||
| 180 | + if (!res) return | ||
| 181 | + this.total = res.total; | ||
| 182 | + uni.stopPullDownRefresh(); | ||
| 183 | + this.mescroll.endByPage(res.items.length, res.total); | ||
| 184 | + if (pageNo == 1) { | ||
| 185 | + this.list = res.items; | ||
| 186 | + } else { | ||
| 187 | + this.list = this.list.concat(res.items); | ||
| 188 | + } | ||
| 189 | + }, | ||
| 190 | + handleClickTag(currentIndex, list) { | ||
| 191 | + list.map((item, index) => { | ||
| 192 | + item.checked = index === currentIndex; | ||
| 193 | + }); | ||
| 194 | + }, | ||
| 195 | + resetFilter() { | ||
| 196 | + const { | ||
| 197 | + issueStatus | ||
| 198 | + } = this; | ||
| 199 | + issueStatus.forEach(item => item.checked = false) | ||
| 200 | + issueStatus[0].checked = true | ||
| 201 | + }, | ||
| 202 | + close() { | ||
| 203 | + this.show = false; | ||
| 204 | + }, | ||
| 205 | + openSearchDialog() { | ||
| 206 | + this.show = true; | ||
| 207 | + this.resetFilter() | ||
| 208 | + this.range = [] | ||
| 209 | + for (let i in this.formTime) Reflect.set(this.formTime, i, '') | ||
| 210 | + }, | ||
| 211 | + hideKeyboard() { | ||
| 212 | + uni.hideKeyboard(); | ||
| 213 | + }, | ||
| 214 | + confirmFilter() { | ||
| 215 | + this.formTime.startTime = this.range[0] | ||
| 216 | + this.formTime.endTime = this.range[1] | ||
| 217 | + const issueStatus = this.issueStatus.find(item => item.checked); | ||
| 218 | + this.formTime.status = issueStatus.type ? issueStatus.type : undefined, | ||
| 219 | + this.loadData(1, { | ||
| 220 | + tbDeviceId: this.tbDeviceId, | ||
| 221 | + ...this.formTime | ||
| 222 | + }); | ||
| 223 | + this.show = false; | ||
| 224 | + }, | ||
| 225 | + openCommandDetail(item) { | ||
| 226 | + useNavigateTo('/device-subpackage/device-detail/components/command-detail?data=', item) | ||
| 227 | + } | ||
| 228 | + } | ||
| 229 | + }; | ||
| 230 | +</script> | ||
| 231 | + | ||
| 232 | + | ||
| 233 | +<style lang="scss" scoped> | ||
| 234 | + @import "../static/command-record.scss"; | ||
| 235 | +</style> |
device-subpackage/device-detail/components/history-data.vue
renamed from
deviceSubPage/deviceDetailPage/tabDetail/historyData.vue
| 1 | -<template> | ||
| 2 | - <view class="historyData"> | ||
| 3 | - <!-- 公共组件-每个页面必须引入 --> | ||
| 4 | - <public-module></public-module> | ||
| 5 | - <view class="historyData-top"> | ||
| 6 | - <u-form :label-style="{ 'font-size': '0rpx' }"> | ||
| 7 | - <u-form-item @click="openCalendar"> | ||
| 8 | - <u-input v-model="timeData.selectTime" disabled disabledColor="#fff" placeholder="请选择日期" | ||
| 9 | - border="none" suffixIcon="arrow-down"> | ||
| 10 | - <template slot="prefix"> | ||
| 11 | - <image class="icon" src="../../../static/can-der.png"></image> | ||
| 12 | - </template> | ||
| 13 | - </u-input> | ||
| 14 | - </u-form-item> | ||
| 15 | - <u-form-item @click="openTimeGap"> | ||
| 16 | - <u-input v-model="timeData.getTimeGap" disabled disabledColor="#fff" placeholder="请选择时间区间" | ||
| 17 | - border="none" suffixIcon="arrow-down"> | ||
| 18 | - <template slot="prefix"> | ||
| 19 | - <image class="icon" src="../../../static/time.png"></image> | ||
| 20 | - </template> | ||
| 21 | - </u-input> | ||
| 22 | - </u-form-item> | ||
| 23 | - <u-form-item @click="openAvg"> | ||
| 24 | - <u-input shape="circle" v-model="aggText" placeholder="请选择数据聚合功能" disabled disabledColor="#377DFF0D" | ||
| 25 | - suffixIcon="arrow-down" /> | ||
| 26 | - </u-form-item> | ||
| 27 | - <u-form-item @click="openTimeGap" v-if="limitFlag"> | ||
| 28 | - <view class="u-flex"> | ||
| 29 | - <text>最大条数</text> | ||
| 30 | - <u-number-box style="margin-left:30rpx" class="ml-10" v-model="timeData.limit" :min="7" | ||
| 31 | - :max="50000"></u-number-box> | ||
| 32 | - </view> | ||
| 33 | - </u-form-item> | ||
| 34 | - <u-form-item @click="openType"> | ||
| 35 | - <u-input shape="circle" v-model="timeData.getType" placeholder="请选择属性" disabled | ||
| 36 | - disabledColor="#377DFF0D" suffixIcon="arrow-down" /> | ||
| 37 | - </u-form-item> | ||
| 38 | - </u-form> | ||
| 39 | - | ||
| 40 | - <view class="charts-box" v-show="historyData.length"> | ||
| 41 | - <qiun-data-charts type="area" canvas2d canvasId="daskujdhasljkdcnzjkdfhuoqwlqwjhkdsamjczxnmdasd123321" | ||
| 42 | - :chartData="chartData" :ontouch="true" | ||
| 43 | - :opts="{ xAxis: { disabled: true, itemCount: 6, scrollShow: true }, legend: { show: false }, enableScroll: true }" /> | ||
| 44 | - </view> | ||
| 45 | - <mescroll-empty v-if="!historyData.length" /> | ||
| 46 | - </view> | ||
| 47 | - <view class="historyData-bottom" v-show="historyData.length"> | ||
| 48 | - <view class="table"> | ||
| 49 | - <view class="tr bg-w" v-if="historyData.length"> | ||
| 50 | - <view class="th">变量值</view> | ||
| 51 | - <view class="th">更新时间</view> | ||
| 52 | - </view> | ||
| 53 | - <view class="tr bg-g" :class="{ odd: index % 2 === 0 }" v-for="(item, index) in historyData" | ||
| 54 | - :key="index"> | ||
| 55 | - <view class="td">{{ item.value }}</view> | ||
| 56 | - <view class="td">{{ item.ts }}</view> | ||
| 57 | - </view> | ||
| 58 | - </view> | ||
| 59 | - </view> | ||
| 60 | - <u-calendar :show="showCalendar" :defaultDate="defaultDate" closeOnClickOverlay mode="range" startText="开始时间" | ||
| 61 | - endText="结束时间" confirmDisabledText="请选择日期" :minDate="minDate" :maxDate="maxDate" @confirm="calendarConfirm" | ||
| 62 | - @close="calendarClose"></u-calendar> | ||
| 63 | - <u-picker :show="showTimeGap" :columns="columns" keyName="label" closeOnClickOverlay @confirm="confirmTimeGap" | ||
| 64 | - @cancel="cancelTimeGap" @close="cancelTimeGap" :defaultIndex="[3]"></u-picker> | ||
| 65 | - <u-picker :show="showSelectType" :columns="keys" closeOnClickOverlay @confirm="confirmTypeGap" | ||
| 66 | - @cancel="cancelTypeGap" @close="cancelTypeGap"></u-picker> | ||
| 67 | - <u-picker :show="showSelectAvg" :columns="avgColumns" keyName="label" closeOnClickOverlay | ||
| 68 | - @confirm="confirmAvgGap" @cancel="showSelectAvg=false" @close="showSelectAvg=false"></u-picker> | ||
| 69 | - </view> | ||
| 70 | -</template> | ||
| 71 | - | ||
| 72 | -<script> | ||
| 73 | - import fTabbar from '@/components/module/f-tabbar/f-tabbar'; | ||
| 74 | - import qiunDataCharts from '@/uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue'; | ||
| 75 | - import { | ||
| 76 | - getHistoryData | ||
| 77 | - } from '../api/index.js'; | ||
| 78 | - import { | ||
| 79 | - formatToDate | ||
| 80 | - } from '@/plugins/utils.js'; | ||
| 81 | - const d = new Date(); | ||
| 82 | - const year = d.getFullYear(); | ||
| 83 | - let month = d.getMonth() + 1; | ||
| 84 | - month = month < 10 ? `0${month}` : month; | ||
| 85 | - const date = d.getDate(); | ||
| 86 | - export default { | ||
| 87 | - components: { | ||
| 88 | - fTabbar, | ||
| 89 | - qiunDataCharts | ||
| 90 | - }, | ||
| 91 | - props: { | ||
| 92 | - keys: { | ||
| 93 | - type: Array, | ||
| 94 | - default: () => [] | ||
| 95 | - }, | ||
| 96 | - yesterday: { | ||
| 97 | - type: String, | ||
| 98 | - default: '' | ||
| 99 | - }, | ||
| 100 | - today: { | ||
| 101 | - type: String, | ||
| 102 | - default: '' | ||
| 103 | - }, | ||
| 104 | - timeDiff: { | ||
| 105 | - type: String, | ||
| 106 | - default: '' | ||
| 107 | - }, | ||
| 108 | - historyData: { | ||
| 109 | - type: Array, | ||
| 110 | - default: () => [] | ||
| 111 | - }, | ||
| 112 | - entityId: { | ||
| 113 | - type: String, | ||
| 114 | - required: true | ||
| 115 | - }, | ||
| 116 | - start: { | ||
| 117 | - type: String, | ||
| 118 | - required: true | ||
| 119 | - }, | ||
| 120 | - end: { | ||
| 121 | - type: String, | ||
| 122 | - required: true | ||
| 123 | - } | ||
| 124 | - }, | ||
| 125 | - data() { | ||
| 126 | - return { | ||
| 127 | - limitFlag: true, | ||
| 128 | - avgColumns: [ | ||
| 129 | - [{ | ||
| 130 | - label: '最小值', | ||
| 131 | - value: 'MIN' | ||
| 132 | - }, { | ||
| 133 | - label: '最大值', | ||
| 134 | - value: 'MAX' | ||
| 135 | - }, | ||
| 136 | - { | ||
| 137 | - label: '平均值', | ||
| 138 | - value: 'AVG' | ||
| 139 | - }, | ||
| 140 | - { | ||
| 141 | - label: '求和', | ||
| 142 | - value: 'SUM' | ||
| 143 | - }, | ||
| 144 | - { | ||
| 145 | - label: '计数', | ||
| 146 | - value: 'COUNT' | ||
| 147 | - }, | ||
| 148 | - { | ||
| 149 | - label: '空', | ||
| 150 | - value: 'NONE' | ||
| 151 | - }, | ||
| 152 | - ] | ||
| 153 | - ], | ||
| 154 | - startTs: this.start, | ||
| 155 | - endTs: this.end, | ||
| 156 | - showCalendar: false, | ||
| 157 | - showTimeGap: false, | ||
| 158 | - showSelectType: false, | ||
| 159 | - showSelectAvg: false, | ||
| 160 | - minDate: `${year}-${month - 1}-${date}`, | ||
| 161 | - maxDate: `${year}-${month}-${date + 1}`, | ||
| 162 | - defaultDate: [this.yesterday, this.today], | ||
| 163 | - chartData: { | ||
| 164 | - categories: this.historyData.length && this.historyData.map(item => item.ts), | ||
| 165 | - series: [{ | ||
| 166 | - name: this.keys[0][0], | ||
| 167 | - data: this.historyData.length && this.historyData.map(item => Number(item.value)) | ||
| 168 | - }] | ||
| 169 | - }, | ||
| 170 | - columns: [ | ||
| 171 | - [{ | ||
| 172 | - label: '5分钟', | ||
| 173 | - value: 300000 | ||
| 174 | - }, | ||
| 175 | - { | ||
| 176 | - label: '10分钟', | ||
| 177 | - value: 600000 | ||
| 178 | - }, | ||
| 179 | - { | ||
| 180 | - label: '15分钟', | ||
| 181 | - value: 900000 | ||
| 182 | - }, | ||
| 183 | - { | ||
| 184 | - label: '30分钟', | ||
| 185 | - value: 1800000 | ||
| 186 | - }, | ||
| 187 | - { | ||
| 188 | - label: '1小时', | ||
| 189 | - value: 3600000 | ||
| 190 | - }, | ||
| 191 | - { | ||
| 192 | - label: '2小时', | ||
| 193 | - value: 7200000 | ||
| 194 | - } | ||
| 195 | - ] | ||
| 196 | - ], | ||
| 197 | - timeData: { | ||
| 198 | - selectTime: this.yesterday + ' 至 ' + this.today, | ||
| 199 | - getTimeGap: this.timeDiff, | ||
| 200 | - getType: this.keys[0][0], | ||
| 201 | - limit: 7, | ||
| 202 | - agg: 'NONE' | ||
| 203 | - }, | ||
| 204 | - aggText: '空' | ||
| 205 | - }; | ||
| 206 | - }, | ||
| 207 | - watch: { | ||
| 208 | - historyData(newValue) { | ||
| 209 | - if (!newValue.length) { | ||
| 210 | - this.chartData.categories = []; | ||
| 211 | - this.chartData.series = []; | ||
| 212 | - } else { | ||
| 213 | - this.chartData.categories = newValue.map(item => item.ts); | ||
| 214 | - this.chartData.series = [{ | ||
| 215 | - name: this.keys[0][0], | ||
| 216 | - data: newValue.map(item => Number(item.value)) | ||
| 217 | - }]; | ||
| 218 | - } | ||
| 219 | - } | ||
| 220 | - }, | ||
| 221 | - methods: { | ||
| 222 | - // 动态生成Columns | ||
| 223 | - generateColumns(value) { | ||
| 224 | - if (value < 604800000) { | ||
| 225 | - // 小于7天 | ||
| 226 | - return [ | ||
| 227 | - [{ | ||
| 228 | - label: '5分钟', | ||
| 229 | - value: 300000 | ||
| 230 | - }, | ||
| 231 | - { | ||
| 232 | - label: '10分钟', | ||
| 233 | - value: 600000 | ||
| 234 | - }, | ||
| 235 | - { | ||
| 236 | - label: '15分钟', | ||
| 237 | - value: 900000 | ||
| 238 | - }, | ||
| 239 | - { | ||
| 240 | - label: '30分钟', | ||
| 241 | - value: 1800000 | ||
| 242 | - }, | ||
| 243 | - { | ||
| 244 | - label: '1小时', | ||
| 245 | - value: 3600000 | ||
| 246 | - }, | ||
| 247 | - { | ||
| 248 | - label: '2小时', | ||
| 249 | - value: 7200000 | ||
| 250 | - } | ||
| 251 | - ] | ||
| 252 | - ]; | ||
| 253 | - } else if (value < 2592000000) { | ||
| 254 | - // 小于30天 | ||
| 255 | - return [ | ||
| 256 | - [{ | ||
| 257 | - label: '30分钟', | ||
| 258 | - value: 1800000 | ||
| 259 | - }, | ||
| 260 | - { | ||
| 261 | - label: '1小时', | ||
| 262 | - value: 3600000 | ||
| 263 | - }, | ||
| 264 | - { | ||
| 265 | - label: '2小时', | ||
| 266 | - value: 7200000 | ||
| 267 | - }, | ||
| 268 | - { | ||
| 269 | - label: '5小时', | ||
| 270 | - value: 18000000 | ||
| 271 | - }, | ||
| 272 | - { | ||
| 273 | - label: '10小时', | ||
| 274 | - value: 36000000 | ||
| 275 | - }, | ||
| 276 | - { | ||
| 277 | - label: '12小时', | ||
| 278 | - value: 43200000 | ||
| 279 | - }, | ||
| 280 | - { | ||
| 281 | - label: '1天', | ||
| 282 | - value: 86400000 | ||
| 283 | - } | ||
| 284 | - ] | ||
| 285 | - ]; | ||
| 286 | - } else if (value >= 2592000000) { | ||
| 287 | - // 大于30天 | ||
| 288 | - return [ | ||
| 289 | - [{ | ||
| 290 | - label: '2小时', | ||
| 291 | - value: 7200000 | ||
| 292 | - }, | ||
| 293 | - { | ||
| 294 | - label: '5小时', | ||
| 295 | - value: 18000000 | ||
| 296 | - }, | ||
| 297 | - { | ||
| 298 | - label: '10小时', | ||
| 299 | - value: 36000000 | ||
| 300 | - }, | ||
| 301 | - { | ||
| 302 | - label: '12小时', | ||
| 303 | - value: 43200000 | ||
| 304 | - }, | ||
| 305 | - { | ||
| 306 | - label: '1天', | ||
| 307 | - value: 86400000 | ||
| 308 | - } | ||
| 309 | - ] | ||
| 310 | - ]; | ||
| 311 | - } | ||
| 312 | - }, | ||
| 313 | - openCalendar() { | ||
| 314 | - this.showCalendar = true; | ||
| 315 | - }, | ||
| 316 | - openTimeGap() { | ||
| 317 | - this.showTimeGap = true; | ||
| 318 | - }, | ||
| 319 | - openType() { | ||
| 320 | - this.showSelectType = true; | ||
| 321 | - }, | ||
| 322 | - openAvg() { | ||
| 323 | - this.showSelectAvg = true | ||
| 324 | - }, | ||
| 325 | - calendarConfirm(date) { | ||
| 326 | - this.showCalendar = false; | ||
| 327 | - this.timeData.selectTime = `${date[0]} 至 ${date[date.length - 1]}`; | ||
| 328 | - // 选择的日期时间差(时间戳) | ||
| 329 | - const timeDiff = formatToDate(date[date.length - 1], 'x') - formatToDate(date[0], 'x'); | ||
| 330 | - const genColumns = this.generateColumns(timeDiff); | ||
| 331 | - this.columns = genColumns; | ||
| 332 | - this.timeData.getTimeGap = ''; | ||
| 333 | - this.timeData.getType = ''; | ||
| 334 | - this.startTs = formatToDate(date[0], 'x'); | ||
| 335 | - // 最后时间的最后一秒 | ||
| 336 | - this.endTs = formatToDate(`${date[date.length - 1]} 23:59:59`, 'x'); | ||
| 337 | - }, | ||
| 338 | - calendarClose() { | ||
| 339 | - this.showCalendar = false; | ||
| 340 | - }, | ||
| 341 | - confirmTimeGap(time) { | ||
| 342 | - this.showTimeGap = false; | ||
| 343 | - this.timeData.getTimeGap = time.value[0].label; | ||
| 344 | - this.timeData.getType = ''; | ||
| 345 | - }, | ||
| 346 | - | ||
| 347 | - cancelTimeGap() { | ||
| 348 | - this.showTimeGap = false; | ||
| 349 | - }, | ||
| 350 | - confirmAvgGap(e) { | ||
| 351 | - this.timeData.agg = e.value[0].value | ||
| 352 | - this.aggText = e.value[0].label | ||
| 353 | - if (e.value[0].value === 'NONE') { | ||
| 354 | - this.limitFlag = true | ||
| 355 | - this.timeData.limit = 7 | ||
| 356 | - } else { | ||
| 357 | - this.timeData.limit = null | ||
| 358 | - this.limitFlag = false | ||
| 359 | - } | ||
| 360 | - this.showSelectAvg = false | ||
| 361 | - }, | ||
| 362 | - async confirmTypeGap(time) { | ||
| 363 | - this.showSelectType = false; | ||
| 364 | - this.timeData.getType = time.value[0]; | ||
| 365 | - const interval = this.columns[0].find(item => item.label === this.timeData.getTimeGap); | ||
| 366 | - const data = await getHistoryData({ | ||
| 367 | - startTs: this.startTs, | ||
| 368 | - endTs: this.endTs, | ||
| 369 | - keys: this.timeData.getType, | ||
| 370 | - interval: this.limitFlag ? null : interval.value, | ||
| 371 | - entityId: this.entityId, | ||
| 372 | - limit: this.timeData.limit, | ||
| 373 | - agg: this.timeData.agg | ||
| 374 | - }); | ||
| 375 | - this.$emit('update', data[this.timeData.getType]); | ||
| 376 | - }, | ||
| 377 | - cancelTypeGap() { | ||
| 378 | - this.showSelectType = false; | ||
| 379 | - } | ||
| 380 | - } | ||
| 381 | - }; | ||
| 382 | -</script> | ||
| 383 | - | ||
| 384 | -<style lang="scss" scoped> | ||
| 385 | - .charts-box { | ||
| 386 | - width: 100%; | ||
| 387 | - height: 550rpx; | ||
| 388 | - } | ||
| 389 | - | ||
| 390 | - .historyData { | ||
| 391 | - margin: 30rpx; | ||
| 392 | - | ||
| 393 | - .historyData-top { | ||
| 394 | - padding: 30rpx; | ||
| 395 | - background-color: #fff; | ||
| 396 | - // height: 870rpx; | ||
| 397 | - border-radius: 20rpx; | ||
| 398 | - | ||
| 399 | - .icon { | ||
| 400 | - width: 28rpx; | ||
| 401 | - height: 28rpx; | ||
| 402 | - margin-right: 15rpx; | ||
| 403 | - } | ||
| 404 | - } | ||
| 405 | - | ||
| 406 | - .historyData-bottom { | ||
| 407 | - margin-top: 30rpx; | ||
| 408 | - background-color: #fff; | ||
| 409 | - border-radius: 20rpx; | ||
| 410 | - | ||
| 411 | - .table { | ||
| 412 | - border: 0px solid darkgray; | ||
| 413 | - | ||
| 414 | - .tr { | ||
| 415 | - display: flex; | ||
| 416 | - width: 100%; | ||
| 417 | - justify-content: center; | ||
| 418 | - height: 3rem; | ||
| 419 | - align-items: center; | ||
| 420 | - | ||
| 421 | - .th { | ||
| 422 | - display: flex; | ||
| 423 | - justify-content: center; | ||
| 424 | - align-items: center; | ||
| 425 | - width: 50%; | ||
| 426 | - color: #333; | ||
| 427 | - font-weight: 500; | ||
| 428 | - } | ||
| 429 | - | ||
| 430 | - .td { | ||
| 431 | - color: #999; | ||
| 432 | - width: 50%; | ||
| 433 | - display: flex; | ||
| 434 | - justify-content: center; | ||
| 435 | - text-align: center; | ||
| 436 | - } | ||
| 437 | - } | ||
| 438 | - } | ||
| 439 | - } | ||
| 440 | - } | ||
| 441 | - | ||
| 442 | - .odd { | ||
| 443 | - background-color: #f9fcff; | ||
| 444 | - } | 1 | +<template> |
| 2 | + <view class="historyData"> | ||
| 3 | + <!-- 公共组件-每个页面必须引入 --> | ||
| 4 | + <public-module></public-module> | ||
| 5 | + <view class="historyData-top"> | ||
| 6 | + <u-form :label-style="{ 'font-size': '0rpx' }"> | ||
| 7 | + <u-form-item @click="openCalendar"> | ||
| 8 | + <u-input v-model="timeData.selectTime" disabled disabledColor="#fff" placeholder="请选择日期" | ||
| 9 | + border="none" suffixIcon="arrow-down"> | ||
| 10 | + <template slot="prefix"> | ||
| 11 | + <image class="icon" src="../../../static/can-der.png"></image> | ||
| 12 | + </template> | ||
| 13 | + </u-input> | ||
| 14 | + </u-form-item> | ||
| 15 | + <u-form-item @click="openTimeGap"> | ||
| 16 | + <u-input v-model="timeData.getTimeGap" disabled disabledColor="#fff" placeholder="请选择时间区间" | ||
| 17 | + border="none" suffixIcon="arrow-down"> | ||
| 18 | + <template slot="prefix"> | ||
| 19 | + <image class="icon" src="../../../static/time.png"></image> | ||
| 20 | + </template> | ||
| 21 | + </u-input> | ||
| 22 | + </u-form-item> | ||
| 23 | + <u-form-item @click="openAvg"> | ||
| 24 | + <u-input shape="circle" v-model="aggText" placeholder="请选择数据聚合功能" disabled disabledColor="#377DFF0D" | ||
| 25 | + suffixIcon="arrow-down" /> | ||
| 26 | + </u-form-item> | ||
| 27 | + <u-form-item @click="openTimeGap" v-if="limitFlag"> | ||
| 28 | + <view class="u-flex"> | ||
| 29 | + <text>最大条数</text> | ||
| 30 | + <u-number-box style="margin-left:30rpx" class="ml-10" v-model="timeData.limit" :min="7" | ||
| 31 | + :max="50000"></u-number-box> | ||
| 32 | + </view> | ||
| 33 | + </u-form-item> | ||
| 34 | + <u-form-item @click="openType"> | ||
| 35 | + <u-input shape="circle" v-model="timeData.getType" placeholder="请选择属性" disabled | ||
| 36 | + disabledColor="#377DFF0D" suffixIcon="arrow-down" /> | ||
| 37 | + </u-form-item> | ||
| 38 | + </u-form> | ||
| 39 | + | ||
| 40 | + <view class="charts-box" v-show="historyData.length"> | ||
| 41 | + <qiun-data-charts type="area" canvas2d canvasId="daskujdhasljkdcnzjkdfhuoqwlqwjhkdsamjczxnmdasd123321" | ||
| 42 | + :chartData="chartData" :ontouch="true" | ||
| 43 | + :opts="{ xAxis: { disabled: true, itemCount: 6, scrollShow: true }, legend: { show: false }, enableScroll: true }" /> | ||
| 44 | + </view> | ||
| 45 | + <mescroll-empty v-if="!historyData.length" /> | ||
| 46 | + </view> | ||
| 47 | + <view class="historyData-bottom" v-show="historyData.length"> | ||
| 48 | + <view class="table"> | ||
| 49 | + <view class="tr bg-w" v-if="historyData.length"> | ||
| 50 | + <view class="th">变量值</view> | ||
| 51 | + <view class="th">更新时间</view> | ||
| 52 | + </view> | ||
| 53 | + <view class="tr bg-g" :class="{ odd: index % 2 === 0 }" v-for="(item, index) in historyData" | ||
| 54 | + :key="index"> | ||
| 55 | + <view class="td">{{ item.value }}</view> | ||
| 56 | + <view class="td">{{ item.ts }}</view> | ||
| 57 | + </view> | ||
| 58 | + </view> | ||
| 59 | + </view> | ||
| 60 | + <u-calendar :show="showCalendar" :defaultDate="defaultDate" closeOnClickOverlay mode="range" startText="开始时间" | ||
| 61 | + endText="结束时间" confirmDisabledText="请选择日期" :minDate="minDate" :maxDate="maxDate" @confirm="calendarConfirm" | ||
| 62 | + @close="calendarClose"></u-calendar> | ||
| 63 | + <u-picker :show="showTimeGap" :columns="columns" keyName="label" closeOnClickOverlay @confirm="confirmTimeGap" | ||
| 64 | + @cancel="cancelTimeGap" @close="cancelTimeGap" :defaultIndex="[3]"></u-picker> | ||
| 65 | + <u-picker :show="showSelectType" :columns="keys" closeOnClickOverlay @confirm="confirmTypeGap" | ||
| 66 | + @cancel="cancelTypeGap" @close="cancelTypeGap"></u-picker> | ||
| 67 | + <u-picker :show="showSelectAvg" :columns="avgColumns" keyName="label" closeOnClickOverlay | ||
| 68 | + @confirm="confirmAvgGap" @cancel="showSelectAvg=false" @close="showSelectAvg=false"></u-picker> | ||
| 69 | + </view> | ||
| 70 | +</template> | ||
| 71 | + | ||
| 72 | +<script> | ||
| 73 | + import fTabbar from '@/components/module/f-tabbar/f-tabbar'; | ||
| 74 | + import qiunDataCharts from './uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue'; | ||
| 75 | + import { | ||
| 76 | + getHistoryData | ||
| 77 | + } from '../api/index.js'; | ||
| 78 | + import { | ||
| 79 | + formatToDate | ||
| 80 | + } from '@/plugins/utils.js'; | ||
| 81 | + const d = new Date(); | ||
| 82 | + const year = d.getFullYear(); | ||
| 83 | + let month = d.getMonth() + 1; | ||
| 84 | + month = month < 10 ? `0${month}` : month; | ||
| 85 | + const date = d.getDate(); | ||
| 86 | + export default { | ||
| 87 | + components: { | ||
| 88 | + fTabbar, | ||
| 89 | + qiunDataCharts | ||
| 90 | + }, | ||
| 91 | + props: { | ||
| 92 | + keys: { | ||
| 93 | + type: Array, | ||
| 94 | + default: () => [] | ||
| 95 | + }, | ||
| 96 | + yesterday: { | ||
| 97 | + type: String, | ||
| 98 | + default: '' | ||
| 99 | + }, | ||
| 100 | + today: { | ||
| 101 | + type: String, | ||
| 102 | + default: '' | ||
| 103 | + }, | ||
| 104 | + timeDiff: { | ||
| 105 | + type: String, | ||
| 106 | + default: '' | ||
| 107 | + }, | ||
| 108 | + historyData: { | ||
| 109 | + type: Array, | ||
| 110 | + default: () => [] | ||
| 111 | + }, | ||
| 112 | + entityId: { | ||
| 113 | + type: String, | ||
| 114 | + required: true | ||
| 115 | + }, | ||
| 116 | + start: { | ||
| 117 | + type: String, | ||
| 118 | + required: true | ||
| 119 | + }, | ||
| 120 | + end: { | ||
| 121 | + type: String, | ||
| 122 | + required: true | ||
| 123 | + } | ||
| 124 | + }, | ||
| 125 | + data() { | ||
| 126 | + return { | ||
| 127 | + limitFlag: true, | ||
| 128 | + avgColumns: [ | ||
| 129 | + [{ | ||
| 130 | + label: '最小值', | ||
| 131 | + value: 'MIN' | ||
| 132 | + }, { | ||
| 133 | + label: '最大值', | ||
| 134 | + value: 'MAX' | ||
| 135 | + }, | ||
| 136 | + { | ||
| 137 | + label: '平均值', | ||
| 138 | + value: 'AVG' | ||
| 139 | + }, | ||
| 140 | + { | ||
| 141 | + label: '求和', | ||
| 142 | + value: 'SUM' | ||
| 143 | + }, | ||
| 144 | + { | ||
| 145 | + label: '计数', | ||
| 146 | + value: 'COUNT' | ||
| 147 | + }, | ||
| 148 | + { | ||
| 149 | + label: '空', | ||
| 150 | + value: 'NONE' | ||
| 151 | + }, | ||
| 152 | + ] | ||
| 153 | + ], | ||
| 154 | + startTs: this.start, | ||
| 155 | + endTs: this.end, | ||
| 156 | + showCalendar: false, | ||
| 157 | + showTimeGap: false, | ||
| 158 | + showSelectType: false, | ||
| 159 | + showSelectAvg: false, | ||
| 160 | + minDate: `${year}-${month - 1}-${date}`, | ||
| 161 | + maxDate: `${year}-${month}-${date + 1}`, | ||
| 162 | + defaultDate: [this.yesterday, this.today], | ||
| 163 | + chartData: { | ||
| 164 | + categories: this.historyData.length && this.historyData.map(item => item.ts), | ||
| 165 | + series: [{ | ||
| 166 | + name: this.keys[0][0], | ||
| 167 | + data: this.historyData.length && this.historyData.map(item => Number(item.value)) | ||
| 168 | + }] | ||
| 169 | + }, | ||
| 170 | + columns: [ | ||
| 171 | + [{ | ||
| 172 | + label: '5分钟', | ||
| 173 | + value: 300000 | ||
| 174 | + }, | ||
| 175 | + { | ||
| 176 | + label: '10分钟', | ||
| 177 | + value: 600000 | ||
| 178 | + }, | ||
| 179 | + { | ||
| 180 | + label: '15分钟', | ||
| 181 | + value: 900000 | ||
| 182 | + }, | ||
| 183 | + { | ||
| 184 | + label: '30分钟', | ||
| 185 | + value: 1800000 | ||
| 186 | + }, | ||
| 187 | + { | ||
| 188 | + label: '1小时', | ||
| 189 | + value: 3600000 | ||
| 190 | + }, | ||
| 191 | + { | ||
| 192 | + label: '2小时', | ||
| 193 | + value: 7200000 | ||
| 194 | + } | ||
| 195 | + ] | ||
| 196 | + ], | ||
| 197 | + timeData: { | ||
| 198 | + selectTime: this.yesterday + ' 至 ' + this.today, | ||
| 199 | + getTimeGap: this.timeDiff, | ||
| 200 | + getType: this.keys[0][0], | ||
| 201 | + limit: 7, | ||
| 202 | + agg: 'NONE' | ||
| 203 | + }, | ||
| 204 | + aggText: '空' | ||
| 205 | + }; | ||
| 206 | + }, | ||
| 207 | + watch: { | ||
| 208 | + historyData(newValue) { | ||
| 209 | + if (!newValue.length) { | ||
| 210 | + this.chartData.categories = []; | ||
| 211 | + this.chartData.series = []; | ||
| 212 | + } else { | ||
| 213 | + this.chartData.categories = newValue.map(item => item.ts); | ||
| 214 | + this.chartData.series = [{ | ||
| 215 | + name: this.keys[0][0], | ||
| 216 | + data: newValue.map(item => Number(item.value)) | ||
| 217 | + }]; | ||
| 218 | + } | ||
| 219 | + } | ||
| 220 | + }, | ||
| 221 | + methods: { | ||
| 222 | + // 动态生成Columns | ||
| 223 | + generateColumns(value) { | ||
| 224 | + if (value < 604800000) { | ||
| 225 | + // 小于7天 | ||
| 226 | + return [ | ||
| 227 | + [{ | ||
| 228 | + label: '5分钟', | ||
| 229 | + value: 300000 | ||
| 230 | + }, | ||
| 231 | + { | ||
| 232 | + label: '10分钟', | ||
| 233 | + value: 600000 | ||
| 234 | + }, | ||
| 235 | + { | ||
| 236 | + label: '15分钟', | ||
| 237 | + value: 900000 | ||
| 238 | + }, | ||
| 239 | + { | ||
| 240 | + label: '30分钟', | ||
| 241 | + value: 1800000 | ||
| 242 | + }, | ||
| 243 | + { | ||
| 244 | + label: '1小时', | ||
| 245 | + value: 3600000 | ||
| 246 | + }, | ||
| 247 | + { | ||
| 248 | + label: '2小时', | ||
| 249 | + value: 7200000 | ||
| 250 | + } | ||
| 251 | + ] | ||
| 252 | + ]; | ||
| 253 | + } else if (value < 2592000000) { | ||
| 254 | + // 小于30天 | ||
| 255 | + return [ | ||
| 256 | + [{ | ||
| 257 | + label: '30分钟', | ||
| 258 | + value: 1800000 | ||
| 259 | + }, | ||
| 260 | + { | ||
| 261 | + label: '1小时', | ||
| 262 | + value: 3600000 | ||
| 263 | + }, | ||
| 264 | + { | ||
| 265 | + label: '2小时', | ||
| 266 | + value: 7200000 | ||
| 267 | + }, | ||
| 268 | + { | ||
| 269 | + label: '5小时', | ||
| 270 | + value: 18000000 | ||
| 271 | + }, | ||
| 272 | + { | ||
| 273 | + label: '10小时', | ||
| 274 | + value: 36000000 | ||
| 275 | + }, | ||
| 276 | + { | ||
| 277 | + label: '12小时', | ||
| 278 | + value: 43200000 | ||
| 279 | + }, | ||
| 280 | + { | ||
| 281 | + label: '1天', | ||
| 282 | + value: 86400000 | ||
| 283 | + } | ||
| 284 | + ] | ||
| 285 | + ]; | ||
| 286 | + } else if (value >= 2592000000) { | ||
| 287 | + // 大于30天 | ||
| 288 | + return [ | ||
| 289 | + [{ | ||
| 290 | + label: '2小时', | ||
| 291 | + value: 7200000 | ||
| 292 | + }, | ||
| 293 | + { | ||
| 294 | + label: '5小时', | ||
| 295 | + value: 18000000 | ||
| 296 | + }, | ||
| 297 | + { | ||
| 298 | + label: '10小时', | ||
| 299 | + value: 36000000 | ||
| 300 | + }, | ||
| 301 | + { | ||
| 302 | + label: '12小时', | ||
| 303 | + value: 43200000 | ||
| 304 | + }, | ||
| 305 | + { | ||
| 306 | + label: '1天', | ||
| 307 | + value: 86400000 | ||
| 308 | + } | ||
| 309 | + ] | ||
| 310 | + ]; | ||
| 311 | + } | ||
| 312 | + }, | ||
| 313 | + openCalendar() { | ||
| 314 | + this.showCalendar = true; | ||
| 315 | + }, | ||
| 316 | + openTimeGap() { | ||
| 317 | + this.showTimeGap = true; | ||
| 318 | + }, | ||
| 319 | + openType() { | ||
| 320 | + this.showSelectType = true; | ||
| 321 | + }, | ||
| 322 | + openAvg() { | ||
| 323 | + this.showSelectAvg = true | ||
| 324 | + }, | ||
| 325 | + calendarConfirm(date) { | ||
| 326 | + this.showCalendar = false; | ||
| 327 | + this.timeData.selectTime = `${date[0]} 至 ${date[date.length - 1]}`; | ||
| 328 | + // 选择的日期时间差(时间戳) | ||
| 329 | + const timeDiff = formatToDate(date[date.length - 1], 'x') - formatToDate(date[0], 'x'); | ||
| 330 | + const genColumns = this.generateColumns(timeDiff); | ||
| 331 | + this.columns = genColumns; | ||
| 332 | + this.timeData.getTimeGap = ''; | ||
| 333 | + this.timeData.getType = ''; | ||
| 334 | + this.startTs = formatToDate(date[0], 'x'); | ||
| 335 | + // 最后时间的最后一秒 | ||
| 336 | + this.endTs = formatToDate(`${date[date.length - 1]} 23:59:59`, 'x'); | ||
| 337 | + }, | ||
| 338 | + calendarClose() { | ||
| 339 | + this.showCalendar = false; | ||
| 340 | + }, | ||
| 341 | + confirmTimeGap(time) { | ||
| 342 | + this.showTimeGap = false; | ||
| 343 | + this.timeData.getTimeGap = time.value[0].label; | ||
| 344 | + this.timeData.getType = ''; | ||
| 345 | + }, | ||
| 346 | + | ||
| 347 | + cancelTimeGap() { | ||
| 348 | + this.showTimeGap = false; | ||
| 349 | + }, | ||
| 350 | + confirmAvgGap(e) { | ||
| 351 | + this.timeData.agg = e.value[0].value | ||
| 352 | + this.aggText = e.value[0].label | ||
| 353 | + if (e.value[0].value === 'NONE') { | ||
| 354 | + this.limitFlag = true | ||
| 355 | + this.timeData.limit = 7 | ||
| 356 | + } else { | ||
| 357 | + this.timeData.limit = null | ||
| 358 | + this.limitFlag = false | ||
| 359 | + } | ||
| 360 | + this.showSelectAvg = false | ||
| 361 | + }, | ||
| 362 | + async confirmTypeGap(time) { | ||
| 363 | + this.showSelectType = false; | ||
| 364 | + this.timeData.getType = time.value[0]; | ||
| 365 | + const interval = this.columns[0].find(item => item.label === this.timeData.getTimeGap); | ||
| 366 | + const data = await getHistoryData({ | ||
| 367 | + startTs: this.startTs, | ||
| 368 | + endTs: this.endTs, | ||
| 369 | + keys: this.timeData.getType, | ||
| 370 | + interval: this.limitFlag ? null : interval.value, | ||
| 371 | + entityId: this.entityId, | ||
| 372 | + limit: this.timeData.limit, | ||
| 373 | + agg: this.timeData.agg | ||
| 374 | + }); | ||
| 375 | + this.$emit('update', data[this.timeData.getType]); | ||
| 376 | + }, | ||
| 377 | + cancelTypeGap() { | ||
| 378 | + this.showSelectType = false; | ||
| 379 | + } | ||
| 380 | + } | ||
| 381 | + }; | ||
| 382 | +</script> | ||
| 383 | + | ||
| 384 | +<style lang="scss" scoped> | ||
| 385 | + .charts-box { | ||
| 386 | + width: 100%; | ||
| 387 | + height: 550rpx; | ||
| 388 | + } | ||
| 389 | + | ||
| 390 | + .historyData { | ||
| 391 | + margin: 30rpx; | ||
| 392 | + | ||
| 393 | + .historyData-top { | ||
| 394 | + padding: 30rpx; | ||
| 395 | + background-color: #fff; | ||
| 396 | + // height: 870rpx; | ||
| 397 | + border-radius: 20rpx; | ||
| 398 | + | ||
| 399 | + .icon { | ||
| 400 | + width: 28rpx; | ||
| 401 | + height: 28rpx; | ||
| 402 | + margin-right: 15rpx; | ||
| 403 | + } | ||
| 404 | + } | ||
| 405 | + | ||
| 406 | + .historyData-bottom { | ||
| 407 | + margin-top: 30rpx; | ||
| 408 | + background-color: #fff; | ||
| 409 | + border-radius: 20rpx; | ||
| 410 | + | ||
| 411 | + .table { | ||
| 412 | + border: 0px solid darkgray; | ||
| 413 | + | ||
| 414 | + .tr { | ||
| 415 | + display: flex; | ||
| 416 | + width: 100%; | ||
| 417 | + justify-content: center; | ||
| 418 | + height: 3rem; | ||
| 419 | + align-items: center; | ||
| 420 | + | ||
| 421 | + .th { | ||
| 422 | + display: flex; | ||
| 423 | + justify-content: center; | ||
| 424 | + align-items: center; | ||
| 425 | + width: 50%; | ||
| 426 | + color: #333; | ||
| 427 | + font-weight: 500; | ||
| 428 | + } | ||
| 429 | + | ||
| 430 | + .td { | ||
| 431 | + color: #999; | ||
| 432 | + width: 50%; | ||
| 433 | + display: flex; | ||
| 434 | + justify-content: center; | ||
| 435 | + text-align: center; | ||
| 436 | + } | ||
| 437 | + } | ||
| 438 | + } | ||
| 439 | + } | ||
| 440 | + } | ||
| 441 | + | ||
| 442 | + .odd { | ||
| 443 | + background-color: #f9fcff; | ||
| 444 | + } | ||
| 445 | </style> | 445 | </style> |
| 1 | +<template> | ||
| 2 | + <view class="mp-u-modal"> | ||
| 3 | + <u-modal :mask-close-able="true" :show="showModal" closeOnClickOverlay :showConfirmButton="false" | ||
| 4 | + @close="$emit('hideModal')" @touchmove.stop.prevent="disabledScroll" z-index="99999"> | ||
| 5 | + <view class="w-100 modal-content"> | ||
| 6 | + <view class="header-title">命令下发</view> | ||
| 7 | + <view class="u-flex"> | ||
| 8 | + <text class="type-text">下发类型:</text> | ||
| 9 | + <u-radio-group v-model="commandType" placement="row"> | ||
| 10 | + <u-radio activeColor="#3388FF" label="单向" name="OneWay"></u-radio> | ||
| 11 | + <view style="margin: 0 20rpx;"></view> | ||
| 12 | + <u-radio activeColor="#3388FF" label="双向" name="TwoWay"></u-radio> | ||
| 13 | + </u-radio-group> | ||
| 14 | + </view> | ||
| 15 | + <view class="content-body"> | ||
| 16 | + <div class="u-flex u-row-between"> | ||
| 17 | + <u--textarea :placeholder="`请输入下发内容${isShowTCP?'(字符串格式)':'(json格式)'}`" | ||
| 18 | + v-model="inputCommandVal" /> | ||
| 19 | + <u-icon v-if="!isShowTCP" @click="handleCopy(copyTextValue)" name="question-circle" | ||
| 20 | + color="#2979ff" size="28" class="ml-10"> | ||
| 21 | + </u-icon> | ||
| 22 | + </div> | ||
| 23 | + </view> | ||
| 24 | + <view class="button-group"> | ||
| 25 | + <view> | ||
| 26 | + <u-button :customStyle="{ color: '#333' }" color="#e3e3e5" shape="circle" text="取消" | ||
| 27 | + @click="cancelCommand"></u-button> | ||
| 28 | + </view> | ||
| 29 | + <view> | ||
| 30 | + <u-button color="#3388ff" shape="circle" text="确认" @click="confirmCommand"></u-button> | ||
| 31 | + </view> | ||
| 32 | + </view> | ||
| 33 | + </view> | ||
| 34 | + </u-modal> | ||
| 35 | + </view> | ||
| 36 | +</template> | ||
| 37 | + | ||
| 38 | +<script> | ||
| 39 | + import { | ||
| 40 | + useShowModal | ||
| 41 | + } from '@/plugins/utils.js' | ||
| 42 | + | ||
| 43 | + export default { | ||
| 44 | + props: { | ||
| 45 | + showModal: Boolean, | ||
| 46 | + isShowTCP: Boolean | ||
| 47 | + }, | ||
| 48 | + data() { | ||
| 49 | + return { | ||
| 50 | + current: 0, | ||
| 51 | + commandType: 'OneWay', | ||
| 52 | + inputCommandVal: '', | ||
| 53 | + copyTextValue: { | ||
| 54 | + "method": "methodThingskit", | ||
| 55 | + "params": { | ||
| 56 | + "pin": 7, | ||
| 57 | + "value": 1 | ||
| 58 | + } | ||
| 59 | + } | ||
| 60 | + } | ||
| 61 | + }, | ||
| 62 | + methods: { | ||
| 63 | + cancelCommand() { | ||
| 64 | + this.$emit('cancelCommand') | ||
| 65 | + }, | ||
| 66 | + confirmCommand() { | ||
| 67 | + this.$emit('confirmCommand', this.commandType, this.inputCommandVal) | ||
| 68 | + }, | ||
| 69 | + handleCopy(value) { | ||
| 70 | + useShowModal(JSON.stringify(value), '命令下发', '复制内容').then(res => { | ||
| 71 | + uni.setClipboardData({ | ||
| 72 | + data: JSON.stringify(value), | ||
| 73 | + success: () => { | ||
| 74 | + uni.showToast({ | ||
| 75 | + title: '复制成功' | ||
| 76 | + }) | ||
| 77 | + } | ||
| 78 | + }); | ||
| 79 | + }) | ||
| 80 | + }, | ||
| 81 | + reset() { | ||
| 82 | + this.commandType = 'OneWay' | ||
| 83 | + this.inputCommandVal = '' | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | +</script> | ||
| 88 | + | ||
| 89 | +<style lang="scss" scoped> | ||
| 90 | + .modal-content { | ||
| 91 | + width: 720rpx; | ||
| 92 | + padding: 0 30rpx; | ||
| 93 | + background-color: white; | ||
| 94 | + | ||
| 95 | + .header-title { | ||
| 96 | + text-align: center; | ||
| 97 | + font-weight: 700; | ||
| 98 | + margin-bottom: 40rpx; | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + .type-text { | ||
| 102 | + color: #333; | ||
| 103 | + font-size: 14px; | ||
| 104 | + font-weight: 700; | ||
| 105 | + margin-right: 30rpx; | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + .content-body { | ||
| 109 | + margin-top: 28rpx; | ||
| 110 | + width: 100%; | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + .button-group { | ||
| 114 | + display: flex; | ||
| 115 | + margin-top: 40rpx; | ||
| 116 | + justify-content: space-between; | ||
| 117 | + | ||
| 118 | + view { | ||
| 119 | + width: 300rpx; | ||
| 120 | + } | ||
| 121 | + } | ||
| 122 | + } | ||
| 123 | +</style> |
| 1 | +<template> | ||
| 2 | + <view class="realtime-page"> | ||
| 3 | + <view class="item" v-for="(item, index) in recordList" :key="index"> | ||
| 4 | + <view class="item-top"> | ||
| 5 | + <view>{{ item.key }}</view> | ||
| 6 | + <view class="item-value">{{ item.value }}</view> | ||
| 7 | + </view> | ||
| 8 | + <view class="item-time">{{ item.time }}</view> | ||
| 9 | + </view> | ||
| 10 | + <mescroll-empty v-if="!recordList.length" /> | ||
| 11 | + </view> | ||
| 12 | +</template> | ||
| 13 | + | ||
| 14 | +<script> | ||
| 15 | + export default { | ||
| 16 | + props: { | ||
| 17 | + recordList: { | ||
| 18 | + type: Array, | ||
| 19 | + default: () => [] | ||
| 20 | + } | ||
| 21 | + } | ||
| 22 | + }; | ||
| 23 | +</script> | ||
| 24 | + | ||
| 25 | +<style lang="scss" scoped> | ||
| 26 | + @import "../static/realtime-data.scss"; | ||
| 27 | +</style> |
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/changelog.md
renamed from
uni_modules/qiun-data-charts/changelog.md
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue
renamed from
uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/components/qiun-error/qiun-error.vue
renamed from
uni_modules/qiun-data-charts/components/qiun-error/qiun-error.vue
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/components/qiun-loading/loading1.vue
renamed from
uni_modules/qiun-data-charts/components/qiun-loading/loading1.vue
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/components/qiun-loading/loading2.vue
renamed from
uni_modules/qiun-data-charts/components/qiun-loading/loading2.vue
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/components/qiun-loading/loading3.vue
renamed from
uni_modules/qiun-data-charts/components/qiun-loading/loading3.vue
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/components/qiun-loading/loading4.vue
renamed from
uni_modules/qiun-data-charts/components/qiun-loading/loading4.vue
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/components/qiun-loading/loading5.vue
renamed from
uni_modules/qiun-data-charts/components/qiun-loading/loading5.vue
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/components/qiun-loading/qiun-loading.vue
renamed from
uni_modules/qiun-data-charts/components/qiun-loading/qiun-loading.vue
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/js_sdk/u-charts/config-echarts.js
renamed from
uni_modules/qiun-data-charts/js_sdk/u-charts/config-echarts.js
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/js_sdk/u-charts/config-ucharts.js
renamed from
uni_modules/qiun-data-charts/js_sdk/u-charts/config-ucharts.js
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/js_sdk/u-charts/readme.md
renamed from
uni_modules/qiun-data-charts/js_sdk/u-charts/readme.md
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.js
renamed from
uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.js
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/license.md
renamed from
uni_modules/qiun-data-charts/license.md
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/package.json
renamed from
uni_modules/qiun-data-charts/package.json
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/readme.md
renamed from
uni_modules/qiun-data-charts/readme.md
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/static/app-plus/echarts.min.js
renamed from
uni_modules/qiun-data-charts/static/app-plus/echarts.min.js
device-subpackage/device-detail/components/uni_modules/qiun-data-charts/static/h5/echarts.min.js
renamed from
uni_modules/qiun-data-charts/static/h5/echarts.min.js
| 1 | +const list = [{ | ||
| 2 | + name: "基础信息", | ||
| 3 | + }, | ||
| 4 | + { | ||
| 5 | + name: "实时数据", | ||
| 6 | + }, | ||
| 7 | + { | ||
| 8 | + name: "历史数据", | ||
| 9 | + }, | ||
| 10 | + { | ||
| 11 | + name: "告警记录", | ||
| 12 | + }, | ||
| 13 | +] | ||
| 14 | + | ||
| 15 | +const issueStatus = [{ | ||
| 16 | + checked: true, | ||
| 17 | + name: '全部', | ||
| 18 | + type: '' | ||
| 19 | + }, | ||
| 20 | + { | ||
| 21 | + checked: false, | ||
| 22 | + name: '队列中', | ||
| 23 | + type: 'QUEUED' | ||
| 24 | + }, | ||
| 25 | + { | ||
| 26 | + checked: false, | ||
| 27 | + name: '已发送', | ||
| 28 | + type: 'SENT' | ||
| 29 | + }, | ||
| 30 | + { | ||
| 31 | + checked: false, | ||
| 32 | + name: '发送成功', | ||
| 33 | + type: 'DELIVERED' | ||
| 34 | + }, | ||
| 35 | + { | ||
| 36 | + checked: false, | ||
| 37 | + name: '响应成功', | ||
| 38 | + type: 'SUCCESSFUL' | ||
| 39 | + }, | ||
| 40 | + { | ||
| 41 | + checked: false, | ||
| 42 | + name: '超时', | ||
| 43 | + type: 'TIMEOUT' | ||
| 44 | + }, | ||
| 45 | + { | ||
| 46 | + checked: false, | ||
| 47 | + name: '已过期', | ||
| 48 | + type: 'EXPIRED' | ||
| 49 | + }, | ||
| 50 | + { | ||
| 51 | + checked: false, | ||
| 52 | + name: '响应失败', | ||
| 53 | + type: 'FAILED' | ||
| 54 | + }, | ||
| 55 | + { | ||
| 56 | + checked: false, | ||
| 57 | + name: '已删除', | ||
| 58 | + type: 'DELETED' | ||
| 59 | + } | ||
| 60 | +] | ||
| 61 | + | ||
| 62 | +const commandTypeList = [{ | ||
| 63 | + value: 'OneWay', | ||
| 64 | + name: '单向', | ||
| 65 | + }, | ||
| 66 | + { | ||
| 67 | + value: 'TwoWay', | ||
| 68 | + name: '双向' | ||
| 69 | + }, | ||
| 70 | +] | ||
| 71 | + | ||
| 72 | + | ||
| 73 | +export { | ||
| 74 | + list, | ||
| 75 | + issueStatus, | ||
| 76 | + commandTypeList | ||
| 77 | +} |
device-subpackage/device-detail/device-detail.vue
renamed from
deviceSubPage/deviceDetailPage/deviceDetail.vue
| 1 | -<template> | ||
| 2 | - <view class="device-detail-page"> | ||
| 3 | - <!-- 公共组件-每个页面必须引入 --> | ||
| 4 | - <public-module></public-module> | ||
| 5 | - <u-sticky bgColor="#fff"> | ||
| 6 | - <u-tabs :list="list" :current="currentTab" @click="handleTabClick" :activeStyle="{ | ||
| 7 | - fontWeight: 'bold', | ||
| 8 | - color: '#333', | ||
| 9 | - }" :inactiveStyle="{ | ||
| 10 | - color: '#999', | ||
| 11 | - }" :scrollable="isScrollable" /> | ||
| 12 | - </u-sticky> | ||
| 13 | - <view style="margin-top: 30rpx"> | ||
| 14 | - <basicInfo v-show="currentTab == 0" :deviceDetail="deviceDetail" /> | ||
| 15 | - <realTimeData v-show="currentTab === 1" :recordList="recordList" /> | ||
| 16 | - <historyData v-if="currentTab === 2" :keys="keys" :yesterday="yesterday" :today="today" :timeDiff="timeDiff" | ||
| 17 | - :historyData="historyData" :entityId="entityId" :start="startTs" :end="endTs" @update="handleUpdate" /> | ||
| 18 | - <alarmHistory v-show="currentTab === 3" :deviceId="deviceId" /> | ||
| 19 | - <commondRecord v-if="currentTab === 4" :tbDeviceId="entityId" /> | ||
| 20 | - </view> | ||
| 21 | - </view> | ||
| 22 | -</template> | ||
| 23 | - | ||
| 24 | -<script> | ||
| 25 | - import fTabbar from "@/components/module/f-tabbar/f-tabbar"; | ||
| 26 | - import basicInfo from "./tabDetail/basicInfo.vue"; | ||
| 27 | - import realTimeData from "./tabDetail/realtimeData.vue"; | ||
| 28 | - import alarmHistory from "./tabDetail/alarmHistory.vue"; | ||
| 29 | - import historyData from "./tabDetail/historyData.vue"; | ||
| 30 | - import commondRecord from "./tabDetail/CommandRecord.vue"; | ||
| 31 | - import { | ||
| 32 | - getDeviceKeys, | ||
| 33 | - getHistoryData | ||
| 34 | - } from "./api/index.js"; | ||
| 35 | - import { | ||
| 36 | - formatToDate | ||
| 37 | - } from "@/plugins/utils.js"; | ||
| 38 | - import MescrollCompMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mixins/mescroll-comp.js"; | ||
| 39 | - import moment from "moment"; | ||
| 40 | - import base from "@/config/baseUrl.js"; | ||
| 41 | - | ||
| 42 | - export default { | ||
| 43 | - mixins: [MescrollCompMixin], | ||
| 44 | - components: { | ||
| 45 | - fTabbar, | ||
| 46 | - basicInfo, | ||
| 47 | - realTimeData, | ||
| 48 | - alarmHistory, | ||
| 49 | - historyData, | ||
| 50 | - commondRecord, | ||
| 51 | - }, | ||
| 52 | - data() { | ||
| 53 | - return { | ||
| 54 | - list: [{ | ||
| 55 | - name: "基础信息", | ||
| 56 | - }, | ||
| 57 | - { | ||
| 58 | - name: "实时数据", | ||
| 59 | - }, | ||
| 60 | - { | ||
| 61 | - name: "历史数据", | ||
| 62 | - }, | ||
| 63 | - { | ||
| 64 | - name: "告警记录", | ||
| 65 | - }, | ||
| 66 | - ], | ||
| 67 | - currentTab: 0, | ||
| 68 | - deviceId: "", | ||
| 69 | - deviceDetail: {}, | ||
| 70 | - keys: [], | ||
| 71 | - yesterday: "", | ||
| 72 | - today: "", | ||
| 73 | - timeDiff: "", | ||
| 74 | - historyData: [], | ||
| 75 | - entityId: "", | ||
| 76 | - startTs: "", | ||
| 77 | - endTs: "", | ||
| 78 | - recordList: [], | ||
| 79 | - isScrollable: false, | ||
| 80 | - attrList: [] | ||
| 81 | - }; | ||
| 82 | - }, | ||
| 83 | - onUnload() { | ||
| 84 | - // 页面关闭时,销毁webSocket连接,否则第二次会存在连接不到的情况 | ||
| 85 | - uni.closeSocket(); | ||
| 86 | - }, | ||
| 87 | - async onLoad(options) { | ||
| 88 | - const { | ||
| 89 | - id, | ||
| 90 | - alarmStatus, | ||
| 91 | - lastOnlineTime, | ||
| 92 | - tbDeviceId, | ||
| 93 | - deviceProfileId | ||
| 94 | - } = | ||
| 95 | - options; | ||
| 96 | - this.deviceId = id; | ||
| 97 | - const res = await uni.$u.http.get(`/yt/device/${id}`); | ||
| 98 | - this.deviceDetail = { | ||
| 99 | - ...res, | ||
| 100 | - alarmStatus, | ||
| 101 | - lastOnlineTime, | ||
| 102 | - }; | ||
| 103 | - | ||
| 104 | - // 设备类型不是网关子设备的添加一个命令记录的选项卡 | ||
| 105 | - if (this.deviceDetail.deviceType !== "SENSOR") { | ||
| 106 | - this.list.push({ | ||
| 107 | - name: "命令记录", | ||
| 108 | - }); | ||
| 109 | - } | ||
| 110 | - this.isScrollable = this.list.length > 4; | ||
| 111 | - if (res.deviceProfileId) { | ||
| 112 | - const getAttrList = await uni.$u.http.get( | ||
| 113 | - `/yt/device/attributes/${res.deviceProfileId}` | ||
| 114 | - ); | ||
| 115 | - if (Array.isArray(getAttrList)) { | ||
| 116 | - this.attrList = getAttrList.map(m => { | ||
| 117 | - return m.identifier | ||
| 118 | - }) | ||
| 119 | - } | ||
| 120 | - } | ||
| 121 | - // 连接webSockte | ||
| 122 | - const socketTask = uni.connectSocket({ | ||
| 123 | - url: `${base.socketPrefix}://${base.baseWebSocketUrl}/api/ws/plugins/telemetry?token=` + | ||
| 124 | - uni.getStorageSync("userInfo").isToken, //仅为示例,并非真实接口地址。 | ||
| 125 | - complete: () => {}, | ||
| 126 | - }); | ||
| 127 | - uni.onSocketOpen((header) => { | ||
| 128 | - socketTask.send({ | ||
| 129 | - data: JSON.stringify({ | ||
| 130 | - attrSubCmds: [], | ||
| 131 | - tsSubCmds: [{ | ||
| 132 | - entityType: "DEVICE", | ||
| 133 | - entityId: tbDeviceId, | ||
| 134 | - scope: "LATEST_TELEMETRY", | ||
| 135 | - cmdId: 1, | ||
| 136 | - keys: this.attrList.join(','), | ||
| 137 | - }, ], | ||
| 138 | - historyCmds: [], | ||
| 139 | - entityDataCmds: [], | ||
| 140 | - entityDataUnsubscribeCmds: [], | ||
| 141 | - alarmDataCmds: [], | ||
| 142 | - alarmDataUnsubscribeCmds: [], | ||
| 143 | - entityCountCmds: [], | ||
| 144 | - entityCountUnsubscribeCmds: [], | ||
| 145 | - }), | ||
| 146 | - success() {}, | ||
| 147 | - }); | ||
| 148 | - }); | ||
| 149 | - socketTask.onMessage((msg) => { | ||
| 150 | - const { | ||
| 151 | - data | ||
| 152 | - } = JSON.parse(msg.data); | ||
| 153 | - const newArray = []; | ||
| 154 | - for (const key in data) { | ||
| 155 | - const [time, value] = data[key].flat(1); | ||
| 156 | - let obj = { | ||
| 157 | - key, | ||
| 158 | - time, | ||
| 159 | - value, | ||
| 160 | - }; | ||
| 161 | - if (this.recordList.length === 0) { | ||
| 162 | - this.recordList.unshift(obj); | ||
| 163 | - } else { | ||
| 164 | - newArray.push(obj); | ||
| 165 | - } | ||
| 166 | - } | ||
| 167 | - newArray.forEach((item) => { | ||
| 168 | - let flag = false; | ||
| 169 | - this.recordList.forEach((item1) => { | ||
| 170 | - if (item1.key === item.key) { | ||
| 171 | - item1.value = item.value; | ||
| 172 | - item1.time = item.time; | ||
| 173 | - flag = true; | ||
| 174 | - } | ||
| 175 | - }); | ||
| 176 | - if (!flag) { | ||
| 177 | - this.recordList.unshift(item); | ||
| 178 | - } | ||
| 179 | - }); | ||
| 180 | - this.recordList = this.recordList.map((item) => { | ||
| 181 | - return { | ||
| 182 | - ...item, | ||
| 183 | - time: formatToDate(item.time, "YYYY-MM-DD HH:mm:ss"), | ||
| 184 | - }; | ||
| 185 | - }); | ||
| 186 | - }); | ||
| 187 | - | ||
| 188 | - const keys = await getDeviceKeys(tbDeviceId); | ||
| 189 | - this.keys = [keys]; | ||
| 190 | - // 昨天 | ||
| 191 | - this.yesterday = moment().subtract(1, "days").format("YYYY-MM-DD"); | ||
| 192 | - // 今天 | ||
| 193 | - this.today = moment().format("YYYY-MM-DD"); | ||
| 194 | - // 开始时间 | ||
| 195 | - this.startTs = moment().subtract(1, "days").format("x"); | ||
| 196 | - // 结束时间 | ||
| 197 | - this.endTs = moment().format("x"); | ||
| 198 | - this.entityId = tbDeviceId; | ||
| 199 | - | ||
| 200 | - const data = await getHistoryData({ | ||
| 201 | - entityId: tbDeviceId, | ||
| 202 | - startTs: this.startTs, | ||
| 203 | - endTs: this.endTs, | ||
| 204 | - keys: keys[0], | ||
| 205 | - // interval: 1800000, | ||
| 206 | - limit: 7, | ||
| 207 | - agg: 'NONE' | ||
| 208 | - }); | ||
| 209 | - this.timeDiff = "30分钟"; | ||
| 210 | - if (!Object.keys(data).length) return; | ||
| 211 | - | ||
| 212 | - this.historyData = data[keys[0]].map((item) => { | ||
| 213 | - return { | ||
| 214 | - value: item.value, | ||
| 215 | - ts: formatToDate(item.ts, "YYYY-MM-DD HH:mm:ss"), | ||
| 216 | - }; | ||
| 217 | - }); | ||
| 218 | - }, | ||
| 219 | - methods: { | ||
| 220 | - handleTabClick({ | ||
| 221 | - index | ||
| 222 | - }) { | ||
| 223 | - this.currentTab = index; | ||
| 224 | - }, | ||
| 225 | - handleUpdate(data, e) { | ||
| 226 | - if (!Array.isArray(data)) { | ||
| 227 | - this.historyData = []; | ||
| 228 | - return; | ||
| 229 | - } | ||
| 230 | - this.historyData = data.map((item) => { | ||
| 231 | - return { | ||
| 232 | - value: item.value, | ||
| 233 | - ts: formatToDate(item.ts, "YYYY-MM-DD HH:mm:ss"), | ||
| 234 | - }; | ||
| 235 | - }); | ||
| 236 | - }, | ||
| 237 | - }, | ||
| 238 | - }; | ||
| 239 | -</script> | ||
| 240 | - | ||
| 241 | -<style lang="scss" scoped> | ||
| 242 | - .device-detail-page { | ||
| 243 | - height: 100vh; | ||
| 244 | - background-color: #f8f9fa; | ||
| 245 | - } | ||
| 246 | -</style> | 1 | +<template> |
| 2 | + <view class="device-detail-page"> | ||
| 3 | + <!-- 公共组件-每个页面必须引入 --> | ||
| 4 | + <public-module></public-module> | ||
| 5 | + <u-sticky :bgColor="bgColor"> | ||
| 6 | + <u-tabs :list="list" :current="currentTab" @click="handleTabClick" :activeStyle="activeColor" | ||
| 7 | + :inactiveStyle="inActiveColor" :scrollable="isScrollable" /> | ||
| 8 | + </u-sticky> | ||
| 9 | + <view class="mt-3"> | ||
| 10 | + <basic-info v-show="currentTab == 0" :deviceDetail="deviceDetail" /> | ||
| 11 | + <realtime-data v-show="currentTab === 1" :recordList="recordList" /> | ||
| 12 | + <history-data v-if="currentTab === 2" :keys="keys" :yesterday="yesterday" :today="today" | ||
| 13 | + :timeDiff="timeDiff" :historyData="historyData" :entityId="entityId" :start="startTs" :end="endTs" | ||
| 14 | + @update="handleUpdate" /> | ||
| 15 | + <alarm-history v-show="currentTab === 3" :deviceId="deviceId" /> | ||
| 16 | + <commond-record v-if="currentTab === 4" :tbDeviceId="entityId" /> | ||
| 17 | + </view> | ||
| 18 | + </view> | ||
| 19 | +</template> | ||
| 20 | + | ||
| 21 | +<script> | ||
| 22 | + import fTabbar from "@/components/module/f-tabbar/f-tabbar"; | ||
| 23 | + import basicInfo from "./components/basic-info.vue"; | ||
| 24 | + import realtimeData from "./components/realtime-data.vue"; | ||
| 25 | + import alarmHistory from "./components/alarm-history.vue"; | ||
| 26 | + import historyData from "./components/history-data.vue"; | ||
| 27 | + import commondRecord from "./components/command-record.vue"; | ||
| 28 | + import { getDeviceKeys,getHistoryData } from "./api/index.js"; | ||
| 29 | + import {formatToDate} from "@/plugins/utils.js"; | ||
| 30 | + import MescrollCompMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mixins/mescroll-comp.js"; | ||
| 31 | + import moment from "moment"; | ||
| 32 | + import base from "@/config/baseUrl.js"; | ||
| 33 | + import { list } from './config/data.js' | ||
| 34 | + import api from '@/api' | ||
| 35 | + | ||
| 36 | + export default { | ||
| 37 | + mixins: [MescrollCompMixin], | ||
| 38 | + components: { | ||
| 39 | + fTabbar, | ||
| 40 | + basicInfo, | ||
| 41 | + realtimeData, | ||
| 42 | + alarmHistory, | ||
| 43 | + historyData, | ||
| 44 | + commondRecord, | ||
| 45 | + }, | ||
| 46 | + data() { | ||
| 47 | + return { | ||
| 48 | + bgColor: '#fff', | ||
| 49 | + activeColor: { | ||
| 50 | + fontWeight: 'bold', | ||
| 51 | + color: '#333', | ||
| 52 | + }, | ||
| 53 | + inActiveColor: { | ||
| 54 | + color: '#999', | ||
| 55 | + }, | ||
| 56 | + list, | ||
| 57 | + currentTab: 0, | ||
| 58 | + deviceId: "", | ||
| 59 | + deviceDetail: {}, | ||
| 60 | + keys: [], | ||
| 61 | + yesterday: "", | ||
| 62 | + today: "", | ||
| 63 | + timeDiff: "", | ||
| 64 | + historyData: [], | ||
| 65 | + entityId: "", | ||
| 66 | + startTs: "", | ||
| 67 | + endTs: "", | ||
| 68 | + recordList: [], //实时数据 | ||
| 69 | + isScrollable: false, | ||
| 70 | + attrList: [] | ||
| 71 | + }; | ||
| 72 | + }, | ||
| 73 | + onUnload() { | ||
| 74 | + // 页面关闭时,销毁webSocket连接,否则第二次会存在连接不到的情况 | ||
| 75 | + uni.closeSocket(); | ||
| 76 | + }, | ||
| 77 | + async onLoad(options) { | ||
| 78 | + const {id,alarmStatus,lastOnlineTime,tbDeviceId,deviceProfileId} = options; | ||
| 79 | + this.deviceId = id; | ||
| 80 | + const res = await api.deviceApi.getDeviceDetail(this.deviceId) | ||
| 81 | + if(!res) return | ||
| 82 | + this.deviceDetail = { | ||
| 83 | + ...res, | ||
| 84 | + alarmStatus, | ||
| 85 | + lastOnlineTime, | ||
| 86 | + }; | ||
| 87 | + // 设备类型不是网关子设备的添加一个命令记录的选项卡 | ||
| 88 | + if (this.deviceDetail.deviceType !== "SENSOR") { | ||
| 89 | + this.list.push({ | ||
| 90 | + name: "命令记录", | ||
| 91 | + }); | ||
| 92 | + const res = new Map() | ||
| 93 | + this.list = this.list.filter((item) => !res.has(item.name) && res.set(item.name, 1)) | ||
| 94 | + } else { | ||
| 95 | + this.list = this.list.filter(item => item.name !=='命令记录') | ||
| 96 | + } | ||
| 97 | + this.isScrollable = this.list.length > 4; | ||
| 98 | + if (res.deviceProfileId) { | ||
| 99 | + const getAttrList = await api.deviceApi.getAttribute(res.deviceProfileId) | ||
| 100 | + if (Array.isArray(getAttrList)) { | ||
| 101 | + this.attrList = getAttrList.map(m => { | ||
| 102 | + return m.identifier | ||
| 103 | + }) | ||
| 104 | + } | ||
| 105 | + } | ||
| 106 | + // 连接webSockte | ||
| 107 | + const socketTask = uni.connectSocket({ | ||
| 108 | + url: `${base.socketPrefix}://${base.baseWebSocketUrl}/api/ws/plugins/telemetry?token=` + uni.getStorageSync("userInfo").isToken, //仅为示例,并非真实接口地址。 | ||
| 109 | + complete: () => {}, | ||
| 110 | + }); | ||
| 111 | + uni.onSocketOpen((header) => { | ||
| 112 | + socketTask.send({ | ||
| 113 | + data: JSON.stringify({ | ||
| 114 | + attrSubCmds: [], | ||
| 115 | + tsSubCmds: [{ | ||
| 116 | + entityType: "DEVICE", | ||
| 117 | + entityId: tbDeviceId, | ||
| 118 | + scope: "LATEST_TELEMETRY", | ||
| 119 | + cmdId: 1, | ||
| 120 | + keys: this.attrList.join(','), | ||
| 121 | + }, ], | ||
| 122 | + historyCmds: [], | ||
| 123 | + entityDataCmds: [], | ||
| 124 | + entityDataUnsubscribeCmds: [], | ||
| 125 | + alarmDataCmds: [], | ||
| 126 | + alarmDataUnsubscribeCmds: [], | ||
| 127 | + entityCountCmds: [], | ||
| 128 | + entityCountUnsubscribeCmds: [], | ||
| 129 | + }), | ||
| 130 | + success() {}, | ||
| 131 | + }); | ||
| 132 | + }); | ||
| 133 | + socketTask.onMessage((msg) => { | ||
| 134 | + const { data } = JSON.parse(msg.data); | ||
| 135 | + const newArray = []; | ||
| 136 | + for (const key in data) { | ||
| 137 | + const [time, value] = data[key].flat(1); | ||
| 138 | + let obj = { key,time,value, }; | ||
| 139 | + if (this.recordList.length === 0) { | ||
| 140 | + this.recordList.unshift(obj); | ||
| 141 | + } else { | ||
| 142 | + newArray.push(obj); | ||
| 143 | + } | ||
| 144 | + } | ||
| 145 | + newArray.forEach((item) => { | ||
| 146 | + let flag = false; | ||
| 147 | + this.recordList.forEach((item1) => { | ||
| 148 | + if (item1.key === item.key) { | ||
| 149 | + item1.value = item.value; | ||
| 150 | + item1.time = item.time; | ||
| 151 | + flag = true; | ||
| 152 | + } | ||
| 153 | + }); | ||
| 154 | + if (!flag) { | ||
| 155 | + this.recordList.unshift(item); | ||
| 156 | + } | ||
| 157 | + }); | ||
| 158 | + this.recordList = this.recordList.map((item) => { | ||
| 159 | + return { | ||
| 160 | + ...item, | ||
| 161 | + time: formatToDate(item.time, "YYYY-MM-DD HH:mm:ss"), | ||
| 162 | + }; | ||
| 163 | + }); | ||
| 164 | + }); | ||
| 165 | + const keys = await getDeviceKeys(tbDeviceId); | ||
| 166 | + this.keys = [keys]; | ||
| 167 | + // 昨天 | ||
| 168 | + this.yesterday = moment().subtract(1, "days").format("YYYY-MM-DD"); | ||
| 169 | + // 今天 | ||
| 170 | + this.today = moment().format("YYYY-MM-DD"); | ||
| 171 | + // 开始时间 | ||
| 172 | + this.startTs = moment().subtract(1, "days").format("x"); | ||
| 173 | + // 结束时间 | ||
| 174 | + this.endTs = moment().format("x"); | ||
| 175 | + this.entityId = tbDeviceId; | ||
| 176 | + const data = await getHistoryData({ | ||
| 177 | + entityId: tbDeviceId, | ||
| 178 | + startTs: this.startTs, | ||
| 179 | + endTs: this.endTs, | ||
| 180 | + keys: keys[0], | ||
| 181 | + // interval: 1800000, | ||
| 182 | + limit: 7, | ||
| 183 | + agg: 'NONE' | ||
| 184 | + }); | ||
| 185 | + this.timeDiff = "30分钟"; | ||
| 186 | + if (!Object.keys(data).length) return; | ||
| 187 | + this.historyData = data[keys[0]].map((item) => { | ||
| 188 | + return { | ||
| 189 | + value: item.value, | ||
| 190 | + ts: formatToDate(item.ts, "YYYY-MM-DD HH:mm:ss"), | ||
| 191 | + }; | ||
| 192 | + }); | ||
| 193 | + }, | ||
| 194 | + methods: { | ||
| 195 | + handleTabClick({ | ||
| 196 | + index | ||
| 197 | + }) { | ||
| 198 | + this.currentTab = index; | ||
| 199 | + }, | ||
| 200 | + handleUpdate(data, e) { | ||
| 201 | + if (!Array.isArray(data)) { | ||
| 202 | + this.historyData = []; | ||
| 203 | + return; | ||
| 204 | + } | ||
| 205 | + this.historyData = data.map((item) => { | ||
| 206 | + return { | ||
| 207 | + value: item.value, | ||
| 208 | + ts: formatToDate(item.ts, "YYYY-MM-DD HH:mm:ss"), | ||
| 209 | + }; | ||
| 210 | + }); | ||
| 211 | + }, | ||
| 212 | + }, | ||
| 213 | + }; | ||
| 214 | +</script> | ||
| 215 | + | ||
| 216 | +<style lang="scss" scoped> | ||
| 217 | + .device-detail-page { | ||
| 218 | + height: 100vh; | ||
| 219 | + background-color: #f8f9fa; | ||
| 220 | + } | ||
| 221 | +</style> |
device-subpackage/device-detail/device-position.vue
renamed from
deviceSubPage/deviceDetailPage/devicePosition.vue
| 1 | +.command-detail { | ||
| 2 | + padding: 5rpx 30rpx; | ||
| 3 | + height: 100vh; | ||
| 4 | + background-color: #f8f9fa; | ||
| 5 | + | ||
| 6 | + .detail-top { | ||
| 7 | + height: 118rpx; | ||
| 8 | + width: 690rpx; | ||
| 9 | + display: flex; | ||
| 10 | + align-items: center; | ||
| 11 | + background-color: #fff; | ||
| 12 | + color: #333; | ||
| 13 | + border-radius: 20rpx; | ||
| 14 | + font-size: 15px; | ||
| 15 | + margin-top: 30rpx; | ||
| 16 | + padding: 30rpx; | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + .detail { | ||
| 20 | + background-color: #fff; | ||
| 21 | + margin-top: 30rpx; | ||
| 22 | + border-radius: 20rpx; | ||
| 23 | + width: 690rpx; | ||
| 24 | + | ||
| 25 | + .detail-item { | ||
| 26 | + padding: 30rpx; | ||
| 27 | + display: flex; | ||
| 28 | + align-items: center; | ||
| 29 | + | ||
| 30 | + .detail-label { | ||
| 31 | + color: #333; | ||
| 32 | + font-size: 15px; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + .detail-value { | ||
| 36 | + color: #666; | ||
| 37 | + font-size: 14px; | ||
| 38 | + margin-left: 30rpx; | ||
| 39 | + } | ||
| 40 | + } | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + .command { | ||
| 44 | + margin: 30rpx 0; | ||
| 45 | + } | ||
| 46 | + } |
| 1 | +.command-record { | ||
| 2 | + padding: 0 30rpx; | ||
| 3 | + background: #f8f9fa; | ||
| 4 | + | ||
| 5 | + .filter-button { | ||
| 6 | + font-size: 12px; | ||
| 7 | + width: 160rpx; | ||
| 8 | + height: 64rpx; | ||
| 9 | + border-radius: 32rpx; | ||
| 10 | + display: flex; | ||
| 11 | + justify-content: center; | ||
| 12 | + align-items: center; | ||
| 13 | + background: #f0f1f2; | ||
| 14 | + color: #666; | ||
| 15 | + | ||
| 16 | + image { | ||
| 17 | + width: 28rpx; | ||
| 18 | + height: 28rpx; | ||
| 19 | + margin-left: 4rpx; | ||
| 20 | + } | ||
| 21 | + } | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + .list-item { | ||
| 25 | + width: 690rpx; | ||
| 26 | + background-color: #fff; | ||
| 27 | + border-radius: 20rpx; | ||
| 28 | + margin: 20rpx auto; | ||
| 29 | + color: #333; | ||
| 30 | + | ||
| 31 | + .item { | ||
| 32 | + .delivered-color { | ||
| 33 | + color: blue; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + padding: 30rpx; | ||
| 37 | + | ||
| 38 | + view { | ||
| 39 | + font-size: 14px; | ||
| 40 | + margin-bottom: 10rpx; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + .time { | ||
| 44 | + margin-top: 20rpx; | ||
| 45 | + color: #999; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + .item-first { | ||
| 49 | + display: flex; | ||
| 50 | + justify-content: space-between; | ||
| 51 | + align-items: center; | ||
| 52 | + font-size: 15px; | ||
| 53 | + font-weight: 500; | ||
| 54 | + align-items: center; | ||
| 55 | + | ||
| 56 | + .item-right { | ||
| 57 | + display: flex; | ||
| 58 | + justify-content: center; | ||
| 59 | + align-items: center; | ||
| 60 | + width: 104rpx; | ||
| 61 | + height: 36rpx; | ||
| 62 | + font-size: 10px; | ||
| 63 | + border-radius: 20rpx; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + .item-fail { | ||
| 67 | + color: #848383; | ||
| 68 | + background-color: #84838325; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + .item.success { | ||
| 72 | + color: #00c9a7; | ||
| 73 | + background-color: #00c9a725; | ||
| 74 | + } | ||
| 75 | + } | ||
| 76 | + } | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + .filter { | ||
| 80 | + padding: 0 30rpx; | ||
| 81 | + | ||
| 82 | + .filter-title { | ||
| 83 | + text-align: center; | ||
| 84 | + margin-top: 14px; | ||
| 85 | + font-size: 16px; | ||
| 86 | + font-weight: 700; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + .button-group { | ||
| 90 | + display: flex; | ||
| 91 | + margin-top: 40rpx; | ||
| 92 | + justify-content: space-between; | ||
| 93 | + | ||
| 94 | + view { | ||
| 95 | + width: 330rpx; | ||
| 96 | + } | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + .command-time-text { | ||
| 100 | + color: #333; | ||
| 101 | + font-size: 14px; | ||
| 102 | + font-weight: 700; | ||
| 103 | + } | ||
| 104 | + } |
device-subpackage/device-detail/static/modal.css
renamed from
deviceSubPage/deviceDetailPage/styles/modal.css
| 1 | +/* ================== | ||
| 2 | +模态窗口 采用colorsui的部分样式 | ||
| 3 | +==================== */ | ||
| 4 | + | ||
| 1 | .cu-modal { | 5 | .cu-modal { |
| 2 | position: fixed; | 6 | position: fixed; |
| 3 | top: 0; | 7 | top: 0; |
| @@ -18,7 +22,7 @@ | @@ -18,7 +22,7 @@ | ||
| 18 | } | 22 | } |
| 19 | 23 | ||
| 20 | .cu-modal::before { | 24 | .cu-modal::before { |
| 21 | - content: "\200B"; | 25 | + content: '\200B'; |
| 22 | display: inline-block; | 26 | display: inline-block; |
| 23 | height: 100%; | 27 | height: 100%; |
| 24 | vertical-align: middle; | 28 | vertical-align: middle; |
| @@ -89,8 +93,8 @@ | @@ -89,8 +93,8 @@ | ||
| 89 | transform: translateX(0%); | 93 | transform: translateX(0%); |
| 90 | } | 94 | } |
| 91 | 95 | ||
| 92 | -.cu-modal .cu-dialog>.cu-bar:first-child .action { | 96 | +.cu-modal .cu-dialog > .cu-bar:first-child .action { |
| 93 | min-width: 100rpx; | 97 | min-width: 100rpx; |
| 94 | margin-right: 0; | 98 | margin-right: 0; |
| 95 | min-height: 100rpx; | 99 | min-height: 100rpx; |
| 96 | -} | 100 | +} |
device-subpackage/device-detail/static/realtime-data.scss
renamed from
deviceSubPage/deviceDetailPage/tabDetail/realtimeData.vue
| 1 | -<template> | ||
| 2 | - <view class="realtime-page"> | ||
| 3 | - <view class="item" v-for="(item, index) in recordList" :key="index"> | ||
| 4 | - <view class="item-top"> | ||
| 5 | - <view>{{ item.key }}</view> | ||
| 6 | - <view class="item-value">{{ item.value }}</view> | ||
| 7 | - </view> | ||
| 8 | - <view class="item-time">{{ item.time }}</view> | ||
| 9 | - </view> | ||
| 10 | - <mescroll-empty v-if="!recordList.length" /> | ||
| 11 | - </view> | ||
| 12 | -</template> | ||
| 13 | - | ||
| 14 | -<script> | ||
| 15 | -export default { | ||
| 16 | - props: { | ||
| 17 | - recordList: { | ||
| 18 | - type: Array, | ||
| 19 | - default: () => [] | ||
| 20 | - } | ||
| 21 | - } | ||
| 22 | -}; | ||
| 23 | -</script> | ||
| 24 | - | ||
| 25 | -<style lang="scss" scoped> | ||
| 26 | -.realtime-page { | ||
| 27 | - .item { | ||
| 28 | - margin: 30rpx; | ||
| 29 | - padding: 30rpx; | ||
| 30 | - border-radius: 20rpx; | ||
| 31 | - background-color: #fff; | ||
| 32 | - height: 160rpx; | ||
| 33 | - width: 690rpx; | ||
| 34 | - .item-top { | ||
| 35 | - display: flex; | ||
| 36 | - justify-content: space-between; | ||
| 37 | - color: #333; | ||
| 38 | - font-size: 16px; | ||
| 39 | - font-family: PingFangSC-Medium, PingFang SC; | ||
| 40 | - font-weight: bold; | ||
| 41 | - .item-value { | ||
| 42 | - font-weight: bold; | ||
| 43 | - } | ||
| 44 | - } | ||
| 45 | - .item-time { | ||
| 46 | - margin-top: 4rpx; | ||
| 47 | - font-size: 13px; | ||
| 48 | - color: #999; | ||
| 49 | - } | ||
| 50 | - } | ||
| 51 | -} | ||
| 52 | -</style> | 1 | +.realtime-page { |
| 2 | + .item { | ||
| 3 | + margin: 30rpx; | ||
| 4 | + padding: 30rpx; | ||
| 5 | + border-radius: 20rpx; | ||
| 6 | + background-color: #fff; | ||
| 7 | + height: 160rpx; | ||
| 8 | + width: 690rpx; | ||
| 9 | + .item-top { | ||
| 10 | + display: flex; | ||
| 11 | + justify-content: space-between; | ||
| 12 | + color: #333; | ||
| 13 | + font-size: 16px; | ||
| 14 | + font-family: PingFangSC-Medium, PingFang SC; | ||
| 15 | + font-weight: bold; | ||
| 16 | + .item-value { | ||
| 17 | + font-weight: bold; | ||
| 18 | + } | ||
| 19 | + } | ||
| 20 | + .item-time { | ||
| 21 | + margin-top: 4rpx; | ||
| 22 | + font-size: 13px; | ||
| 23 | + color: #999; | ||
| 24 | + } | ||
| 25 | + } | ||
| 26 | +} |
deviceSubPage/deviceDetailPage/tabDetail/CommandRecord.vue
deleted
100644 → 0
| 1 | -<template> | ||
| 2 | - <!-- 单向没有响应失败状态 --> | ||
| 3 | - <!-- 响应类型 --> | ||
| 4 | - <view class="command-record"> | ||
| 5 | - <view class="filter-button" @click="openSearchDialog"> | ||
| 6 | - <text>筛选</text> | ||
| 7 | - <image src="../../../static/shaixuan.png" /> | ||
| 8 | - </view> | ||
| 9 | - | ||
| 10 | - <mescroll-uni ref="mescrollRef" @init="mescrollInit" :down="downOption" @down="downCallback" @up="upCallback" | ||
| 11 | - height="700px"> | ||
| 12 | - <view @click="openCommandDetail(item)" class="list-item" v-for="(item, index) in list" :key="index"> | ||
| 13 | - <view class="item"> | ||
| 14 | - <view class="item-first"> | ||
| 15 | - <text>{{ item.deviceName }}</text> | ||
| 16 | - <view v-if="!item.request.oneway"> | ||
| 17 | - <view class="item-right item-success" v-if="item.response">响应成功</view> | ||
| 18 | - <view class="item-right item-fail" v-else>响应失败</view> | ||
| 19 | - </view> | ||
| 20 | - </view> | ||
| 21 | - <view> | ||
| 22 | - 命令类型: | ||
| 23 | - <text style="margin-left: 16rpx;">{{ item.additionalInfo.cmdType===1?'服务':'自定义' }}</text> | ||
| 24 | - </view> | ||
| 25 | - <view v-if="item.statusName"> | ||
| 26 | - 命令状态: | ||
| 27 | - <text :style="{ | ||
| 28 | - color: | ||
| 29 | - item.status == 'EXPIRED' | ||
| 30 | - ? 'red' | ||
| 31 | - : item.status == 'DELIVERED' | ||
| 32 | - ? 'blue' | ||
| 33 | - : item.status == 'QUEUED' | ||
| 34 | - ? '#00C9A7' | ||
| 35 | - : item.status == 'TIMEOUT' | ||
| 36 | - ? 'red' | ||
| 37 | - : item.status == 'SENT' | ||
| 38 | - ? '#00C9A7' | ||
| 39 | - : '' | ||
| 40 | - }" style="margin-left: 16rpx;"> | ||
| 41 | - {{ item.statusName }} | ||
| 42 | - </text> | ||
| 43 | - </view> | ||
| 44 | - <view class="item-first"> | ||
| 45 | - <view> | ||
| 46 | - 响应类型: | ||
| 47 | - <text style="margin-left: 16rpx;">{{ !item.request.oneway?'双向':'单向' }}</text> | ||
| 48 | - </view> | ||
| 49 | - <view class="time">{{ format(item.createTime) }}</view> | ||
| 50 | - </view> | ||
| 51 | - </view> | ||
| 52 | - </view> | ||
| 53 | - </mescroll-uni> | ||
| 54 | - <!-- 告警筛选 --> | ||
| 55 | - <u-popup @close="close" closeable bgColor="#fff" :show="show" mode="bottom" :round="20" | ||
| 56 | - @touchmove.stop.prevent="disabledScroll"> | ||
| 57 | - <view class="filter" @touchmove.stop.prevent="disabledScroll"> | ||
| 58 | - <view class="filter-title"><text>筛选条件</text></view> | ||
| 59 | - <FilterItem :filterList="issueStatus" title="下发状态" | ||
| 60 | - @clickTag="currentIndex => handleClickTag(currentIndex, issueStatus)"></FilterItem> | ||
| 61 | - <view class="button-group"> | ||
| 62 | - <view> | ||
| 63 | - <u-button :customStyle="{ color: '#333' }" color="#e3e3e5" shape="circle" text="重置" | ||
| 64 | - @click="resetFilter"></u-button> | ||
| 65 | - </view> | ||
| 66 | - <view> | ||
| 67 | - <u-button color="#3388ff" shape="circle" text="确认" @click="confirmFilter"></u-button> | ||
| 68 | - </view> | ||
| 69 | - </view> | ||
| 70 | - </view> | ||
| 71 | - </u-popup> | ||
| 72 | - <u-calendar :show="showCalendar" mode="range" @confirm="calendarConfirm" @close="calendarClose" startText="开始时间" | ||
| 73 | - endText="结束时间" confirmDisabledText="请选择日期" :formatter="formatter"></u-calendar> | ||
| 74 | - </view> | ||
| 75 | -</template> | ||
| 76 | -<script> | ||
| 77 | - import FilterItem from '@/pages/device/FilterItem.vue'; | ||
| 78 | - import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js'; | ||
| 79 | - import { | ||
| 80 | - formatToDate | ||
| 81 | - } from '@/plugins/utils.js'; | ||
| 82 | - import { | ||
| 83 | - debounce | ||
| 84 | - } from '@/plugins/throttle.js'; | ||
| 85 | - export default { | ||
| 86 | - mixins: [MescrollMixin], | ||
| 87 | - components: { | ||
| 88 | - FilterItem | ||
| 89 | - }, | ||
| 90 | - props: { | ||
| 91 | - tbDeviceId: { | ||
| 92 | - type: String, | ||
| 93 | - default: '' | ||
| 94 | - } | ||
| 95 | - }, | ||
| 96 | - data() { | ||
| 97 | - return { | ||
| 98 | - show: false, | ||
| 99 | - list: [], | ||
| 100 | - total: '', | ||
| 101 | - timeData: { | ||
| 102 | - selectTime: '', | ||
| 103 | - getTimeGap: '' | ||
| 104 | - }, | ||
| 105 | - showCalendar: false, | ||
| 106 | - issueStatus: [{ | ||
| 107 | - checked: true, | ||
| 108 | - name: '全部', | ||
| 109 | - type: '' | ||
| 110 | - }, | ||
| 111 | - { | ||
| 112 | - checked: false, | ||
| 113 | - name: '响应成功', | ||
| 114 | - type: 'SUCCESSFUL' | ||
| 115 | - }, | ||
| 116 | - { | ||
| 117 | - checked: false, | ||
| 118 | - name: '发送成功', | ||
| 119 | - type: 'DELIVERED' | ||
| 120 | - }, | ||
| 121 | - { | ||
| 122 | - checked: false, | ||
| 123 | - name: '已过期', | ||
| 124 | - type: 'EXPIRED' | ||
| 125 | - }, | ||
| 126 | - { | ||
| 127 | - checked: false, | ||
| 128 | - name: '响应失败', | ||
| 129 | - type: 'FAILED' | ||
| 130 | - } | ||
| 131 | - ], | ||
| 132 | - downOption: { | ||
| 133 | - auto: false //是否在初始化后,自动执行downCallback; 默认true | ||
| 134 | - }, | ||
| 135 | - page: { | ||
| 136 | - num: 0, | ||
| 137 | - size: 10 | ||
| 138 | - } | ||
| 139 | - }; | ||
| 140 | - }, | ||
| 141 | - methods: { | ||
| 142 | - /*下拉刷新的回调 */ | ||
| 143 | - downCallback() { | ||
| 144 | - //联网加载数据 | ||
| 145 | - this.list = []; | ||
| 146 | - this.page.num = 1; | ||
| 147 | - this.loadData(this.page.num, { | ||
| 148 | - tbDeviceId: this.tbDeviceId | ||
| 149 | - }); | ||
| 150 | - }, | ||
| 151 | - format(date) { | ||
| 152 | - return formatToDate(date, 'YYYY-MM-DD HH:mm:ss'); | ||
| 153 | - }, | ||
| 154 | - disabledScroll() { | ||
| 155 | - return; | ||
| 156 | - }, | ||
| 157 | - /*上拉加载的回调: 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10 */ | ||
| 158 | - upCallback() { | ||
| 159 | - //联网加载数据 | ||
| 160 | - this.page.num += 1; | ||
| 161 | - this.loadData(this.page.num, { | ||
| 162 | - tbDeviceId: this.tbDeviceId | ||
| 163 | - }); | ||
| 164 | - }, | ||
| 165 | - //获取告警数据 | ||
| 166 | - loadData(pageNo, params = {}) { | ||
| 167 | - let httpData = { | ||
| 168 | - ...params, | ||
| 169 | - page: pageNo, | ||
| 170 | - pageSize: 10 | ||
| 171 | - }; | ||
| 172 | - uni.$u.http | ||
| 173 | - .get('/yt/rpc', { | ||
| 174 | - params: httpData, | ||
| 175 | - custom: { | ||
| 176 | - load: false | ||
| 177 | - } | ||
| 178 | - }) | ||
| 179 | - .then(res => { | ||
| 180 | - this.total = res.total; | ||
| 181 | - uni.stopPullDownRefresh(); | ||
| 182 | - //方法一(推荐): 后台接口有返回列表的总页数 totalPage | ||
| 183 | - this.mescroll.endByPage(res.items.length, res.total); //必传参数(当前页的数据个数, 总页数) | ||
| 184 | - if (pageNo == 1) { | ||
| 185 | - this.list = res.items; | ||
| 186 | - } else { | ||
| 187 | - this.list = this.list.concat(res.items); | ||
| 188 | - } | ||
| 189 | - }) | ||
| 190 | - .catch(() => { | ||
| 191 | - //联网失败, 结束加载 | ||
| 192 | - this.mescroll.endErr(); | ||
| 193 | - }); | ||
| 194 | - }, | ||
| 195 | - handleClickTag(currentIndex, list) { | ||
| 196 | - list.map((item, index) => { | ||
| 197 | - item.checked = index === currentIndex; | ||
| 198 | - }); | ||
| 199 | - }, | ||
| 200 | - resetFilter() { | ||
| 201 | - const { | ||
| 202 | - issueStatus | ||
| 203 | - } = this; | ||
| 204 | - issueStatus.forEach(item => item.map((item, index) => (item.checked = index === 0))); | ||
| 205 | - }, | ||
| 206 | - close() { | ||
| 207 | - this.show = false; | ||
| 208 | - }, | ||
| 209 | - openSearchDialog() { | ||
| 210 | - this.show = true; | ||
| 211 | - }, | ||
| 212 | - hideKeyboard() { | ||
| 213 | - uni.hideKeyboard(); | ||
| 214 | - }, | ||
| 215 | - calendarConfirm(e) { | ||
| 216 | - this.showCalendar = false; | ||
| 217 | - this.timeData.selectTime = `${e[0]} / ${e[e.length - 1]}`; | ||
| 218 | - }, | ||
| 219 | - confirmFilter() { | ||
| 220 | - const issueStatus = this.issueStatus.find(item => item.checked); | ||
| 221 | - this.loadData(1, { | ||
| 222 | - status: issueStatus.type ? issueStatus.type : undefined, | ||
| 223 | - tbDeviceId: this.tbDeviceId | ||
| 224 | - }); | ||
| 225 | - this.show = false; | ||
| 226 | - }, | ||
| 227 | - calendarClose() { | ||
| 228 | - this.showCalendar = false; | ||
| 229 | - }, | ||
| 230 | - openCommandDetail(item) { | ||
| 231 | - uni.navigateTo({ | ||
| 232 | - url: '/deviceSubPage/deviceDetailPage/tabDetail/CommandDetail?data=' + JSON.stringify(item) | ||
| 233 | - }); | ||
| 234 | - } | ||
| 235 | - } | ||
| 236 | - }; | ||
| 237 | -</script> | ||
| 238 | - | ||
| 239 | -<style lang="scss" scoped> | ||
| 240 | - .command-record { | ||
| 241 | - padding: 0 30rpx; | ||
| 242 | - background: #f8f9fa; | ||
| 243 | - | ||
| 244 | - .filter-button { | ||
| 245 | - font-size: 12px; | ||
| 246 | - width: 160rpx; | ||
| 247 | - height: 64rpx; | ||
| 248 | - border-radius: 32rpx; | ||
| 249 | - display: flex; | ||
| 250 | - justify-content: center; | ||
| 251 | - align-items: center; | ||
| 252 | - background: #f0f1f2; | ||
| 253 | - color: #666; | ||
| 254 | - | ||
| 255 | - image { | ||
| 256 | - width: 28rpx; | ||
| 257 | - height: 28rpx; | ||
| 258 | - margin-left: 4rpx; | ||
| 259 | - } | ||
| 260 | - } | ||
| 261 | - } | ||
| 262 | - | ||
| 263 | - .list-item { | ||
| 264 | - width: 690rpx; | ||
| 265 | - background-color: #fff; | ||
| 266 | - border-radius: 20rpx; | ||
| 267 | - margin: 20rpx auto; | ||
| 268 | - color: #333; | ||
| 269 | - | ||
| 270 | - .item { | ||
| 271 | - .delivered-color { | ||
| 272 | - color: blue; | ||
| 273 | - } | ||
| 274 | - | ||
| 275 | - padding: 30rpx; | ||
| 276 | - | ||
| 277 | - view { | ||
| 278 | - font-size: 14px; | ||
| 279 | - margin-bottom: 10rpx; | ||
| 280 | - } | ||
| 281 | - | ||
| 282 | - .time { | ||
| 283 | - margin-top: 20rpx; | ||
| 284 | - color: #999; | ||
| 285 | - } | ||
| 286 | - | ||
| 287 | - .item-first { | ||
| 288 | - display: flex; | ||
| 289 | - justify-content: space-between; | ||
| 290 | - align-items: center; | ||
| 291 | - font-size: 15px; | ||
| 292 | - font-weight: 500; | ||
| 293 | - align-items: center; | ||
| 294 | - | ||
| 295 | - .item-right { | ||
| 296 | - display: flex; | ||
| 297 | - justify-content: center; | ||
| 298 | - align-items: center; | ||
| 299 | - width: 104rpx; | ||
| 300 | - height: 36rpx; | ||
| 301 | - font-size: 10px; | ||
| 302 | - border-radius: 20rpx; | ||
| 303 | - } | ||
| 304 | - | ||
| 305 | - .item-fail { | ||
| 306 | - color: #848383; | ||
| 307 | - background-color: #84838325; | ||
| 308 | - } | ||
| 309 | - | ||
| 310 | - .item.success { | ||
| 311 | - color: #00c9a7; | ||
| 312 | - background-color: #00c9a725; | ||
| 313 | - } | ||
| 314 | - } | ||
| 315 | - } | ||
| 316 | - } | ||
| 317 | - | ||
| 318 | - .filter { | ||
| 319 | - padding: 0 30rpx; | ||
| 320 | - | ||
| 321 | - .filter-title { | ||
| 322 | - text-align: center; | ||
| 323 | - margin-top: 14px; | ||
| 324 | - font-size: 16px; | ||
| 325 | - font-weight: 700; | ||
| 326 | - } | ||
| 327 | - | ||
| 328 | - .button-group { | ||
| 329 | - display: flex; | ||
| 330 | - margin-top: 40rpx; | ||
| 331 | - justify-content: space-between; | ||
| 332 | - | ||
| 333 | - view { | ||
| 334 | - width: 330rpx; | ||
| 335 | - } | ||
| 336 | - } | ||
| 337 | - } | ||
| 338 | -</style> |