Showing
21 changed files
with
2277 additions
and
2498 deletions
Too many changes to show.
To preserve performance only 21 of 40 files are displayed.
alarm-subpackage/alarm-detail/alarm-detail.vue
renamed from
alarmSubPage/alarmDetailPage/alarmDetail.vue
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 { | |
97 | - deviceName, | |
98 | - severity, | |
99 | - organizationName, | |
100 | - details, | |
101 | - type, | |
102 | - createdTime, | |
103 | - status, | |
104 | - id | |
105 | - } = params | |
106 | - this.detailId = id | |
107 | - this.alarmDetail = [{ | |
108 | - label: '告警场景:', | |
109 | - value: type | |
110 | - }, | |
111 | - { | |
112 | - label: '告警级别:', | |
113 | - value: severity | |
114 | - }, | |
115 | - { | |
116 | - label: '所属组织:', | |
117 | - value: organizationName | |
118 | - }, | |
119 | - { | |
120 | - label: '告警设备:', | |
121 | - value: '' | |
122 | - }, | |
123 | - { | |
124 | - label: '告警条件:', | |
125 | - value: '' | |
126 | - }, | |
127 | - { | |
128 | - label: '告警值:', | |
129 | - value: '' | |
130 | - }, | |
131 | - { | |
132 | - label: '告警时间:', | |
133 | - value: createdTime | |
134 | - }, | |
135 | - { | |
136 | - label: '告警状态:', | |
137 | - value: status | |
138 | - }, | |
139 | - ] | |
140 | - this.formatAlarmDevice(details) | |
141 | - this.formatAlarmValue(details) | |
142 | - this.formatAlarmCondition(details) | |
143 | - } | |
144 | - // 隐藏原生的tabbar | |
145 | - uni.hideTabBar(); | |
146 | - }, | |
147 | - methods: { | |
148 | - ...mapActions(['updateBadgeTotal']), | |
149 | - setAlarmStatus(value) { | |
150 | - return this.alarmSeverity.find(item => item.value === value).label | |
151 | - }, | |
152 | - setAlarmSeverity(value) { | |
153 | - return this.alarmStatus.find(item => item.value === value).label | |
154 | - }, | |
155 | - returnPrevPage(title) { | |
156 | - useShowToast(title) | |
157 | - let pages = getCurrentPages(); //获取所有页面栈实例列表 | |
158 | - let nowPage = pages[pages.length - 1]; //当前页页面实例 | |
159 | - let prevPage = pages[pages.length - 2]; //上一页页面实例 | |
160 | - prevPage.$vm.detailStatus = true; | |
161 | - }, | |
162 | - async handleSubmit() { | |
163 | - if (this.formModel.result == '') return uni.$u.toast('请输入处理结果'); | |
164 | - const res = await api.alarmApi.postAlarmAckApi(this.detailId) | |
165 | - if (res == '') { | |
166 | - this.returnPrevPage('处理成功~') | |
167 | - setTimeout(() => { | |
168 | - useNavigateBack(1) | |
169 | - }, 500); | |
170 | - } | |
171 | - }, | |
172 | - async handleRemove() { | |
173 | - const res = await api.alarmApi.postAlarmClearApi(this.detailId) | |
174 | - if (res == '') { | |
175 | - this.returnPrevPage('清除成功~') | |
176 | - setTimeout(async () => { | |
177 | - useNavigateBack(1) | |
178 | - const res = await uni.$u.http.get('/yt/homepage/app?login=true'); | |
179 | - if (res) { | |
180 | - //异步实时更新告警徽标数 | |
181 | - await this.updateBadgeTotal(res.totalAlarm?.activedAlarm); | |
182 | - } | |
183 | - }, 500); | |
184 | - } | |
185 | - }, | |
186 | - async formatAlarmValue(e) { | |
187 | - const keys = Object.keys(e) | |
188 | - const dataFormat = await this.handleAlarmDetailFormat(keys); | |
189 | - const values = keys.reduce((acc, curr) => { | |
190 | - dataFormat.forEach((dataItem => { | |
191 | - if (dataItem.tbDeviceId === curr) { | |
192 | - const findAttribute = dataItem.attribute.find(findItem => findItem | |
193 | - .identifier === e[curr].key) | |
194 | - acc.push( | |
195 | - `${findAttribute.name}:${e[curr].realValue}${findAttribute.detail?.dataType?.specs?.unit?.key}` | |
196 | - ) | |
197 | - } | |
198 | - })) | |
199 | - return acc | |
200 | - }, []) | |
201 | - this.formatAlarmValueText = values.join(',') | |
202 | - }, | |
203 | - formatAlarmCondition(e) { | |
204 | - const keys = Object.keys(e) | |
205 | - const values = keys.reduce((acc, curr) => { | |
206 | - acc.push({ | |
207 | - login: e[curr].logic, | |
208 | - logicValue: e[curr].logicValue | |
209 | - }) | |
210 | - return acc | |
211 | - }, []) | |
212 | - const operation = [...operationNumberOrDate, ...operationString, ...operationBoolean] | |
213 | - const format = values.map(item => { | |
214 | - const findOperation = operation.find(findItem => findItem.value === item.login)?.symbol | |
215 | - return findOperation + item.logicValue | |
216 | - }) | |
217 | - this.formatAlarmConditionText = format | |
218 | - }, | |
219 | - async formatAlarmDevice(e) { | |
220 | - const keys = Object.keys(e) | |
221 | - const dataFormat = await this.handleAlarmDetailFormat(keys); | |
222 | - this.formatDeviceText = dataFormat.map(item => item.name).join(',') | |
223 | - }, | |
224 | - async handleAlarmDetailFormat(keys) { | |
225 | - const temp = []; | |
226 | - for (let item of keys) { | |
227 | - if (item === 'key' || item === 'data') return; //旧数据则终止 | |
228 | - const deviceDetailRes = await api.deviceApi.getDeviceDetail(item); | |
229 | - const { | |
230 | - deviceProfileId | |
231 | - } = deviceDetailRes; | |
232 | - if (!deviceProfileId) return; | |
233 | - const attributeRes = await api.deviceApi.getAttribute(deviceProfileId); | |
234 | - const dataFormat = this.handleDataFormat(deviceDetailRes, attributeRes); | |
235 | - temp.push(dataFormat); | |
236 | - } | |
237 | - return temp; | |
238 | - }, | |
239 | - handleDataFormat(deviceDetail, attributes) { | |
240 | - const { | |
241 | - name, | |
242 | - tbDeviceId | |
243 | - } = deviceDetail; | |
244 | - const attribute = attributes.map((item) => ({ | |
245 | - identifier: item.identifier, | |
246 | - name: item.name, | |
247 | - detail: item.detail | |
248 | - })); | |
249 | - return { | |
250 | - name, | |
251 | - tbDeviceId, | |
252 | - attribute, | |
253 | - }; | |
254 | - } | |
255 | - } | |
256 | - }; | |
257 | -</script> | |
258 | - | |
259 | -<style lang="scss" scoped> | |
260 | - @import './static/alarmDetail.scss'; | |
261 | - | |
262 | - /deep/ .u-button--primary { | |
263 | - background-color: #377dff !important; | |
264 | - border-color: #377dff !important; | |
265 | - } | |
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 { | |
97 | + deviceName, | |
98 | + severity, | |
99 | + organizationName, | |
100 | + details, | |
101 | + type, | |
102 | + createdTime, | |
103 | + status, | |
104 | + id | |
105 | + } = params | |
106 | + this.detailId = id | |
107 | + this.alarmDetail = [{ | |
108 | + label: '告警场景:', | |
109 | + value: type | |
110 | + }, | |
111 | + { | |
112 | + label: '告警级别:', | |
113 | + value: severity | |
114 | + }, | |
115 | + { | |
116 | + label: '所属组织:', | |
117 | + value: organizationName | |
118 | + }, | |
119 | + { | |
120 | + label: '告警设备:', | |
121 | + value: '' | |
122 | + }, | |
123 | + { | |
124 | + label: '告警条件:', | |
125 | + value: '' | |
126 | + }, | |
127 | + { | |
128 | + label: '告警值:', | |
129 | + value: '' | |
130 | + }, | |
131 | + { | |
132 | + label: '告警时间:', | |
133 | + value: createdTime | |
134 | + }, | |
135 | + { | |
136 | + label: '告警状态:', | |
137 | + value: status | |
138 | + }, | |
139 | + ] | |
140 | + this.formatAlarmDevice(details) | |
141 | + this.formatAlarmValue(details) | |
142 | + this.formatAlarmCondition(details) | |
143 | + } | |
144 | + // 隐藏原生的tabbar | |
145 | + uni.hideTabBar(); | |
146 | + }, | |
147 | + methods: { | |
148 | + ...mapActions(['updateBadgeTotal']), | |
149 | + setAlarmStatus(value) { | |
150 | + return this.alarmSeverity.find(item => item.value === value).label | |
151 | + }, | |
152 | + setAlarmSeverity(value) { | |
153 | + return this.alarmStatus.find(item => item.value === value).label | |
154 | + }, | |
155 | + returnPrevPage(title) { | |
156 | + useShowToast(title) | |
157 | + let pages = getCurrentPages(); //获取所有页面栈实例列表 | |
158 | + let nowPage = pages[pages.length - 1]; //当前页页面实例 | |
159 | + let prevPage = pages[pages.length - 2]; //上一页页面实例 | |
160 | + prevPage.$vm.detailStatus = true; | |
161 | + }, | |
162 | + async handleSubmit() { | |
163 | + if (this.formModel.result == '') return uni.$u.toast('请输入处理结果'); | |
164 | + const res = await api.alarmApi.postAlarmAckApi(this.detailId) | |
165 | + if (res == '') { | |
166 | + this.returnPrevPage('处理成功~') | |
167 | + setTimeout(() => { | |
168 | + useNavigateBack(1) | |
169 | + }, 500); | |
170 | + } | |
171 | + }, | |
172 | + async handleRemove() { | |
173 | + const res = await api.alarmApi.postAlarmClearApi(this.detailId) | |
174 | + if (res == '') { | |
175 | + this.returnPrevPage('清除成功~') | |
176 | + setTimeout(async () => { | |
177 | + useNavigateBack(1) | |
178 | + const res = await uni.$u.http.get('/yt/homepage/app?login=true'); | |
179 | + if (res) { | |
180 | + //异步实时更新告警徽标数 | |
181 | + await this.updateBadgeTotal(res.totalAlarm?.activedAlarm); | |
182 | + } | |
183 | + }, 500); | |
184 | + } | |
185 | + }, | |
186 | + async formatAlarmValue(e) { | |
187 | + const keys = Object.keys(e) | |
188 | + const dataFormat = await this.handleAlarmDetailFormat(keys); | |
189 | + const values = keys.reduce((acc, curr) => { | |
190 | + dataFormat.forEach((dataItem => { | |
191 | + if (dataItem.tbDeviceId === curr) { | |
192 | + const findAttribute = dataItem.attribute.find(findItem => findItem | |
193 | + .identifier === e[curr].key) | |
194 | + acc.push( | |
195 | + `${findAttribute.name}:${e[curr].realValue}${findAttribute.detail?.dataType?.specs?.unit?.key}` | |
196 | + ) | |
197 | + } | |
198 | + })) | |
199 | + return acc | |
200 | + }, []) | |
201 | + this.formatAlarmValueText = values.join(',') | |
202 | + }, | |
203 | + formatAlarmCondition(e) { | |
204 | + const keys = Object.keys(e) | |
205 | + const values = keys.reduce((acc, curr) => { | |
206 | + acc.push({ | |
207 | + login: e[curr].logic, | |
208 | + logicValue: e[curr].logicValue | |
209 | + }) | |
210 | + return acc | |
211 | + }, []) | |
212 | + const operation = [...operationNumberOrDate, ...operationString, ...operationBoolean] | |
213 | + const format = values.map(item => { | |
214 | + const findOperation = operation.find(findItem => findItem.value === item.login)?.symbol | |
215 | + return findOperation + item.logicValue | |
216 | + }) | |
217 | + this.formatAlarmConditionText = format | |
218 | + }, | |
219 | + async formatAlarmDevice(e) { | |
220 | + const keys = Object.keys(e) | |
221 | + const dataFormat = await this.handleAlarmDetailFormat(keys); | |
222 | + this.formatDeviceText = dataFormat.map(item => item.name).join(',') | |
223 | + }, | |
224 | + async handleAlarmDetailFormat(keys) { | |
225 | + const temp = []; | |
226 | + for (let item of keys) { | |
227 | + if (item === 'key' || item === 'data') return; //旧数据则终止 | |
228 | + const deviceDetailRes = await api.deviceApi.getDeviceDetail(item); | |
229 | + const { | |
230 | + deviceProfileId | |
231 | + } = deviceDetailRes; | |
232 | + if (!deviceProfileId) return; | |
233 | + const attributeRes = await api.deviceApi.getAttribute(deviceProfileId); | |
234 | + const dataFormat = this.handleDataFormat(deviceDetailRes, attributeRes); | |
235 | + temp.push(dataFormat); | |
236 | + } | |
237 | + return temp; | |
238 | + }, | |
239 | + handleDataFormat(deviceDetail, attributes) { | |
240 | + const { | |
241 | + name, | |
242 | + tbDeviceId | |
243 | + } = deviceDetail; | |
244 | + const attribute = attributes.map((item) => ({ | |
245 | + identifier: item.identifier, | |
246 | + name: item.name, | |
247 | + detail: item.detail | |
248 | + })); | |
249 | + return { | |
250 | + name, | |
251 | + tbDeviceId, | |
252 | + attribute, | |
253 | + }; | |
254 | + } | |
255 | + } | |
256 | + }; | |
257 | +</script> | |
258 | + | |
259 | +<style lang="scss" scoped> | |
260 | + @import './static/alarmDetail.scss'; | |
261 | + | |
262 | + /deep/ .u-button--primary { | |
263 | + background-color: #377dff !important; | |
264 | + border-color: #377dff !important; | |
265 | + } | |
266 | 266 | </style> |
\ No newline at end of file | ... | ... |
alarm-subpackage/alarm-detail/static/alarmDetail.scss
renamed from
alarmSubPage/alarmDetailPage/static/alarmDetail.scss
... | ... | @@ -17,13 +17,24 @@ const getDeviceDetail = (id) => { |
17 | 17 | }; |
18 | 18 | |
19 | 19 | //设备属性 |
20 | - const getAttribute = (deviceProfileId) => { | |
21 | - return uni.$u.http.get(`/yt/device/attributes/${deviceProfileId}`); | |
20 | +const getAttribute = (deviceProfileId) => { | |
21 | + return uni.$u.http.get(`/yt/device/attributes/${deviceProfileId}`); | |
22 | 22 | }; |
23 | 23 | |
24 | +//命令下发 | |
25 | +const issueCommand = (type, tbDeviceId, data) => { | |
26 | + return uni.$u.http.post(`/rpc/${type==='OneWay'?'oneway':'twoway'}/${tbDeviceId}`, data) | |
27 | +} | |
28 | + | |
29 | +//获取命令下发记录 | |
30 | +const getRpcRecord = (params) => { | |
31 | + return uni.$u.http.get('/yt/rpc', params); | |
32 | +}; | |
24 | 33 | |
25 | 34 | export default { |
26 | 35 | getDeviceApi, |
27 | 36 | getDeviceDetail, |
28 | - getAttribute | |
29 | -} | |
37 | + getAttribute, | |
38 | + issueCommand, | |
39 | + getRpcRecord | |
40 | +} | |
\ No newline at end of file | ... | ... |
... | ... | @@ -103,11 +103,11 @@ uni.$u.http.interceptors.response.use( |
103 | 103 | const routers = getCurrentPages(); |
104 | 104 | const currentRoute = routers[routers.length - 1].route; |
105 | 105 | const isLoginPage = currentRoute.includes( |
106 | - "publicLoginSubPage/public/login" | |
106 | + "login-subpackage/public/login" | |
107 | 107 | ); |
108 | 108 | !isLoginPage && |
109 | 109 | uni.reLaunch({ |
110 | - url: "/publicLoginSubPage/public/login", | |
110 | + url: "/login-subpackage/public/login", | |
111 | 111 | }); |
112 | 112 | // 清空登录信息 |
113 | 113 | store.commit("emptyUserInfo"); | ... | ... |
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="700px" 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 FilterItem from '@/pages/device/components/query-item.vue'; | |
21 | + import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js'; | |
22 | + import api from '@/api/index.js' | |
23 | + import alarmItem from '@/pages/alarm/components/alarm-item.vue' | |
24 | + import alarmPopup from '@/pages/alarm/components/alarm-popup.vue' | |
25 | + import { | |
26 | + useNavigateTo | |
27 | + } from '@/plugins/utils.js' | |
28 | + | |
29 | + export default { | |
30 | + mixins: [MescrollMixin], | |
31 | + components: { | |
32 | + FilterItem, | |
33 | + alarmItem, | |
34 | + alarmPopup | |
35 | + }, | |
36 | + props: { | |
37 | + deviceId: { | |
38 | + type: String, | |
39 | + default: '' | |
40 | + } | |
41 | + }, | |
42 | + data() { | |
43 | + return { | |
44 | + show: false, | |
45 | + list: [], | |
46 | + total: 0, | |
47 | + downOption: { | |
48 | + auto: true //是否在初始化后,自动执行downCallback; 默认true | |
49 | + }, | |
50 | + upOption: { | |
51 | + auto: false // 不自动加载 | |
52 | + }, | |
53 | + page: { | |
54 | + num: 0, | |
55 | + size: 10 | |
56 | + }, | |
57 | + conditions: {}, | |
58 | + }; | |
59 | + }, | |
60 | + methods: { | |
61 | + disabledScroll() { | |
62 | + return; | |
63 | + }, | |
64 | + getQueryCondition(value) { | |
65 | + this.conditions = value | |
66 | + this.conditions.deviceId = this.deviceId | |
67 | + this.loadData(1, this.conditions); | |
68 | + this.close() | |
69 | + }, | |
70 | + resetQuery() { | |
71 | + this.page.num = 1; | |
72 | + this.$refs.alarmPopupRef.resetQuery() | |
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> | |
\ No newline at end of file | ... | ... |
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="请输入下发内容(json格式)" v-model="inputCommandVal" /> | |
130 | - <u-icon @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 | - }; | |
192 | - }, | |
193 | - computed: { | |
194 | - deviceStatus(){ | |
195 | - return this.deviceDetail.deviceState === 'INACTIVE' ? '待激活' : this.deviceDetail.deviceState === 'ONLINE' ? '在线' : '离线' | |
196 | - }, | |
197 | - deviceType() { | |
198 | - return this.deviceDetail.deviceType === 'DIRECT_CONNECTION' ? | |
199 | - '直连设备' : | |
200 | - this.deviceDetail.deviceType === 'GATEWAY' ? | |
201 | - '网关设备' : | |
202 | - this.deviceDetail.deviceType === 'SENSOR' ? | |
203 | - '网关子设备' : | |
204 | - ''; | |
205 | - }, | |
206 | - alarmStatus() { | |
207 | - return this.deviceDetail.alarmStatus === '0' ? '否' : '是'; | |
208 | - }, | |
209 | - formatLastOnlineTime() { | |
210 | - return formatToDate(Number(this.deviceDetail.lastOnlineTime), 'YYYY-MM-DD HH:mm:ss'); | |
211 | - } | |
212 | - }, | |
213 | - onLoad(e) { | |
214 | - // 隐藏原生的tabbar | |
215 | - uni.hideTabBar(); | |
216 | - }, | |
217 | - mounted() {}, | |
218 | - beforeCreate() { | |
219 | - this.modalName = null | |
220 | - }, | |
221 | - methods: { | |
222 | - handleCopy(value) { | |
223 | - uni.showModal({ | |
224 | - content: JSON.stringify(value), | |
225 | - confirmText: '复制内容', | |
226 | - showCancel:false, | |
227 | - success: () => { | |
228 | - uni.setClipboardData({ | |
229 | - data: JSON.stringify(value), | |
230 | - success: () => { | |
231 | - uni.showToast({ | |
232 | - title: '复制成功' | |
233 | - }) | |
234 | - } | |
235 | - }); | |
236 | - }, | |
237 | - | |
238 | - }); | |
239 | - }, | |
240 | - radioChange: function(evt) { | |
241 | - for (let i = 0; i < this.items.length; i++) { | |
242 | - if (this.items[i].value === evt.detail.value) { | |
243 | - this.current = i; | |
244 | - break; | |
245 | - } | |
246 | - } | |
247 | - this.commandType = evt.detail.value | |
248 | - }, | |
249 | - handleClick() { | |
250 | - const data = { | |
251 | - longitude: this.deviceDetail.deviceInfo.longitude || 0, | |
252 | - latitude: this.deviceDetail.deviceInfo.latitude || 0 | |
253 | - }; | |
254 | - uni.navigateTo({ | |
255 | - url: '/deviceSubPage/deviceDetailPage/devicePosition?data=' + JSON.stringify(data) | |
256 | - }); | |
257 | - }, | |
258 | - showModal(e) { | |
259 | - this.modalName = e.currentTarget.dataset.target | |
260 | - this.showNodal = true | |
261 | - }, | |
262 | - showModalBtn() { | |
263 | - this.showModel = true; | |
264 | - this.inputCommandVal = ''; | |
265 | - }, | |
266 | - disabledScroll() { | |
267 | - return; | |
268 | - }, | |
269 | - hiddenModal() { | |
270 | - this.showModel = false; | |
271 | - this.inputCommandVal = ''; | |
272 | - // #ifdef APP-PLUS | |
273 | - this.modalName = null | |
274 | - this.showNodal = false | |
275 | - // #endif | |
276 | - }, | |
277 | - async confirmCommand() { | |
278 | - try { | |
279 | - const commandJsonValue = JSON.parse(this.inputCommandVal); | |
280 | - this.commandValue.persistent = true; | |
281 | - this.commandValue.additionalInfo = { | |
282 | - cmdType: 'API' | |
283 | - }; | |
284 | - this.commandValue.method = 'methodThingskit'; | |
285 | - this.commandValue.params = commandJsonValue | |
286 | - await issueCommand(this.commandType, this.deviceDetail.tbDeviceId, this.commandValue); | |
287 | - this.hiddenModal(); | |
288 | - uni.$u.toast('下发成功~'); | |
289 | - } catch (e) { | |
290 | - uni.$u.toast('下发失败~'); | |
291 | - } | |
292 | - }, | |
293 | - cancelCommand() { | |
294 | - this.hiddenModal(); | |
295 | - // #ifdef APP-PLUS | |
296 | - this.modalName = null | |
297 | - this.showNodal = false | |
298 | - // #endif | |
299 | - } | |
300 | - } | |
301 | - }; | |
302 | -</script> | |
303 | - | |
304 | -<style lang="scss" scoped> | |
305 | - @import url('../styles/modal.css'); | |
306 | - | |
307 | - .cusAppplusContent { | |
308 | - width: 625rpx; | |
309 | - height: 400rpx; | |
310 | - background: #FFFFFF; | |
311 | - box-shadow: 2px 2px 4px 0px rgba(0, 0, 0, 0.03); | |
312 | - border-radius: 10px; | |
313 | - | |
314 | - } | |
315 | - | |
316 | - .cusAppplusCancelBtn { | |
317 | - background: #e3e3e5; | |
318 | - border-radius: 38rpx; | |
319 | - height: 85rpx; | |
320 | - line-height: 85rpx | |
321 | - } | |
322 | - | |
323 | - .cusAppplusConfrimBtn { | |
324 | - background: #3388ff; | |
325 | - border-radius: 38rpx; | |
326 | - height: 85rpx; | |
327 | - line-height: 85rpx | |
328 | - } | |
329 | - | |
330 | - .cu-item { | |
331 | - background: #3388FF; | |
332 | - border-radius: 12px; | |
333 | - width: 120rpx; | |
334 | - height: 48rpx; | |
335 | - text-align: center; | |
336 | - line-height: 40rpx; | |
337 | - | |
338 | - text { | |
339 | - font-size: 12px; | |
340 | - font-family: PingFangSC-Regular, PingFang SC; | |
341 | - font-weight: 400; | |
342 | - color: #FFFFFF; | |
343 | - } | |
344 | - } | |
345 | - | |
346 | - | |
347 | - | |
348 | - .basic-page { | |
349 | - padding: 0 30rpx; | |
350 | - | |
351 | - .basic-title { | |
352 | - display: flex; | |
353 | - justify-content: space-between; | |
354 | - align-items: center; | |
355 | - height: 140rpx; | |
356 | - background-color: #fff; | |
357 | - border-radius: 20rpx; | |
358 | - } | |
359 | - | |
360 | - .detail { | |
361 | - background-color: #fff; | |
362 | - margin-top: 30rpx; | |
363 | - border-radius: 20rpx; | |
364 | - width: 690rpx; | |
365 | - | |
366 | - .detail-item { | |
367 | - padding: 30rpx; | |
368 | - display: flex; | |
369 | - align-items: center; | |
370 | - | |
371 | - .detail-label { | |
372 | - color: #333; | |
373 | - font-size: 15px; | |
374 | - } | |
375 | - | |
376 | - .detail-value { | |
377 | - color: #666; | |
378 | - font-size: 14px; | |
379 | - margin-left: 30rpx; | |
380 | - } | |
381 | - } | |
382 | - } | |
383 | - } | |
384 | - | |
385 | - /deep/ .u-modal__content { | |
386 | - padding: 30rpx 0 !important; | |
387 | - } | |
388 | - | |
389 | - .button-group { | |
390 | - display: flex; | |
391 | - margin-top: 40rpx; | |
392 | - justify-content: space-between; | |
393 | - | |
394 | - view { | |
395 | - width: 300rpx; | |
396 | - } | |
397 | - } | |
398 | -</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" name="map-fill"> | |
10 | + </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 | + <u-button type="primary" shape="circle" size="mini" text="下发命令" @click="handleAppShowModal" /> | |
26 | + <!-- #endif --> | |
27 | + </view> | |
28 | + </view> | |
29 | + <!-- 设备详情 --> | |
30 | + <view class="detail"> | |
31 | + <view class="detail-item"> | |
32 | + <view class="detail-label">设备编号</view> | |
33 | + <view class="detail-value">{{ deviceDetail.sn }}</view> | |
34 | + </view> | |
35 | + <u-line length="90%" margin="0 auto"></u-line> | |
36 | + <view class="detail-item"> | |
37 | + <view class="detail-label">设备类型</view> | |
38 | + <view class="detail-value">{{ deviceType }}</view> | |
39 | + </view> | |
40 | + <u-line length="90%" margin="0 auto"></u-line> | |
41 | + <view class="detail-item"> | |
42 | + <view class="detail-label">所属组织</view> | |
43 | + <view class="detail-value">{{ deviceDetail.organizationDTO.name }}</view> | |
44 | + </view> | |
45 | + <u-line length="90%" margin="0 auto"></u-line> | |
46 | + <view class="detail-item"> | |
47 | + <view class="detail-label">最后连接时间</view> | |
48 | + <view class="detail-value">{{ formatLastOnlineTime }}</view> | |
49 | + </view> | |
50 | + <u-line length="90%" margin="0 auto"></u-line> | |
51 | + <view class="detail-item"> | |
52 | + <view class="detail-label">是否告警</view> | |
53 | + <view class="detail-value">{{ alarmStatus }}</view> | |
54 | + </view> | |
55 | + <u-line length="90%" margin="0 auto"></u-line> | |
56 | + <view class="detail-item"> | |
57 | + <view class="detail-label">设备描述</view> | |
58 | + <view class="detail-value">{{ deviceDetail.description }}</view> | |
59 | + </view> | |
60 | + </view> | |
61 | + <!-- 命令下发 --> | |
62 | + <!-- #ifdef APP-PLUS --> | |
63 | + <app-command-issuance :showModal="appShowModal"></app-command-issuance> | |
64 | + <!-- #endif --> | |
65 | + <!-- #ifdef MP --> | |
66 | + <!-- u-modal在app端弹窗层级无法覆盖 --> | |
67 | + <mp-command-issuance :isShowTCP="isShowTCP" :showModal="mpShowModal" @hideModal="hideMpModal" | |
68 | + @cancelCommand="cancelCommand" @confirmCommand="confirmCommand"></mp-command-issuance> | |
69 | + <!-- #endif --> | |
70 | + </view> | |
71 | +</template> | |
72 | + | |
73 | +<script> | |
74 | + import { | |
75 | + formatToDate | |
76 | + } from '@/plugins/utils.js'; | |
77 | + import { | |
78 | + issueCommand | |
79 | + } from '../api/index.js'; | |
80 | + import api from '@/api/index.js' | |
81 | + import mpCommandIssuance from './mp-command-issuance.vue' | |
82 | + import appCommandIssuance from './app-command-issuance.vue' | |
83 | + import nextModal from '@/components/module/next-modal_1.0.2/components/next-modal/next-modal.vue' | |
84 | + | |
85 | + export default { | |
86 | + components: { | |
87 | + mpCommandIssuance, | |
88 | + appCommandIssuance, | |
89 | + nextModal | |
90 | + }, | |
91 | + props: { | |
92 | + deviceDetail: { | |
93 | + type: Object, | |
94 | + default: () => ({}) | |
95 | + } | |
96 | + }, | |
97 | + data() { | |
98 | + return { | |
99 | + mpShowModal: false, | |
100 | + appShowModal: false, | |
101 | + commandValue: {}, | |
102 | + isShowTCP: false, //用于下发命令时判断是否是TCP/UDP | |
103 | + }; | |
104 | + }, | |
105 | + computed: { | |
106 | + deviceStatus() { | |
107 | + return this.deviceDetail.deviceState === 'INACTIVE' ? '待激活' : this.deviceDetail.deviceState === 'ONLINE' ? | |
108 | + '在线' : '离线' | |
109 | + }, | |
110 | + deviceType() { | |
111 | + return this.deviceDetail.deviceType === 'DIRECT_CONNECTION' ? | |
112 | + '直连设备' : | |
113 | + this.deviceDetail.deviceType === 'GATEWAY' ? | |
114 | + '网关设备' : | |
115 | + this.deviceDetail.deviceType === 'SENSOR' ? | |
116 | + '网关子设备' : | |
117 | + ''; | |
118 | + }, | |
119 | + alarmStatus() { | |
120 | + return this.deviceDetail.alarmStatus === '0' ? '否' : '是'; | |
121 | + }, | |
122 | + formatLastOnlineTime() { | |
123 | + return formatToDate(Number(this.deviceDetail.lastOnlineTime), 'YYYY-MM-DD HH:mm:ss'); | |
124 | + } | |
125 | + }, | |
126 | + onLoad() { | |
127 | + // 隐藏原生的tabbar | |
128 | + uni.hideTabBar(); | |
129 | + }, | |
130 | + methods: { | |
131 | + formatTextStatus(deviceState) { | |
132 | + return deviceState === 'INACTIVE' ? '#666' : deviceState === 'ONLINE' ? '#377DFF' : '#DE4437' | |
133 | + }, | |
134 | + handleClick() { | |
135 | + const data = { | |
136 | + longitude: this.deviceDetail.deviceInfo.longitude || 0, | |
137 | + latitude: this.deviceDetail.deviceInfo.latitude || 0 | |
138 | + }; | |
139 | + uni.navigateTo({ | |
140 | + url: '/deviceSubPage/deviceDetailPage/devicePosition?data=' + JSON.stringify(data) | |
141 | + }); | |
142 | + }, | |
143 | + disabledScroll() { | |
144 | + return; | |
145 | + }, | |
146 | + handleAppShowModal() { | |
147 | + this.appShowModal = true | |
148 | + }, | |
149 | + handleMpShowModal() { | |
150 | + const { | |
151 | + transportType | |
152 | + } = this.deviceDetail.deviceProfile | |
153 | + this.isShowTCP = transportType == 'TCP' ? true : false | |
154 | + this.mpShowModal = true; | |
155 | + }, | |
156 | + hideMpModal() { | |
157 | + this.mpShowModal = false; | |
158 | + }, | |
159 | + hideAppModal() { | |
160 | + this.appShowModal = false | |
161 | + }, | |
162 | + async confirmCommand(commandType, inputCommandVal) { | |
163 | + try { | |
164 | + if (this.isShowTCP) { //TCP的格式只能是字符串 | |
165 | + const zg = /^[0-9a-zA-Z]*$/ | |
166 | + if (!zg.test(inputCommandVal)) { | |
167 | + uni.$u.toast('输入的内容只能是字母和数字的组合') | |
168 | + return | |
169 | + } | |
170 | + this.commandValue.params = inputCommandVal | |
171 | + } else { | |
172 | + this.commandValue.params = JSON.parse(inputCommandVal); | |
173 | + } | |
174 | + if (!commandJsonValue) return uni.$u.toast('请输入下发内容~'); | |
175 | + this.commandValue.persistent = true; | |
176 | + this.commandValue.additionalInfo = { | |
177 | + cmdType: 'API' | |
178 | + }; | |
179 | + this.commandValue.method = 'methodThingskit'; | |
180 | + this.commandValue.params = commandJsonValue | |
181 | + await api.deviceApi.issueCommand(commandType, this.deviceDetail.tbDeviceId, this.commandValue); | |
182 | + this.cancelCommand(); | |
183 | + uni.$u.toast('下发成功~'); | |
184 | + } catch (e) { | |
185 | + uni.$u.toast('下发失败~'); | |
186 | + } | |
187 | + }, | |
188 | + cancelCommand() { | |
189 | + this.hideMpModal(); | |
190 | + this.hideAppModal() | |
191 | + } | |
192 | + } | |
193 | + }; | |
194 | +</script> | |
195 | + | |
196 | +<style lang="scss" scoped> | |
197 | + .basic-page { | |
198 | + padding: 0 30rpx; | |
199 | + | |
200 | + .basic-header { | |
201 | + display: flex; | |
202 | + justify-content: space-between; | |
203 | + align-items: center; | |
204 | + height: 140rpx; | |
205 | + background-color: #fff; | |
206 | + border-radius: 20rpx; | |
207 | + | |
208 | + .basic-text { | |
209 | + width: 370rpx; | |
210 | + } | |
211 | + | |
212 | + .cu-item { | |
213 | + background: #3388FF; | |
214 | + border-radius: 12px; | |
215 | + width: 120rpx; | |
216 | + height: 48rpx; | |
217 | + text-align: center; | |
218 | + line-height: 40rpx; | |
219 | + | |
220 | + text { | |
221 | + font-size: 12px; | |
222 | + font-family: PingFangSC-Regular, PingFang SC; | |
223 | + font-weight: 400; | |
224 | + color: #FFFFFF; | |
225 | + } | |
226 | + } | |
227 | + | |
228 | + .basic-text-status { | |
229 | + font-size: 14px; | |
230 | + } | |
231 | + } | |
232 | + | |
233 | + .detail { | |
234 | + background-color: #fff; | |
235 | + margin-top: 30rpx; | |
236 | + border-radius: 20rpx; | |
237 | + width: 690rpx; | |
238 | + | |
239 | + .detail-item { | |
240 | + padding: 30rpx; | |
241 | + display: flex; | |
242 | + align-items: center; | |
243 | + | |
244 | + .detail-label { | |
245 | + color: #333; | |
246 | + font-size: 15px; | |
247 | + } | |
248 | + | |
249 | + .detail-value { | |
250 | + color: #666; | |
251 | + font-size: 14px; | |
252 | + margin-left: 30rpx; | |
253 | + } | |
254 | + } | |
255 | + } | |
256 | + } | |
257 | + | |
258 | + /deep/ .u-modal__content { | |
259 | + padding: 30rpx 0 !important; | |
260 | + } | |
261 | +</style> | |
\ No newline at end of file | ... | ... |
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 { | |
95 | + data | |
96 | + } = options; | |
97 | + this.commandDetail = JSON.parse(decodeURIComponent(data)); | |
98 | + if (this.commandDetail.response.status === 'SUCCESS') return | |
99 | + this.failContent = JSON.stringify(this.commandDetail.response.error) | |
100 | + } | |
101 | + }; | |
102 | +</script> | |
103 | + | |
104 | +<style lang="scss" scoped> | |
105 | + .command-detail { | |
106 | + padding: 0 30rpx; | |
107 | + height: 100vh; | |
108 | + background-color: #f8f9fa; | |
109 | + | |
110 | + .detail-top { | |
111 | + height: 118rpx; | |
112 | + width: 690rpx; | |
113 | + display: flex; | |
114 | + align-items: center; | |
115 | + background-color: #fff; | |
116 | + color: #333; | |
117 | + border-radius: 20rpx; | |
118 | + font-size: 15px; | |
119 | + margin-top: 30rpx; | |
120 | + padding: 30rpx; | |
121 | + } | |
122 | + | |
123 | + .detail { | |
124 | + background-color: #fff; | |
125 | + margin-top: 30rpx; | |
126 | + border-radius: 20rpx; | |
127 | + width: 690rpx; | |
128 | + | |
129 | + .detail-item { | |
130 | + padding: 30rpx; | |
131 | + display: flex; | |
132 | + align-items: center; | |
133 | + | |
134 | + .detail-label { | |
135 | + color: #333; | |
136 | + font-size: 15px; | |
137 | + } | |
138 | + | |
139 | + .detail-value { | |
140 | + color: #666; | |
141 | + font-size: 14px; | |
142 | + margin-left: 30rpx; | |
143 | + } | |
144 | + } | |
145 | + } | |
146 | + | |
147 | + .command { | |
148 | + margin: 30rpx 0; | |
149 | + } | |
150 | + } | |
151 | +</style> | |
\ No newline at end of file | ... | ... |
device-subpackage/device-detail/components/command-record.vue
renamed from
deviceSubPage/deviceDetailPage/tabDetail/CommandRecord.vue
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/components/query-item.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> | |
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 | + @touchmove.stop.prevent="disabledScroll"> | |
44 | + <view class="filter" @touchmove.stop.prevent="disabledScroll"> | |
45 | + <view class="filter-title"><text>筛选条件</text></view> | |
46 | + <query-item :filterList="issueStatus" title="下发状态" | |
47 | + @clickTag="currentIndex => handleClickTag(currentIndex, issueStatus)"></query-item> | |
48 | + <view class="mt-3"> | |
49 | + <uni-datetime-picker return-type="timestamp" v-model="range" type="datetimerange" | |
50 | + rangeSeparator="至" /> | |
51 | + </view> | |
52 | + <view class="h-30"></view> | |
53 | + <view class="button-group"> | |
54 | + <view> | |
55 | + <u-button :customStyle="{ color: '#333' }" color="#e3e3e5" shape="circle" text="重置" | |
56 | + @click="resetFilter"></u-button> | |
57 | + </view> | |
58 | + <view> | |
59 | + <u-button color="#3388ff" shape="circle" text="确认" @click="confirmFilter"></u-button> | |
60 | + </view> | |
61 | + </view> | |
62 | + </view> | |
63 | + </u-popup> | |
64 | + </view> | |
65 | +</template> | |
66 | +<script> | |
67 | + import queryItem from '@/pages/device/components/query-item.vue'; | |
68 | + import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js'; | |
69 | + import { | |
70 | + formatToDate | |
71 | + } from '@/plugins/utils.js'; | |
72 | + import { | |
73 | + debounce | |
74 | + } from '@/plugins/throttle.js'; | |
75 | + import { | |
76 | + issueStatus | |
77 | + } from '../config/data.js' | |
78 | + import api from '@/api/index.js' | |
79 | + import { | |
80 | + useNavigateTo | |
81 | + } from '@/plugins/utils.js' | |
82 | + | |
83 | + export default { | |
84 | + mixins: [MescrollMixin], | |
85 | + components: { | |
86 | + queryItem | |
87 | + }, | |
88 | + props: { | |
89 | + tbDeviceId: { | |
90 | + type: String, | |
91 | + default: '' | |
92 | + } | |
93 | + }, | |
94 | + data() { | |
95 | + return { | |
96 | + show: false, | |
97 | + list: [], | |
98 | + total: 0, | |
99 | + range: [], | |
100 | + formTime: { | |
101 | + status: '', | |
102 | + startTime: '', | |
103 | + endTime: '' | |
104 | + }, | |
105 | + status: '', | |
106 | + issueStatus, | |
107 | + downOption: { | |
108 | + auto: false //是否在初始化后,自动执行downCallback; 默认true | |
109 | + }, | |
110 | + page: { | |
111 | + num: 0, | |
112 | + size: 10 | |
113 | + } | |
114 | + }; | |
115 | + }, | |
116 | + methods: { | |
117 | + formatCommandStatus(status) { | |
118 | + return status == 'EXPIRED' ? | |
119 | + 'red' : | |
120 | + status == 'DELIVERED' ? | |
121 | + 'blue' : | |
122 | + status == 'QUEUED' ? | |
123 | + '#00C9A7' : | |
124 | + status == 'TIMEOUT' ? | |
125 | + 'red' : | |
126 | + status == 'SENT' ? | |
127 | + '#00C9A7' : '' | |
128 | + }, | |
129 | + downCallback() { | |
130 | + for (let i in this.formTime) Reflect.set(this.formTime, i, '') | |
131 | + this.list = []; | |
132 | + this.page.num = 1; | |
133 | + this.loadData(this.page.num, { | |
134 | + tbDeviceId: this.tbDeviceId | |
135 | + }); | |
136 | + }, | |
137 | + format(date) { | |
138 | + return formatToDate(date, 'YYYY-MM-DD HH:mm:ss'); | |
139 | + }, | |
140 | + disabledScroll() { | |
141 | + return; | |
142 | + }, | |
143 | + upCallback() { | |
144 | + const tbDeviceId = { | |
145 | + tbDeviceId: this.tbDeviceId | |
146 | + } | |
147 | + const condition = Object.values(this.formTime) | |
148 | + if (condition.length === 0) { | |
149 | + this.page.num += 1; | |
150 | + this.loadData(this.page.num); | |
151 | + } else if (condition.filter(Boolean).length > 0) { | |
152 | + this.page.num += 1; | |
153 | + this.loadData(this.page.num, { | |
154 | + ...this.formTime, | |
155 | + ...tbDeviceId | |
156 | + }); | |
157 | + } else { | |
158 | + this.page.num += 1; | |
159 | + this.loadData(this.page.num); | |
160 | + } | |
161 | + }, | |
162 | + async loadData(pageNo, params = {}) { | |
163 | + let httpData = { | |
164 | + ...params, | |
165 | + page: pageNo, | |
166 | + pageSize: 10 | |
167 | + }; | |
168 | + const res = await api.deviceApi.getRpcRecord({ | |
169 | + params: httpData, | |
170 | + custom: { | |
171 | + load: false | |
172 | + } | |
173 | + }) | |
174 | + if (!res) return | |
175 | + this.total = res.total; | |
176 | + uni.stopPullDownRefresh(); | |
177 | + this.mescroll.endByPage(res.items.length, res.total); | |
178 | + if (pageNo == 1) { | |
179 | + this.list = res.items; | |
180 | + } else { | |
181 | + this.list = this.list.concat(res.items); | |
182 | + } | |
183 | + }, | |
184 | + handleClickTag(currentIndex, list) { | |
185 | + list.map((item, index) => { | |
186 | + item.checked = index === currentIndex; | |
187 | + }); | |
188 | + }, | |
189 | + resetFilter() { | |
190 | + const { | |
191 | + issueStatus | |
192 | + } = this; | |
193 | + issueStatus.forEach(item => item.checked = false) | |
194 | + issueStatus[0].checked = true | |
195 | + }, | |
196 | + close() { | |
197 | + this.show = false; | |
198 | + }, | |
199 | + openSearchDialog() { | |
200 | + this.show = true; | |
201 | + this.resetFilter() | |
202 | + this.range = [] | |
203 | + for (let i in this.formTime) Reflect.set(this.formTime, i, '') | |
204 | + }, | |
205 | + hideKeyboard() { | |
206 | + uni.hideKeyboard(); | |
207 | + }, | |
208 | + confirmFilter() { | |
209 | + this.formTime.startTime = this.range[0] | |
210 | + this.formTime.endTime = this.range[1] | |
211 | + const issueStatus = this.issueStatus.find(item => item.checked); | |
212 | + this.formTime.status = issueStatus.type ? issueStatus.type : undefined, | |
213 | + this.loadData(1, { | |
214 | + tbDeviceId: this.tbDeviceId, | |
215 | + ...this.formTime | |
216 | + }); | |
217 | + this.show = false; | |
218 | + }, | |
219 | + openCommandDetail(item) { | |
220 | + useNavigateTo('/device-subpackage/device-detail/components/command-detail?data=', item) | |
221 | + } | |
222 | + } | |
223 | + }; | |
224 | +</script> | |
225 | + | |
226 | +<style lang="scss" scoped> | |
227 | + .command-record { | |
228 | + padding: 0 30rpx; | |
229 | + background: #f8f9fa; | |
230 | + | |
231 | + .filter-button { | |
232 | + font-size: 12px; | |
233 | + width: 160rpx; | |
234 | + height: 64rpx; | |
235 | + border-radius: 32rpx; | |
236 | + display: flex; | |
237 | + justify-content: center; | |
238 | + align-items: center; | |
239 | + background: #f0f1f2; | |
240 | + color: #666; | |
241 | + | |
242 | + image { | |
243 | + width: 28rpx; | |
244 | + height: 28rpx; | |
245 | + margin-left: 4rpx; | |
246 | + } | |
247 | + } | |
248 | + } | |
249 | + | |
250 | + .list-item { | |
251 | + width: 690rpx; | |
252 | + background-color: #fff; | |
253 | + border-radius: 20rpx; | |
254 | + margin: 20rpx auto; | |
255 | + color: #333; | |
256 | + | |
257 | + .item { | |
258 | + .delivered-color { | |
259 | + color: blue; | |
260 | + } | |
261 | + | |
262 | + padding: 30rpx; | |
263 | + | |
264 | + view { | |
265 | + font-size: 14px; | |
266 | + margin-bottom: 10rpx; | |
267 | + } | |
268 | + | |
269 | + .time { | |
270 | + margin-top: 20rpx; | |
271 | + color: #999; | |
272 | + } | |
273 | + | |
274 | + .item-first { | |
275 | + display: flex; | |
276 | + justify-content: space-between; | |
277 | + align-items: center; | |
278 | + font-size: 15px; | |
279 | + font-weight: 500; | |
280 | + align-items: center; | |
281 | + | |
282 | + .item-right { | |
283 | + display: flex; | |
284 | + justify-content: center; | |
285 | + align-items: center; | |
286 | + width: 104rpx; | |
287 | + height: 36rpx; | |
288 | + font-size: 10px; | |
289 | + border-radius: 20rpx; | |
290 | + } | |
291 | + | |
292 | + .item-fail { | |
293 | + color: #848383; | |
294 | + background-color: #84838325; | |
295 | + } | |
296 | + | |
297 | + .item.success { | |
298 | + color: #00c9a7; | |
299 | + background-color: #00c9a725; | |
300 | + } | |
301 | + } | |
302 | + } | |
303 | + } | |
304 | + | |
305 | + .filter { | |
306 | + padding: 0 30rpx; | |
307 | + | |
308 | + .filter-title { | |
309 | + text-align: center; | |
310 | + margin-top: 14px; | |
311 | + font-size: 16px; | |
312 | + font-weight: 700; | |
313 | + } | |
314 | + | |
315 | + .button-group { | |
316 | + display: flex; | |
317 | + margin-top: 40rpx; | |
318 | + justify-content: space-between; | |
319 | + | |
320 | + view { | |
321 | + width: 330rpx; | |
322 | + } | |
323 | + } | |
324 | + } | |
325 | +</style> | |
\ No newline at end of file | ... | ... |
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 | 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 | + | |
23 | + </div> | |
24 | + </view> | |
25 | + <view class="button-group"> | |
26 | + <view> | |
27 | + <u-button :customStyle="{ color: '#333' }" color="#e3e3e5" shape="circle" text="取消" | |
28 | + @click="cancelCommand"></u-button> | |
29 | + </view> | |
30 | + <view> | |
31 | + <u-button color="#3388ff" shape="circle" text="确认" @click="confirmCommand"></u-button> | |
32 | + </view> | |
33 | + </view> | |
34 | + </view> | |
35 | + </u-modal> | |
36 | + </view> | |
37 | +</template> | |
38 | + | |
39 | +<script> | |
40 | + import { | |
41 | + useShowModal | |
42 | + } from '@/plugins/utils.js' | |
43 | + | |
44 | + export default { | |
45 | + props: { | |
46 | + showModal: Boolean, | |
47 | + isShowTCP: Boolean | |
48 | + }, | |
49 | + data() { | |
50 | + return { | |
51 | + current: 0, | |
52 | + commandType: 'OneWay', | |
53 | + inputCommandVal: '', | |
54 | + copyTextValue: { | |
55 | + "method": "methodThingskit", | |
56 | + "params": { | |
57 | + "pin": 7, | |
58 | + "value": 1 | |
59 | + } | |
60 | + } | |
61 | + } | |
62 | + }, | |
63 | + methods: { | |
64 | + cancelCommand() { | |
65 | + this.$emit('cancelCommand') | |
66 | + }, | |
67 | + confirmCommand() { | |
68 | + this.$emit('confirmCommand', this.commandType, this.inputCommandVal) | |
69 | + }, | |
70 | + handleCopy(value) { | |
71 | + useShowModal(JSON.stringify(value), '命令下发', '复制内容').then(res => { | |
72 | + uni.setClipboardData({ | |
73 | + data: JSON.stringify(value), | |
74 | + success: () => { | |
75 | + uni.showToast({ | |
76 | + title: '复制成功' | |
77 | + }) | |
78 | + } | |
79 | + }); | |
80 | + }) | |
81 | + } | |
82 | + } | |
83 | + } | |
84 | +</script> | |
85 | + | |
86 | +<style lang="scss" scoped> | |
87 | + .modal-content { | |
88 | + width: 720rpx; | |
89 | + padding: 0 30rpx; | |
90 | + background-color: white; | |
91 | + | |
92 | + .header-title { | |
93 | + text-align: center; | |
94 | + font-weight: 700; | |
95 | + margin-bottom: 40rpx; | |
96 | + } | |
97 | + | |
98 | + .type-text { | |
99 | + color: #333; | |
100 | + font-size: 14px; | |
101 | + font-weight: 700; | |
102 | + margin-right: 30rpx; | |
103 | + } | |
104 | + | |
105 | + .content-body { | |
106 | + margin-top: 28rpx; | |
107 | + width: 100%; | |
108 | + } | |
109 | + | |
110 | + .button-group { | |
111 | + display: flex; | |
112 | + margin-top: 40rpx; | |
113 | + justify-content: space-between; | |
114 | + | |
115 | + view { | |
116 | + width: 300rpx; | |
117 | + } | |
118 | + } | |
119 | + } | |
120 | +</style> | |
\ No newline at end of file | ... | ... |
device-subpackage/device-detail/components/realtime-data.vue
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 | -} | |
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 | 52 | </style> | ... | ... |
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 | +export { | |
63 | + list, | |
64 | + issueStatus | |
65 | +} | |
\ No newline at end of file | ... | ... |
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 { | |
29 | + getDeviceKeys, | |
30 | + getHistoryData | |
31 | + } from "./api/index.js"; | |
32 | + import { | |
33 | + formatToDate | |
34 | + } from "@/plugins/utils.js"; | |
35 | + import MescrollCompMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mixins/mescroll-comp.js"; | |
36 | + import moment from "moment"; | |
37 | + import base from "@/config/baseUrl.js"; | |
38 | + import { | |
39 | + list | |
40 | + } from './config/data.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 | + bgColor: '#fff', | |
55 | + activeColor: { | |
56 | + fontWeight: 'bold', | |
57 | + color: '#333', | |
58 | + }, | |
59 | + inActiveColor: { | |
60 | + color: '#999', | |
61 | + }, | |
62 | + list, | |
63 | + currentTab: 0, | |
64 | + deviceId: "", | |
65 | + deviceDetail: {}, | |
66 | + keys: [], | |
67 | + yesterday: "", | |
68 | + today: "", | |
69 | + timeDiff: "", | |
70 | + historyData: [], | |
71 | + entityId: "", | |
72 | + startTs: "", | |
73 | + endTs: "", | |
74 | + recordList: [], //实时数据 | |
75 | + isScrollable: false, | |
76 | + attrList: [] | |
77 | + }; | |
78 | + }, | |
79 | + onUnload() { | |
80 | + // 页面关闭时,销毁webSocket连接,否则第二次会存在连接不到的情况 | |
81 | + uni.closeSocket(); | |
82 | + }, | |
83 | + async onLoad(options) { | |
84 | + const { | |
85 | + id, | |
86 | + alarmStatus, | |
87 | + lastOnlineTime, | |
88 | + tbDeviceId, | |
89 | + deviceProfileId | |
90 | + } = | |
91 | + options; | |
92 | + this.deviceId = id; | |
93 | + const res = await uni.$u.http.get(`/yt/device/${id}`); | |
94 | + this.deviceDetail = { | |
95 | + ...res, | |
96 | + alarmStatus, | |
97 | + lastOnlineTime, | |
98 | + }; | |
99 | + | |
100 | + // 设备类型不是网关子设备的添加一个命令记录的选项卡 | |
101 | + if (this.deviceDetail.deviceType !== "SENSOR") { | |
102 | + this.list.push({ | |
103 | + name: "命令记录", | |
104 | + }); | |
105 | + } | |
106 | + this.isScrollable = this.list.length > 4; | |
107 | + if (res.deviceProfileId) { | |
108 | + const getAttrList = await uni.$u.http.get( | |
109 | + `/yt/device/attributes/${res.deviceProfileId}` | |
110 | + ); | |
111 | + if (Array.isArray(getAttrList)) { | |
112 | + this.attrList = getAttrList.map(m => { | |
113 | + return m.identifier | |
114 | + }) | |
115 | + } | |
116 | + } | |
117 | + // 连接webSockte | |
118 | + const socketTask = uni.connectSocket({ | |
119 | + url: `${base.socketPrefix}://${base.baseWebSocketUrl}/api/ws/plugins/telemetry?token=` + | |
120 | + uni.getStorageSync("userInfo").isToken, //仅为示例,并非真实接口地址。 | |
121 | + complete: () => {}, | |
122 | + }); | |
123 | + uni.onSocketOpen((header) => { | |
124 | + socketTask.send({ | |
125 | + data: JSON.stringify({ | |
126 | + attrSubCmds: [], | |
127 | + tsSubCmds: [{ | |
128 | + entityType: "DEVICE", | |
129 | + entityId: tbDeviceId, | |
130 | + scope: "LATEST_TELEMETRY", | |
131 | + cmdId: 1, | |
132 | + keys: this.attrList.join(','), | |
133 | + }, ], | |
134 | + historyCmds: [], | |
135 | + entityDataCmds: [], | |
136 | + entityDataUnsubscribeCmds: [], | |
137 | + alarmDataCmds: [], | |
138 | + alarmDataUnsubscribeCmds: [], | |
139 | + entityCountCmds: [], | |
140 | + entityCountUnsubscribeCmds: [], | |
141 | + }), | |
142 | + success() {}, | |
143 | + }); | |
144 | + }); | |
145 | + socketTask.onMessage((msg) => { | |
146 | + const { | |
147 | + data | |
148 | + } = JSON.parse(msg.data); | |
149 | + const newArray = []; | |
150 | + for (const key in data) { | |
151 | + const [time, value] = data[key].flat(1); | |
152 | + let obj = { | |
153 | + key, | |
154 | + time, | |
155 | + value, | |
156 | + }; | |
157 | + if (this.recordList.length === 0) { | |
158 | + this.recordList.unshift(obj); | |
159 | + } else { | |
160 | + newArray.push(obj); | |
161 | + } | |
162 | + } | |
163 | + newArray.forEach((item) => { | |
164 | + let flag = false; | |
165 | + this.recordList.forEach((item1) => { | |
166 | + if (item1.key === item.key) { | |
167 | + item1.value = item.value; | |
168 | + item1.time = item.time; | |
169 | + flag = true; | |
170 | + } | |
171 | + }); | |
172 | + if (!flag) { | |
173 | + this.recordList.unshift(item); | |
174 | + } | |
175 | + }); | |
176 | + this.recordList = this.recordList.map((item) => { | |
177 | + return { | |
178 | + ...item, | |
179 | + time: formatToDate(item.time, "YYYY-MM-DD HH:mm:ss"), | |
180 | + }; | |
181 | + }); | |
182 | + }); | |
183 | + | |
184 | + const keys = await getDeviceKeys(tbDeviceId); | |
185 | + this.keys = [keys]; | |
186 | + // 昨天 | |
187 | + this.yesterday = moment().subtract(1, "days").format("YYYY-MM-DD"); | |
188 | + // 今天 | |
189 | + this.today = moment().format("YYYY-MM-DD"); | |
190 | + // 开始时间 | |
191 | + this.startTs = moment().subtract(1, "days").format("x"); | |
192 | + // 结束时间 | |
193 | + this.endTs = moment().format("x"); | |
194 | + this.entityId = tbDeviceId; | |
195 | + | |
196 | + const data = await getHistoryData({ | |
197 | + entityId: tbDeviceId, | |
198 | + startTs: this.startTs, | |
199 | + endTs: this.endTs, | |
200 | + keys: keys[0], | |
201 | + // interval: 1800000, | |
202 | + limit: 7, | |
203 | + agg: 'NONE' | |
204 | + }); | |
205 | + this.timeDiff = "30分钟"; | |
206 | + if (!Object.keys(data).length) return; | |
207 | + | |
208 | + this.historyData = data[keys[0]].map((item) => { | |
209 | + return { | |
210 | + value: item.value, | |
211 | + ts: formatToDate(item.ts, "YYYY-MM-DD HH:mm:ss"), | |
212 | + }; | |
213 | + }); | |
214 | + }, | |
215 | + methods: { | |
216 | + handleTabClick({ | |
217 | + index | |
218 | + }) { | |
219 | + this.currentTab = index; | |
220 | + }, | |
221 | + handleUpdate(data, e) { | |
222 | + if (!Array.isArray(data)) { | |
223 | + this.historyData = []; | |
224 | + return; | |
225 | + } | |
226 | + this.historyData = data.map((item) => { | |
227 | + return { | |
228 | + value: item.value, | |
229 | + ts: formatToDate(item.ts, "YYYY-MM-DD HH:mm:ss"), | |
230 | + }; | |
231 | + }); | |
232 | + }, | |
233 | + }, | |
234 | + }; | |
235 | +</script> | |
236 | + | |
237 | +<style lang="scss" scoped> | |
238 | + .device-detail-page { | |
239 | + height: 100vh; | |
240 | + background-color: #f8f9fa; | |
241 | + } | |
242 | +</style> | |
\ No newline at end of file | ... | ... |
device-subpackage/device-detail/device-position.vue
renamed from
deviceSubPage/deviceDetailPage/devicePosition.vue
device-subpackage/device-detail/static/modal.css
renamed from
deviceSubPage/deviceDetailPage/styles/modal.css
deviceSubPage/deviceDetailPage/tabDetail/alarmHistory.vue
deleted
100644 → 0
1 | -<template> | |
2 | - <view class="alert-page"> | |
3 | - <view class="filter-button" @click="openSearchDialog"> | |
4 | - <text>筛选</text> | |
5 | - <image src="../../../static/shaixuan.png" /> | |
6 | - </view> | |
7 | - | |
8 | - <mescroll-uni ref="mescrollRef" @init="mescrollInit" :down="downOption" @down="downCallback" @up="upCallback" height="700px"> | |
9 | - <view @click="openDeviceDetail(item)" class="list-item" v-for="(item, index) in list" :key="index"> | |
10 | - <view class="item"> | |
11 | - <view class="item-first"> | |
12 | - <text style="font-weight: bold;">{{ item.deviceName }}</text> | |
13 | - <view class="item-right"> | |
14 | - <image | |
15 | - :src=" | |
16 | - item.severity === 'CRITICAL' | |
17 | - ? '../../../static/danger.png' | |
18 | - : item.severity === 'MAJOR' | |
19 | - ? '../../../static/major.png' | |
20 | - : item.severity === 'MINOR' | |
21 | - ? '../../../static/secondary.png' | |
22 | - : item.severity === 'WARNING' | |
23 | - ? '../../../static/warn.png' | |
24 | - : '../../../static/noshue.png' | |
25 | - " | |
26 | - ></image> | |
27 | - <text | |
28 | - :style="{ | |
29 | - color: | |
30 | - item.severity === 'CRITICAL' | |
31 | - ? '#DE4437' | |
32 | - : item.severity === 'MAJOR' | |
33 | - ? '#DE7337' | |
34 | - : item.severity === 'MINOR' | |
35 | - ? '#FFC107' | |
36 | - : item.severity === 'WARNING' | |
37 | - ? '#FF1E0B' | |
38 | - : '#00C9A7' | |
39 | - }" | |
40 | - > | |
41 | - {{ | |
42 | - item.severity === 'CRITICAL' | |
43 | - ? '危险' | |
44 | - : item.severity === 'MAJOR' | |
45 | - ? '重要' | |
46 | - : item.severity === 'MINOR' | |
47 | - ? '次要' | |
48 | - : item.severity === 'WARNING' | |
49 | - ? '警告' | |
50 | - : '不确定' | |
51 | - }} | |
52 | - </text> | |
53 | - </view> | |
54 | - </view> | |
55 | - <view> | |
56 | - {{ Object.entries(item.details.data)[0][0] }} : | |
57 | - <text style="font-weight: bold; margin-left:4rpx;">{{ Object.entries(item.details.data)[0][1] }}</text> | |
58 | - </view> | |
59 | - <view v-if="item.status"> | |
60 | - 告警状态:{{ | |
61 | - item.status === 'CLEARED_UNACK' | |
62 | - ? '清除未确认' | |
63 | - : item.status === 'CLEARED_ACK' | |
64 | - ? '清除已确认' | |
65 | - : item.status === 'ACTIVE_UNACK' | |
66 | - ? '激活未确认' | |
67 | - : '激活已确认' | |
68 | - }} | |
69 | - </view> | |
70 | - <view class="time">{{ item.createdTime }}</view> | |
71 | - </view> | |
72 | - </view> | |
73 | - </mescroll-uni> | |
74 | - <!-- 告警筛选 --> | |
75 | - <u-popup @close="close" closeable bgColor="#fff" :show="show" mode="bottom" :round="20" @touchmove.stop.prevent="disabledScroll"> | |
76 | - <view class="filter" @touchmove.stop.prevent="disabledScroll"> | |
77 | - <view class="filter-title"><text>筛选条件</text></view> | |
78 | - <FilterItem :filterList="alarmStatus" title="告警状态" @clickTag="currentIndex => handleClickTag(currentIndex, alarmStatus)"></FilterItem> | |
79 | - <FilterItem :filterList="typeStatus" title="设备类型" @clickTag="currentIndex => handleClickTag(currentIndex, typeStatus)"></FilterItem> | |
80 | - <FilterItem :filterList="alarmLevelStatus" title="告警等级" @clickTag="currentIndex => handleClickTag(currentIndex, alarmLevelStatus)"></FilterItem> | |
81 | - <FilterItem :filterList="timeStatus" title="选择时间" @clickTag="currentIndex => handleClickTag(currentIndex, timeStatus)"></FilterItem> | |
82 | - <view class="button-group"> | |
83 | - <view><u-button :customStyle="{ color: '#333' }" color="#e3e3e5" shape="circle" text="重置" @click="resetFilter"></u-button></view> | |
84 | - <view><u-button color="#3388ff" shape="circle" text="确认" @click="confirmFilter"></u-button></view> | |
85 | - </view> | |
86 | - </view> | |
87 | - </u-popup> | |
88 | - <u-calendar | |
89 | - :show="showCalendar" | |
90 | - mode="range" | |
91 | - @confirm="calendarConfirm" | |
92 | - @close="calendarClose" | |
93 | - startText="开始时间" | |
94 | - endText="结束时间" | |
95 | - confirmDisabledText="请选择日期" | |
96 | - ></u-calendar> | |
97 | - </view> | |
98 | -</template> | |
99 | -<script> | |
100 | -import FilterItem from '@/pages/device/components/query-item.vue'; | |
101 | -import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js'; | |
102 | -export default { | |
103 | - mixins: [MescrollMixin], | |
104 | - components: { | |
105 | - FilterItem | |
106 | - }, | |
107 | - props: { | |
108 | - deviceId: { | |
109 | - type: String, | |
110 | - default: '' | |
111 | - } | |
112 | - }, | |
113 | - data() { | |
114 | - return { | |
115 | - show: false, | |
116 | - list: [], | |
117 | - total: '', | |
118 | - timeData: { | |
119 | - selectTime: '', | |
120 | - getTimeGap: '' | |
121 | - }, | |
122 | - showCalendar: false, | |
123 | - alarmStatus: [ | |
124 | - { | |
125 | - checked: true, | |
126 | - name: '全部', | |
127 | - type: '' | |
128 | - }, | |
129 | - { | |
130 | - checked: false, | |
131 | - name: '激活未确认', | |
132 | - type: 'ACTIVE_UNACK' | |
133 | - }, | |
134 | - { | |
135 | - checked: false, | |
136 | - name: '激活已确认', | |
137 | - type: 'ACTIVE_ACK' | |
138 | - }, | |
139 | - { | |
140 | - checked: false, | |
141 | - name: '清除未确认', | |
142 | - type: 'CLEARED_UNACK' | |
143 | - }, | |
144 | - { | |
145 | - checked: false, | |
146 | - name: '清除已确认', | |
147 | - type: 'CLEARED_ACK' | |
148 | - } | |
149 | - ], | |
150 | - typeStatus: [ | |
151 | - { | |
152 | - checked: true, | |
153 | - name: '全部', | |
154 | - type: '' | |
155 | - }, | |
156 | - { | |
157 | - checked: false, | |
158 | - name: '网关设备', | |
159 | - type: 'GATEWAY' | |
160 | - }, | |
161 | - { | |
162 | - checked: false, | |
163 | - name: '网关子设备', | |
164 | - type: 'SENSOR' | |
165 | - }, | |
166 | - { | |
167 | - checked: false, | |
168 | - name: '直连设备', | |
169 | - type: 'DIRECT_CONNECTION' | |
170 | - } | |
171 | - ], | |
172 | - alarmLevelStatus: [ | |
173 | - { | |
174 | - checked: true, | |
175 | - name: '全部', | |
176 | - type: '' | |
177 | - }, | |
178 | - { | |
179 | - checked: false, | |
180 | - name: '危险', | |
181 | - type: 'CRITICAL' | |
182 | - }, | |
183 | - { | |
184 | - checked: false, | |
185 | - name: '重要', | |
186 | - type: 'MAJOR' | |
187 | - }, | |
188 | - { | |
189 | - checked: false, | |
190 | - name: '次要', | |
191 | - type: 'MINOR' | |
192 | - }, | |
193 | - { | |
194 | - checked: false, | |
195 | - name: '警告', | |
196 | - type: 'WARNING' | |
197 | - }, | |
198 | - { | |
199 | - checked: false, | |
200 | - name: '不确定', | |
201 | - type: 'INDETERMINATE' | |
202 | - } | |
203 | - ], | |
204 | - timeStatus: [ | |
205 | - { | |
206 | - checked: true, | |
207 | - name: '全部', | |
208 | - type: '' | |
209 | - }, | |
210 | - { | |
211 | - checked: false, | |
212 | - name: '30分钟', | |
213 | - type: '1800000' | |
214 | - }, | |
215 | - { | |
216 | - checked: false, | |
217 | - name: '一小时', | |
218 | - type: '3600000' | |
219 | - }, | |
220 | - { | |
221 | - checked: false, | |
222 | - name: '2小时', | |
223 | - type: '7200000' | |
224 | - }, | |
225 | - { | |
226 | - checked: false, | |
227 | - name: '近一天', | |
228 | - type: '86400000' | |
229 | - } | |
230 | - ], | |
231 | - downOption: { | |
232 | - auto: false //是否在初始化后,自动执行downCallback; 默认true | |
233 | - }, | |
234 | - page: { | |
235 | - num: 0, | |
236 | - size: 10 | |
237 | - } | |
238 | - }; | |
239 | - }, | |
240 | - methods: { | |
241 | - disabledScroll() { | |
242 | - return; | |
243 | - }, | |
244 | - /*下拉刷新的回调 */ | |
245 | - downCallback() { | |
246 | - //联网加载数据 | |
247 | - this.list = []; | |
248 | - this.page.num = 1; | |
249 | - this.loadData(this.page.num, { | |
250 | - deviceId: this.deviceId | |
251 | - }); | |
252 | - }, | |
253 | - /*上拉加载的回调: 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10 */ | |
254 | - upCallback() { | |
255 | - //联网加载数据 | |
256 | - this.page.num += 1; | |
257 | - this.loadData(this.page.num, { | |
258 | - deviceId: this.deviceId | |
259 | - }); | |
260 | - }, | |
261 | - //获取告警数据 | |
262 | - loadData(pageNo, params = {}) { | |
263 | - let httpData = { | |
264 | - ...params, | |
265 | - page: pageNo, | |
266 | - pageSize: 10 | |
267 | - }; | |
268 | - uni.$u.http | |
269 | - .get('/yt/alarm', { | |
270 | - params: httpData, | |
271 | - custom: { | |
272 | - load: false | |
273 | - } | |
274 | - }) | |
275 | - .then(res => { | |
276 | - this.total = res.total; | |
277 | - uni.stopPullDownRefresh(); | |
278 | - //方法一(推荐): 后台接口有返回列表的总页数 totalPage | |
279 | - this.mescroll.endByPage(res.items.length, res.total); //必传参数(当前页的数据个数, 总页数) | |
280 | - if (pageNo == 1) { | |
281 | - this.list = res.items; | |
282 | - } else { | |
283 | - this.list = this.list.concat(res.items); | |
284 | - } | |
285 | - }) | |
286 | - .catch(() => { | |
287 | - //联网失败, 结束加载 | |
288 | - this.mescroll.endErr(); | |
289 | - }); | |
290 | - }, | |
291 | - handleClickTag(currentIndex, list) { | |
292 | - list.map((item, index) => { | |
293 | - item.checked = index === currentIndex; | |
294 | - }); | |
295 | - }, | |
296 | - resetFilter() { | |
297 | - const { alarmStatus, typeStatus, alarmLevelStatus, timeStatus } = this; | |
298 | - [alarmStatus, typeStatus, alarmLevelStatus, timeStatus].forEach(item => item.map((item, index) => (item.checked = index === 0))); | |
299 | - }, | |
300 | - close() { | |
301 | - this.show = false; | |
302 | - }, | |
303 | - openSearchDialog() { | |
304 | - this.show = true; | |
305 | - }, | |
306 | - hideKeyboard() { | |
307 | - uni.hideKeyboard(); | |
308 | - }, | |
309 | - calendarConfirm(e) { | |
310 | - this.showCalendar = false; | |
311 | - this.timeData.selectTime = `${e[0]} / ${e[e.length - 1]}`; | |
312 | - }, | |
313 | - confirmFilter() { | |
314 | - const alarmState = this.alarmStatus.find(item => item.checked); | |
315 | - const typeState = this.typeStatus.find(item => item.checked); | |
316 | - const alarmLevelState = this.alarmLevelStatus.find(item => item.checked); | |
317 | - const timeState = this.timeStatus.find(item => item.checked); | |
318 | - const endTs = Date.now(); | |
319 | - const startTs = endTs - timeState.type; | |
320 | - this.loadData(1, { | |
321 | - status: alarmState.type ? alarmState.type : undefined, | |
322 | - deviceType: typeState.type ? typeState.type : undefined, | |
323 | - severity: alarmLevelState.type ? alarmLevelState.type : undefined, | |
324 | - startTime: timeState.type ? startTs : undefined, | |
325 | - endTime: timeState.type ? endTs : undefined, | |
326 | - deviceId: this.deviceId | |
327 | - }); | |
328 | - this.show = false; | |
329 | - }, | |
330 | - calendarClose() { | |
331 | - this.showCalendar = false; | |
332 | - }, | |
333 | - openDeviceDetail(item) { | |
334 | - const { id, deviceName, severity, originatorType, details, createdTime, status } = item; | |
335 | - let obj = { | |
336 | - id, | |
337 | - deviceName, | |
338 | - severity, | |
339 | - originatorType, | |
340 | - details, | |
341 | - createdTime, | |
342 | - status | |
343 | - }; | |
344 | - uni.navigateTo({ | |
345 | - url: '/alarmSubPage/alarmDetailPage/alarmDetail?data=' + JSON.stringify(obj) | |
346 | - // url: '/' + JSON.stringify(obj) | |
347 | - }); | |
348 | - } | |
349 | - } | |
350 | -}; | |
351 | -</script> | |
352 | - | |
353 | -<style lang="scss" scoped> | |
354 | -.filter-button { | |
355 | - font-size: 12px; | |
356 | - width: 160rpx; | |
357 | - height: 64rpx; | |
358 | - border-radius: 32rpx; | |
359 | - display: flex; | |
360 | - justify-content: center; | |
361 | - align-items: center; | |
362 | - background: #f0f1f2; | |
363 | - color: #666; | |
364 | - image { | |
365 | - width: 28rpx; | |
366 | - height: 28rpx; | |
367 | - margin-left: 4rpx; | |
368 | - } | |
369 | -} | |
370 | -.alert-page { | |
371 | - padding: 0 30rpx; | |
372 | - .list-item { | |
373 | - width: 690rpx; | |
374 | - height: 262rpx; | |
375 | - background-color: #fff; | |
376 | - border-radius: 20rpx; | |
377 | - margin: 20rpx auto; | |
378 | - color: #333; | |
379 | - .item { | |
380 | - padding: 30rpx; | |
381 | - view { | |
382 | - font-size: 14px; | |
383 | - margin-bottom: 10rpx; | |
384 | - } | |
385 | - .time { | |
386 | - color: #999; | |
387 | - } | |
388 | - .item-first { | |
389 | - display: flex; | |
390 | - justify-content: space-between; | |
391 | - font-size: 15px; | |
392 | - font-weight: 500; | |
393 | - align-items: center; | |
394 | - .item-right { | |
395 | - display: flex; | |
396 | - align-items: center; | |
397 | - image { | |
398 | - width: 28rpx; | |
399 | - height: 28rpx; | |
400 | - margin-right: 10rpx; | |
401 | - } | |
402 | - } | |
403 | - } | |
404 | - } | |
405 | - } | |
406 | -} | |
407 | - | |
408 | -.filter { | |
409 | - padding: 0 30rpx; | |
410 | - .filter-title { | |
411 | - text-align: center; | |
412 | - margin-top: 14px; | |
413 | - font-size: 16px; | |
414 | - font-weight: 700; | |
415 | - } | |
416 | - .button-group { | |
417 | - display: flex; | |
418 | - margin-top: 40rpx; | |
419 | - justify-content: space-between; | |
420 | - view { | |
421 | - width: 330rpx; | |
422 | - } | |
423 | - } | |
424 | -} | |
425 | -</style> |
feedback-subpackage/feedback/feedback.vue
renamed from
feedBackSubPage/feedback/feedback.vue
feedback-subpackage/feedback/static/feedback.scss
renamed from
feedBackSubPage/feedback/static/feedback.scss
login-subpackage/other/code.vue
renamed from
publicLoginSubPage/other/code.vue
1 | -<template> | |
2 | - <view class="code-page"> | |
3 | - <!-- 公共组件-每个页面必须引入 --> | |
4 | - <public-module></public-module> | |
5 | - <view class="login-body"> | |
6 | - <view class="login-phone"> | |
7 | - <view class="phone-main"> | |
8 | - <text class="text">手机验证码登录</text> | |
9 | - <view class="circleStyle"></view> | |
10 | - </view> | |
11 | - <view class="form-row"><u-input v-model="loginForm.phone" type="number" placeholder="请输入手机号码" | |
12 | - border="bottom"></u-input></view> | |
13 | - <view class="form-row"> | |
14 | - <u-input type="number" v-model="loginForm.verifyCode" placeholder="请输入验证码" border="bottom"> | |
15 | - <template slot="suffix"> | |
16 | - <view @click="getVerifyCode" class="verify-code">{{ codeText }}</view> | |
17 | - </template> | |
18 | - </u-input> | |
19 | - </view> | |
20 | - <button class="submit" size="default" @click="onSubmit"><text class="text">登录</text></button> | |
21 | - <view class="u-flex account-style"> | |
22 | - <view class="content" @click="openAccountFunc">账号密码登录</view> | |
23 | - </view> | |
24 | - <view class="circleStyleBottom"></view> | |
25 | - </view> | |
26 | - </view> | |
27 | - </view> | |
28 | -</template> | |
29 | - | |
30 | -<script> | |
31 | - var clear; | |
32 | - import { | |
33 | - mapState, | |
34 | - mapMutations, | |
35 | - mapActions | |
36 | - } from 'vuex'; | |
37 | - import { | |
38 | - useShowToast, | |
39 | - useNavigateTo | |
40 | - } from '@/plugins/utils.js' | |
41 | - import api from '@/api' | |
42 | - | |
43 | - export default { | |
44 | - data() { | |
45 | - return { | |
46 | - loginForm: { | |
47 | - phone: '', | |
48 | - verifyCode: '' | |
49 | - }, | |
50 | - readonly: false, | |
51 | - codeText: '发送验证码', | |
52 | - }; | |
53 | - }, | |
54 | - methods: { | |
55 | - ...mapMutations(['setUserInfo']), | |
56 | - ...mapActions(['updateBadgeTotal']), | |
57 | - //验证码按钮文字状态 | |
58 | - codeCountdownText() { | |
59 | - const _this = this; | |
60 | - this.readonly = true; | |
61 | - this.codeText = '60s后重新获取'; | |
62 | - var s = 60; | |
63 | - clear = setInterval(() => { | |
64 | - s--; | |
65 | - _this.codeText = s + 's后重新获取'; | |
66 | - if (s <= 0) { | |
67 | - clearInterval(clear); | |
68 | - _this.codeText = '发送验证码'; | |
69 | - _this.readonly = false; | |
70 | - } | |
71 | - }, 1000); | |
72 | - }, | |
73 | - //获取验证码 | |
74 | - async getVerifyCode() { | |
75 | - const phoneRegular = /^1\d{10}$/; | |
76 | - if (this.readonly) { | |
77 | - useShowToast('验证码已发送~') | |
78 | - } | |
79 | - if (!this.loginForm.phone) { | |
80 | - return useShowToast('请输入手机号~') | |
81 | - } | |
82 | - if (!phoneRegular.test(this.loginForm.phone)) { | |
83 | - return useShowToast('手机号格式不正确~') | |
84 | - } | |
85 | - // 获取验证码接口 | |
86 | - await api.loginApi.postPhoneCodeApi(this.loginForm.phone) | |
87 | - this.codeCountdownText(); //开始倒计时 | |
88 | - }, | |
89 | - async onSubmit() { | |
90 | - const phoneRegular = /^1\d{10}$/; | |
91 | - const verifyCodeReg = /^\d{6}$/; | |
92 | - const validateValue = Object.values(this.loginForm) | |
93 | - if (!validateValue[0]) return uni.$u.toast("请输入手机号码~"); | |
94 | - if (!validateValue[1]) return uni.$u.toast("请输入验证码~"); | |
95 | - if (!phoneRegular.test(validateValue[0])) return uni.$u.toast("手机号格式不正确~"); | |
96 | - if (!verifyCodeReg.test(validateValue[1])) return uni.$u.toast("验证码格式不正确~"); | |
97 | - const res = await api.loginApi.postPhoneLoginApi(this.loginForm) | |
98 | - if (res) { | |
99 | - // 储存登录信息 | |
100 | - let tokenInfo = { | |
101 | - refreshToken: res.refreshToken, | |
102 | - isToken: res.token | |
103 | - }; | |
104 | - let userInfo = { | |
105 | - ...tokenInfo, | |
106 | - token: true, //token用于判断是否登录 | |
107 | - isThirdLogin: false | |
108 | - }; | |
109 | - if (userInfo.token) { | |
110 | - this.setUserInfo(userInfo); | |
111 | - } | |
112 | - useShowToast('登录成功~').then(async (res) => { | |
113 | - this.saveUserInfo(); | |
114 | - await this.getAlarmTotalData(); | |
115 | - useReLaunch("/pages/index/index") | |
116 | - }); | |
117 | - } | |
118 | - }, | |
119 | - async getAlarmTotalData() { | |
120 | - const res = await await api.loginApi.getAlarmTotalApi() | |
121 | - if (!res) return | |
122 | - //异步实时更新告警徽标数 | |
123 | - this.updateBadgeTotal(res.totalAlarm?.activedAlarm); | |
124 | - }, | |
125 | - async saveUserInfo() { | |
126 | - //储存个人信息 | |
127 | - const res = await api.loginApi.setUserInfoApi() | |
128 | - if (!res) return | |
129 | - this.setUserInfo(res); | |
130 | - }, | |
131 | - openAccountFunc() { | |
132 | - useNavigateTo('../public/login') | |
133 | - } | |
134 | - } | |
135 | - }; | |
136 | -</script> | |
137 | - | |
138 | -<style lang="scss" scoped> | |
139 | - @import './static/code.scss'; | |
1 | +<template> | |
2 | + <view class="code-page"> | |
3 | + <!-- 公共组件-每个页面必须引入 --> | |
4 | + <public-module></public-module> | |
5 | + <view class="login-body"> | |
6 | + <view class="login-phone"> | |
7 | + <view class="phone-main"> | |
8 | + <text class="text">手机验证码登录</text> | |
9 | + <view class="circleStyle"></view> | |
10 | + </view> | |
11 | + <view class="form-row"><u-input v-model="loginForm.phone" type="number" placeholder="请输入手机号码" | |
12 | + border="bottom"></u-input></view> | |
13 | + <view class="form-row"> | |
14 | + <u-input type="number" v-model="loginForm.verifyCode" placeholder="请输入验证码" border="bottom"> | |
15 | + <template slot="suffix"> | |
16 | + <view @click="getVerifyCode" class="verify-code">{{ codeText }}</view> | |
17 | + </template> | |
18 | + </u-input> | |
19 | + </view> | |
20 | + <button class="submit" size="default" @click="onSubmit"><text class="text">登录</text></button> | |
21 | + <view class="u-flex account-style"> | |
22 | + <view class="content" @click="openAccountFunc">账号密码登录</view> | |
23 | + </view> | |
24 | + <view class="circleStyleBottom"></view> | |
25 | + </view> | |
26 | + </view> | |
27 | + </view> | |
28 | +</template> | |
29 | + | |
30 | +<script> | |
31 | + var clear; | |
32 | + import { | |
33 | + mapState, | |
34 | + mapMutations, | |
35 | + mapActions | |
36 | + } from 'vuex'; | |
37 | + import { | |
38 | + useShowToast, | |
39 | + useNavigateTo | |
40 | + } from '@/plugins/utils.js' | |
41 | + import api from '@/api' | |
42 | + | |
43 | + export default { | |
44 | + data() { | |
45 | + return { | |
46 | + loginForm: { | |
47 | + phone: '', | |
48 | + verifyCode: '' | |
49 | + }, | |
50 | + readonly: false, | |
51 | + codeText: '发送验证码', | |
52 | + }; | |
53 | + }, | |
54 | + methods: { | |
55 | + ...mapMutations(['setUserInfo']), | |
56 | + ...mapActions(['updateBadgeTotal']), | |
57 | + //验证码按钮文字状态 | |
58 | + codeCountdownText() { | |
59 | + const _this = this; | |
60 | + this.readonly = true; | |
61 | + this.codeText = '60s后重新获取'; | |
62 | + var s = 60; | |
63 | + clear = setInterval(() => { | |
64 | + s--; | |
65 | + _this.codeText = s + 's后重新获取'; | |
66 | + if (s <= 0) { | |
67 | + clearInterval(clear); | |
68 | + _this.codeText = '发送验证码'; | |
69 | + _this.readonly = false; | |
70 | + } | |
71 | + }, 1000); | |
72 | + }, | |
73 | + //获取验证码 | |
74 | + async getVerifyCode() { | |
75 | + const phoneRegular = /^1\d{10}$/; | |
76 | + if (this.readonly) { | |
77 | + useShowToast('验证码已发送~') | |
78 | + } | |
79 | + if (!this.loginForm.phone) { | |
80 | + return useShowToast('请输入手机号~') | |
81 | + } | |
82 | + if (!phoneRegular.test(this.loginForm.phone)) { | |
83 | + return useShowToast('手机号格式不正确~') | |
84 | + } | |
85 | + // 获取验证码接口 | |
86 | + await api.loginApi.postPhoneCodeApi(this.loginForm.phone) | |
87 | + this.codeCountdownText(); //开始倒计时 | |
88 | + }, | |
89 | + async onSubmit() { | |
90 | + const phoneRegular = /^1\d{10}$/; | |
91 | + const verifyCodeReg = /^\d{6}$/; | |
92 | + const validateValue = Object.values(this.loginForm) | |
93 | + if (!validateValue[0]) return uni.$u.toast("请输入手机号码~"); | |
94 | + if (!validateValue[1]) return uni.$u.toast("请输入验证码~"); | |
95 | + if (!phoneRegular.test(validateValue[0])) return uni.$u.toast("手机号格式不正确~"); | |
96 | + if (!verifyCodeReg.test(validateValue[1])) return uni.$u.toast("验证码格式不正确~"); | |
97 | + const res = await api.loginApi.postPhoneLoginApi(this.loginForm) | |
98 | + if (res) { | |
99 | + // 储存登录信息 | |
100 | + let tokenInfo = { | |
101 | + refreshToken: res.refreshToken, | |
102 | + isToken: res.token | |
103 | + }; | |
104 | + let userInfo = { | |
105 | + ...tokenInfo, | |
106 | + token: true, //token用于判断是否登录 | |
107 | + isThirdLogin: false | |
108 | + }; | |
109 | + if (userInfo.token) { | |
110 | + this.setUserInfo(userInfo); | |
111 | + } | |
112 | + useShowToast('登录成功~').then(async (res) => { | |
113 | + this.saveUserInfo(); | |
114 | + await this.getAlarmTotalData(); | |
115 | + useReLaunch("/pages/index/index") | |
116 | + }); | |
117 | + } | |
118 | + }, | |
119 | + async getAlarmTotalData() { | |
120 | + const res = await await api.loginApi.getAlarmTotalApi() | |
121 | + if (!res) return | |
122 | + //异步实时更新告警徽标数 | |
123 | + this.updateBadgeTotal(res.totalAlarm?.activedAlarm); | |
124 | + }, | |
125 | + async saveUserInfo() { | |
126 | + //储存个人信息 | |
127 | + const res = await api.loginApi.setUserInfoApi() | |
128 | + if (!res) return | |
129 | + this.setUserInfo(res); | |
130 | + }, | |
131 | + openAccountFunc() { | |
132 | + useNavigateTo('../public/login') | |
133 | + } | |
134 | + } | |
135 | + }; | |
136 | +</script> | |
137 | + | |
138 | +<style lang="scss" scoped> | |
139 | + @import './static/code.scss'; | |
140 | 140 | </style> |
\ No newline at end of file | ... | ... |