Commit 8a4168bd3b34b546bc2fab5495f2720f2a06372d

Authored by fengwotao
1 parent 7db98cc5

perf: 优化重构app

Showing 43 changed files with 742 additions and 804 deletions
... ... @@ -93,50 +93,9 @@
93 93 onLoad(e) {
94 94 if (e.data !== null) {
95 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
  96 + const {deviceName,severity,organizationName,details,type,createdTime,status,id} = params
106 97 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   - ]
  98 + this.alarmDetail = [{label: '告警场景:',value: type},{label: '告警级别:',value: severity},{label: '所属组织:',value: organizationName},{label: '告警设备:',value: ''},{label: '告警条件:',value: ''},{label: '告警值:',value: ''},{label: '告警时间:',value: createdTime},{label: '告警状态:',value: status},]
140 99 this.formatAlarmDevice(details)
141 100 this.formatAlarmValue(details)
142 101 this.formatAlarmCondition(details)
... ... @@ -183,14 +142,14 @@
183 142 }, 500);
184 143 }
185 144 },
  145 + //告警值处理
186 146 async formatAlarmValue(e) {
187 147 const keys = Object.keys(e)
188 148 const dataFormat = await this.handleAlarmDetailFormat(keys);
189 149 const values = keys.reduce((acc, curr) => {
190 150 dataFormat.forEach((dataItem => {
191 151 if (dataItem.tbDeviceId === curr) {
192   - const findAttribute = dataItem.attribute.find(findItem => findItem
193   - .identifier === e[curr].key)
  152 + const findAttribute = dataItem.attribute.find(findItem => findItem.identifier === e[curr].key)
194 153 acc.push(
195 154 `${findAttribute.name}:${e[curr].realValue}${!findAttribute.detail?.dataType?.specs?.unit?.key?'':findAttribute.detail?.dataType?.specs?.unit?.key}`
196 155 )
... ... @@ -200,6 +159,7 @@
200 159 }, [])
201 160 this.formatAlarmValueText = values.join(',')
202 161 },
  162 + //告警条件处理
203 163 formatAlarmCondition(e) {
204 164 const keys = Object.keys(e)
205 165 const values = keys.reduce((acc, curr) => {
... ... @@ -215,8 +175,8 @@
215 175 return findOperation + item.logicValue
216 176 })
217 177 this.formatAlarmConditionText = format.filter(Boolean).join(',')
218   - console.log(this.formatAlarmConditionText);
219 178 },
  179 + //告警设备处理
220 180 async formatAlarmDevice(e) {
221 181 const keys = Object.keys(e)
222 182 const dataFormat = await this.handleAlarmDetailFormat(keys);
... ... @@ -229,9 +189,7 @@
229 189 for (let item of keys) {
230 190 if (item === 'key' || item === 'data') return; //旧数据则终止
231 191 const deviceDetailRes = await api.deviceApi.getDeviceDetail(item);
232   - const {
233   - deviceProfileId
234   - } = deviceDetailRes;
  192 + const { deviceProfileId } = deviceDetailRes;
235 193 if (!deviceProfileId) return;
236 194 const attributeRes = await api.deviceApi.getAttribute(deviceProfileId);
237 195 const dataFormat = this.handleDataFormat(deviceDetailRes, attributeRes);
... ... @@ -240,10 +198,7 @@
240 198 return temp;
241 199 },
242 200 handleDataFormat(deviceDetail, attributes) {
243   - const {
244   - name,
245   - tbDeviceId
246   - } = deviceDetail;
  201 + const { name,tbDeviceId } = deviceDetail;
247 202 const attribute = attributes.map((item) => ({
248 203 identifier: item.identifier,
249 204 name: item.name,
... ...
... ... @@ -20,9 +20,16 @@ const getConfigurationApi = (params = {}) => {
20 20 .get('/yt/configuration/center', params)
21 21 }
22 22
  23 +//获取组织列表
  24 +const getMeOrgListApi = () => {
  25 + return uni.$u.http
  26 + .get('/yt/organization/me/list')
  27 +}
  28 +
23 29 export default {
24 30 getHomeStatisticsApi,
25 31 getCameraApi,
26 32 byCameraIdGetDetailApi,
27   - getConfigurationApi
  33 + getConfigurationApi,
  34 + getMeOrgListApi
28 35 }
... ...
  1 +//上传图片大小
  2 +const UPLOAD_FILE_SIZE = 5242880
  3 +
  4 +export {
  5 + UPLOAD_FILE_SIZE
  6 +}
\ No newline at end of file
... ...
... ... @@ -111,21 +111,13 @@
111 111 </template>
112 112
113 113 <script>
114   - import {
115   - formatToDate
116   - } from '@/plugins/utils.js';
117   - import {
118   - issueCommand
119   - } from '../api/index.js';
  114 + import {formatToDate} from '@/plugins/utils.js';
  115 + import {issueCommand} from '../api/index.js';
120 116 import api from '@/api/index.js';
121 117 import mpCommandIssuance from './mp-command-issuance.vue';
122   - import {
123   - commandTypeList
124   - } from '../config/data.js'
125   - import {
126   - useShowModal
127   - } from '@/plugins/utils.js'
128   -
  118 + import {commandTypeList} from '../config/data.js'
  119 + import {useShowModal} from '@/plugins/utils.js'
  120 +
129 121 export default {
130 122 components: {
131 123 mpCommandIssuance,
... ...
... ... @@ -91,9 +91,7 @@
91 91 }
92 92 },
93 93 onLoad(options) {
94   - const {
95   - data
96   - } = options;
  94 + const { data } = options;
97 95 this.commandDetail = JSON.parse(decodeURIComponent(data));
98 96 if (this.commandDetail.response.status === 'SUCCESS') return
99 97 this.failContent = JSON.stringify(this.commandDetail.response.error)
... ... @@ -102,50 +100,5 @@
102 100 </script>
103 101
104 102 <style lang="scss" scoped>
105   - .command-detail {
106   - padding: 5rpx 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   - }
  103 + @import "../static/command-detail.scss";
151 104 </style>
\ No newline at end of file
... ...
... ... @@ -229,109 +229,7 @@
229 229 };
230 230 </script>
231 231
232   -<style lang="scss" scoped>
233   - .command-record {
234   - padding: 0 30rpx;
235   - background: #f8f9fa;
236   -
237   - .filter-button {
238   - font-size: 12px;
239   - width: 160rpx;
240   - height: 64rpx;
241   - border-radius: 32rpx;
242   - display: flex;
243   - justify-content: center;
244   - align-items: center;
245   - background: #f0f1f2;
246   - color: #666;
247   -
248   - image {
249   - width: 28rpx;
250   - height: 28rpx;
251   - margin-left: 4rpx;
252   - }
253   - }
254   - }
255   -
256   - .list-item {
257   - width: 690rpx;
258   - background-color: #fff;
259   - border-radius: 20rpx;
260   - margin: 20rpx auto;
261   - color: #333;
262   -
263   - .item {
264   - .delivered-color {
265   - color: blue;
266   - }
267   -
268   - padding: 30rpx;
269   -
270   - view {
271   - font-size: 14px;
272   - margin-bottom: 10rpx;
273   - }
274   -
275   - .time {
276   - margin-top: 20rpx;
277   - color: #999;
278   - }
279   -
280   - .item-first {
281   - display: flex;
282   - justify-content: space-between;
283   - align-items: center;
284   - font-size: 15px;
285   - font-weight: 500;
286   - align-items: center;
287   -
288   - .item-right {
289   - display: flex;
290   - justify-content: center;
291   - align-items: center;
292   - width: 104rpx;
293   - height: 36rpx;
294   - font-size: 10px;
295   - border-radius: 20rpx;
296   - }
297 232
298   - .item-fail {
299   - color: #848383;
300   - background-color: #84838325;
301   - }
302   -
303   - .item.success {
304   - color: #00c9a7;
305   - background-color: #00c9a725;
306   - }
307   - }
308   - }
309   - }
310   -
311   - .filter {
312   - padding: 0 30rpx;
313   -
314   - .filter-title {
315   - text-align: center;
316   - margin-top: 14px;
317   - font-size: 16px;
318   - font-weight: 700;
319   - }
320   -
321   - .button-group {
322   - display: flex;
323   - margin-top: 40rpx;
324   - justify-content: space-between;
325   -
326   - view {
327   - width: 330rpx;
328   - }
329   - }
330   -
331   - .command-time-text {
332   - color: #333;
333   - font-size: 14px;
334   - font-weight: 700;
335   - }
336   - }
  233 +<style lang="scss" scoped>
  234 + @import "../static/command-record.scss";
337 235 </style>
\ No newline at end of file
... ...
... ... @@ -19,7 +19,6 @@
19 19 <u-icon v-if="!isShowTCP" @click="handleCopy(copyTextValue)" name="question-circle"
20 20 color="#2979ff" size="28" class="ml-10">
21 21 </u-icon>
22   -
23 22 </div>
24 23 </view>
25 24 <view class="button-group">
... ...
... ... @@ -12,41 +12,16 @@
12 12 </template>
13 13
14 14 <script>
15   -export default {
16   - props: {
17   - recordList: {
18   - type: Array,
19   - default: () => []
  15 + export default {
  16 + props: {
  17 + recordList: {
  18 + type: Array,
  19 + default: () => []
  20 + }
20 21 }
21   - }
22   -};
  22 + };
23 23 </script>
24 24
25 25 <style lang="scss" scoped>
26   -.realtime-page {
27   - .item {
28   - margin: 30rpx;
29   - padding: 30rpx;
30   - border-radius: 20rpx;
31   - background-color: #fff;
32   - height: 160rpx;
33   - width: 690rpx;
34   - .item-top {
35   - display: flex;
36   - justify-content: space-between;
37   - color: #333;
38   - font-size: 16px;
39   - font-family: PingFangSC-Medium, PingFang SC;
40   - font-weight: bold;
41   - .item-value {
42   - font-weight: bold;
43   - }
44   - }
45   - .item-time {
46   - margin-top: 4rpx;
47   - font-size: 13px;
48   - color: #999;
49   - }
50   - }
51   -}
52   -</style>
  26 + @import "../static/realtime-data.scss";
  27 +</style>
\ No newline at end of file
... ...
... ... @@ -25,19 +25,13 @@
25 25 import alarmHistory from "./components/alarm-history.vue";
26 26 import historyData from "./components/history-data.vue";
27 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";
  28 + import { getDeviceKeys,getHistoryData } from "./api/index.js";
  29 + import {formatToDate} from "@/plugins/utils.js";
35 30 import MescrollCompMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mixins/mescroll-comp.js";
36 31 import moment from "moment";
37 32 import base from "@/config/baseUrl.js";
38   - import {
39   - list
40   - } from './config/data.js'
  33 + import { list } from './config/data.js'
  34 + import api from '@/api'
41 35
42 36 export default {
43 37 mixins: [MescrollCompMixin],
... ... @@ -81,16 +75,10 @@
81 75 uni.closeSocket();
82 76 },
83 77 async onLoad(options) {
84   - const {
85   - id,
86   - alarmStatus,
87   - lastOnlineTime,
88   - tbDeviceId,
89   - deviceProfileId
90   - } =
91   - options;
  78 + const {id,alarmStatus,lastOnlineTime,tbDeviceId,deviceProfileId} = options;
92 79 this.deviceId = id;
93   - const res = await uni.$u.http.get(`/yt/device/${id}`);
  80 + const res = await api.deviceApi.getDeviceDetail(this.deviceId)
  81 + if(!res) return
94 82 this.deviceDetail = {
95 83 ...res,
96 84 alarmStatus,
... ... @@ -106,9 +94,7 @@
106 94 }
107 95 this.isScrollable = this.list.length > 4;
108 96 if (res.deviceProfileId) {
109   - const getAttrList = await uni.$u.http.get(
110   - `/yt/device/attributes/${res.deviceProfileId}`
111   - );
  97 + const getAttrList = await api.deviceApi.getAttribute(res.deviceProfileId)
112 98 if (Array.isArray(getAttrList)) {
113 99 this.attrList = getAttrList.map(m => {
114 100 return m.identifier
... ... @@ -117,8 +103,7 @@
117 103 }
118 104 // 连接webSockte
119 105 const socketTask = uni.connectSocket({
120   - url: `${base.socketPrefix}://${base.baseWebSocketUrl}/api/ws/plugins/telemetry?token=` +
121   - uni.getStorageSync("userInfo").isToken, //仅为示例,并非真实接口地址。
  106 + url: `${base.socketPrefix}://${base.baseWebSocketUrl}/api/ws/plugins/telemetry?token=` + uni.getStorageSync("userInfo").isToken, //仅为示例,并非真实接口地址。
122 107 complete: () => {},
123 108 });
124 109 uni.onSocketOpen((header) => {
... ... @@ -144,17 +129,11 @@
144 129 });
145 130 });
146 131 socketTask.onMessage((msg) => {
147   - const {
148   - data
149   - } = JSON.parse(msg.data);
  132 + const { data } = JSON.parse(msg.data);
150 133 const newArray = [];
151 134 for (const key in data) {
152 135 const [time, value] = data[key].flat(1);
153   - let obj = {
154   - key,
155   - time,
156   - value,
157   - };
  136 + let obj = { key,time,value, };
158 137 if (this.recordList.length === 0) {
159 138 this.recordList.unshift(obj);
160 139 } else {
... ... @@ -192,7 +171,6 @@
192 171 // 结束时间
193 172 this.endTs = moment().format("x");
194 173 this.entityId = tbDeviceId;
195   -
196 174 const data = await getHistoryData({
197 175 entityId: tbDeviceId,
198 176 startTs: this.startTs,
... ...
  1 +.command-detail {
  2 + padding: 5rpx 30rpx;
  3 + height: 100vh;
  4 + background-color: #f8f9fa;
  5 +
  6 + .detail-top {
  7 + height: 118rpx;
  8 + width: 690rpx;
  9 + display: flex;
  10 + align-items: center;
  11 + background-color: #fff;
  12 + color: #333;
  13 + border-radius: 20rpx;
  14 + font-size: 15px;
  15 + margin-top: 30rpx;
  16 + padding: 30rpx;
  17 + }
  18 +
  19 + .detail {
  20 + background-color: #fff;
  21 + margin-top: 30rpx;
  22 + border-radius: 20rpx;
  23 + width: 690rpx;
  24 +
  25 + .detail-item {
  26 + padding: 30rpx;
  27 + display: flex;
  28 + align-items: center;
  29 +
  30 + .detail-label {
  31 + color: #333;
  32 + font-size: 15px;
  33 + }
  34 +
  35 + .detail-value {
  36 + color: #666;
  37 + font-size: 14px;
  38 + margin-left: 30rpx;
  39 + }
  40 + }
  41 + }
  42 +
  43 + .command {
  44 + margin: 30rpx 0;
  45 + }
  46 + }
\ No newline at end of file
... ...
  1 +.command-record {
  2 + padding: 0 30rpx;
  3 + background: #f8f9fa;
  4 +
  5 + .filter-button {
  6 + font-size: 12px;
  7 + width: 160rpx;
  8 + height: 64rpx;
  9 + border-radius: 32rpx;
  10 + display: flex;
  11 + justify-content: center;
  12 + align-items: center;
  13 + background: #f0f1f2;
  14 + color: #666;
  15 +
  16 + image {
  17 + width: 28rpx;
  18 + height: 28rpx;
  19 + margin-left: 4rpx;
  20 + }
  21 + }
  22 + }
  23 +
  24 + .list-item {
  25 + width: 690rpx;
  26 + background-color: #fff;
  27 + border-radius: 20rpx;
  28 + margin: 20rpx auto;
  29 + color: #333;
  30 +
  31 + .item {
  32 + .delivered-color {
  33 + color: blue;
  34 + }
  35 +
  36 + padding: 30rpx;
  37 +
  38 + view {
  39 + font-size: 14px;
  40 + margin-bottom: 10rpx;
  41 + }
  42 +
  43 + .time {
  44 + margin-top: 20rpx;
  45 + color: #999;
  46 + }
  47 +
  48 + .item-first {
  49 + display: flex;
  50 + justify-content: space-between;
  51 + align-items: center;
  52 + font-size: 15px;
  53 + font-weight: 500;
  54 + align-items: center;
  55 +
  56 + .item-right {
  57 + display: flex;
  58 + justify-content: center;
  59 + align-items: center;
  60 + width: 104rpx;
  61 + height: 36rpx;
  62 + font-size: 10px;
  63 + border-radius: 20rpx;
  64 + }
  65 +
  66 + .item-fail {
  67 + color: #848383;
  68 + background-color: #84838325;
  69 + }
  70 +
  71 + .item.success {
  72 + color: #00c9a7;
  73 + background-color: #00c9a725;
  74 + }
  75 + }
  76 + }
  77 + }
  78 +
  79 + .filter {
  80 + padding: 0 30rpx;
  81 +
  82 + .filter-title {
  83 + text-align: center;
  84 + margin-top: 14px;
  85 + font-size: 16px;
  86 + font-weight: 700;
  87 + }
  88 +
  89 + .button-group {
  90 + display: flex;
  91 + margin-top: 40rpx;
  92 + justify-content: space-between;
  93 +
  94 + view {
  95 + width: 330rpx;
  96 + }
  97 + }
  98 +
  99 + .command-time-text {
  100 + color: #333;
  101 + font-size: 14px;
  102 + font-weight: 700;
  103 + }
  104 + }
\ No newline at end of file
... ...
  1 +.realtime-page {
  2 + .item {
  3 + margin: 30rpx;
  4 + padding: 30rpx;
  5 + border-radius: 20rpx;
  6 + background-color: #fff;
  7 + height: 160rpx;
  8 + width: 690rpx;
  9 + .item-top {
  10 + display: flex;
  11 + justify-content: space-between;
  12 + color: #333;
  13 + font-size: 16px;
  14 + font-family: PingFangSC-Medium, PingFang SC;
  15 + font-weight: bold;
  16 + .item-value {
  17 + font-weight: bold;
  18 + }
  19 + }
  20 + .item-time {
  21 + margin-top: 4rpx;
  22 + font-size: 13px;
  23 + color: #999;
  24 + }
  25 + }
  26 +}
\ No newline at end of file
... ...
  1 +const rules = {
  2 + 'feedbackInfo.title': {
  3 + type: 'string',
  4 + required: true,
  5 + message: '请输入主题',
  6 + trigger: ['blur', 'change']
  7 + },
  8 + 'feedbackInfo.name': {
  9 + type: 'string',
  10 + required: true,
  11 + message: '请输入姓名',
  12 + trigger: ['blur', 'change']
  13 + },
  14 + 'feedbackInfo.message': {
  15 + type: 'string',
  16 + required: true,
  17 + message: '请输入意见反馈',
  18 + trigger: ['blur', 'change']
  19 + }
  20 +}
  21 +export {
  22 + rules
  23 +}
\ No newline at end of file
... ...
1 1 <template>
2 2 <view class="feedback-page">
3   - <view style="overflow-y: scroll;overflow: hidden;height: 1500rpx;">
  3 + <view class="feedback-container">
4 4 <!-- 公共组件-每个页面必须引入 -->
5 5 <public-module></public-module>
6 6 <view class="form-page">
... ... @@ -55,6 +55,8 @@
55 55 mapState
56 56 } from 'vuex';
57 57 import api from '@/api/index.js'
  58 + import { rules } from './config/data.js'
  59 + import { UPLOAD_FILE_SIZE } from '@/constant/index.js'
58 60
59 61 export default {
60 62 data() {
... ... @@ -69,27 +71,7 @@
69 71 }
70 72 },
71 73 fileList1: [],
72   - rules: {
73   - 'feedbackInfo.title': {
74   - type: 'string',
75   - required: true,
76   - message: '请输入主题',
77   - trigger: ['blur', 'change']
78   - },
79   - 'feedbackInfo.name': {
80   - type: 'string',
81   - required: true,
82   - message: '请输入姓名',
83   - trigger: ['blur', 'change']
84   - },
85   - 'feedbackInfo.message': {
86   - type: 'string',
87   - required: true,
88   - message: '请输入意见反馈',
89   - trigger: ['blur', 'change']
90   - },
91   -
92   - },
  74 + rules
93 75 };
94 76 },
95 77 onReady() {
... ... @@ -113,7 +95,7 @@
113 95 let lists = [].concat(event.file);
114 96 let fileListLen = this[`fileList${event.name}`].length;
115 97 lists.map(item => {
116   - if (item.size > 5242880) {
  98 + if (item.size > UPLOAD_FILE_SIZE) {
117 99 this[`fileList${event.name}`].push({
118 100 ...item,
119 101 status: 'error',
... ... @@ -129,7 +111,7 @@
129 111 });
130 112 for (let i = 0; i < lists.length; i++) {
131 113 const judgeImageSize = lists[0].size
132   - if (judgeImageSize > 5242880) {
  114 + if (judgeImageSize > UPLOAD_FILE_SIZE) {
133 115 return uni.$u.toast('图片限定5M')
134 116 } else {
135 117 const result = await this.uploadFilePromise(lists[i].url);
... ...
... ... @@ -5,6 +5,11 @@
5 5 padding-left: 27rpx;
6 6 overflow-y: scroll;
7 7 overflow: hidden;
  8 + .feedback-container{
  9 + overflow-y: scroll;
  10 + overflow: hidden;
  11 + height: 1500rpx;
  12 + }
8 13 }
9 14
10 15 .form-page {
... ... @@ -12,8 +17,7 @@
12 17 background-color: #ffffff;
13 18 border-radius: 10px;
14 19 margin-top: 20rpx;
15   - padding-left: 15rpx;
16   - padding: 0 20rpx;
  20 + padding: 0 40rpx;
17 21 height: 860rpx;
18 22 .upload-text{
19 23 margin: 15px 0px 0px -16rpx;
... ...
... ... @@ -29,16 +29,8 @@
29 29
30 30 <script>
31 31 var clear;
32   - import {
33   - mapState,
34   - mapMutations,
35   - mapActions
36   - } from 'vuex';
37   - import {
38   - useShowToast,
39   - useNavigateTo,
40   - useReLaunch
41   - } from '@/plugins/utils.js'
  32 + import {mapState,mapMutations,mapActions} from 'vuex';
  33 + import {useShowToast,useNavigateTo,useReLaunch} from '@/plugins/utils.js'
42 34 import api from '@/api'
43 35
44 36 export default {
... ...
... ... @@ -83,17 +83,10 @@
83 83 mapMutations
84 84 } from 'vuex';
85 85 import baseUrl from '@/config/baseUrl.js';
86   - import {
87   - mapState
88   - } from 'vuex';
  86 + import {mapState} from 'vuex';
89 87 import api from '@/api/index.js'
90 88 import permission from '@/js_sdk/wa-permission/permission.js'
91   - import {
92   - useShowModal,
93   - useUploadFile,
94   - useChooseImage,
95   - useFileValidate
96   - } from '@/plugins/utils.js'
  89 + import {useShowModal,useUploadFile,useChooseImage,useFileValidate} from '@/plugins/utils.js'
97 90
98 91 export default {
99 92 data() {
... ...
... ... @@ -47,26 +47,16 @@
47 47 </template>
48 48
49 49 <script>
50   - import {
51   - mapMutations,
52   - mapActions,
53   - mapState
54   - } from "vuex";
  50 + import {mapMutations,mapActions,mapState} from "vuex";
55 51 import api from '@/api'
56   - import {
57   - loginPasswordReg,
58   - useReLaunch,
59   - useShowToast,
60   - useShowModal,
61   - useNavigateTo
62   - } from '@/plugins/utils.js'
  52 + import {loginPasswordReg,useReLaunch,useShowToast,useShowModal,useNavigateTo} from '@/plugins/utils.js'
63 53
64 54 export default {
65 55 data() {
66 56 return {
67 57 loginForm: {
68   - username: "",
69   - password: "",
  58 + username: "fengtao",
  59 + password: "Aa123456@",
70 60 },
71 61 showPassword: true,
72 62 code: "",
... ...
... ... @@ -39,19 +39,19 @@
39 39 }
40 40 },
41 41 {
42   - "path": "pages/index/camera/camera",
  42 + "path": "pages/index/components/camera/camera",
43 43 "style": {
44 44 "navigationBarTitleText": "查看摄像头"
45 45 }
46 46 },
47 47 {
48   - "path": "pages/index/configuration/configuration",
  48 + "path": "pages/index/components/configuration/configuration",
49 49 "style": {
50 50 "navigationBarTitleText": "查看组态"
51 51 }
52 52 },
53 53 {
54   - "path": "pages/index/configuration/configuration-detail",
  54 + "path": "pages/index/components/configuration/configuration-detail",
55 55 "style": {
56 56 "navigationBarTitleText": "组态详情"
57 57 }
... ...
1 1 <template>
2   - <view class="alert-page" :class="pageDisableScroll">
  2 + <view class="alarm-page" :class="pageDisableScroll">
3 3 <!-- 公共组件-每个页面必须引入 -->
4 4 <public-module></public-module>
5 5 <!-- 告警头部 -->
... ...
1 1 <template>
2   - <view class="device-list">
  2 + <view class="alarm-list">
3 3 <view @click="$emit('openAlertDetail',item)" class="list-item" v-for="(item, index) in list" :key="index">
4 4 <view class="u-flex item">
5 5 <view class="item-text text-clip">
... ... @@ -69,6 +69,7 @@
69 69 },
70 70 formatDetailText(e) {
71 71 const keys = Object.keys(e)
  72 + if(!keys) return
72 73 const values = keys.reduce((acc, curr) => {
73 74 acc.push(`${!e[curr].key?'暂无数据':e[curr].key}:${!e[curr].realValue?'暂无数据':e[curr].realValue}`)
74 75 return acc
... ... @@ -80,7 +81,7 @@
80 81 </script>
81 82
82 83 <style lang="scss" scoped>
83   - .device-list {
  84 + .alarm-list {
84 85 display: flex;
85 86 flex-direction: column;
86 87 padding-left: 18rpx;
... ...
1   -.alert-page {
  1 +.alarm-page {
2 2 background: #f8f9fa;
3 3 .device-top {
4 4 padding: 10rpx 30rpx;
... ...
... ... @@ -54,13 +54,8 @@
54 54 });
55 55 },
56 56 resetFilter() {
57   - const {
58   - deviceStatus,
59   - alarmStatus,
60   - typeStatus
61   - } = this;
62   - [deviceStatus, alarmStatus, typeStatus].forEach(item => item.map((item, index) => (item.checked = index ===
63   - 0)));
  57 + const {deviceStatus,alarmStatus,typeStatus} = this;
  58 + [deviceStatus, alarmStatus, typeStatus].forEach(item => item.map((item, index) => (item.checked = index ===0)));
64 59 },
65 60 confirmFilter() {
66 61 const deviceState = this.deviceStatus.find(item => item.checked);
... ... @@ -70,7 +65,6 @@
70 65 deviceState: deviceState.type ? deviceState.type : undefined,
71 66 deviceType: deviceType.type ? deviceType.type : undefined,
72 67 alarmStatus: alarmStatus.type === 0 || alarmStatus.type === 1 ? alarmStatus.type : undefined
73   -
74 68 })
75 69 },
76 70 }
... ...
pages/index/components/camera/camera.vue renamed from pages/index/camera/camera.vue
1   -<template>
2   - <view class="camera-page">
3   - <!-- 公共组件-每个页面必须引入 -->
4   - <public-module></public-module>
5   - <header-org @openOrg="openOrg" :total="cameraTotal" :imageSrc="imageSrc"></header-org>
6   - <view style="height: 150rpx;"></view>
7   - <!-- 自带分页组件 -->
8   - <mescroll-body ref="mescrollRef" :up="upOption" @init="mescrollInit" :down="downOption" @down="downCallback"
9   - @up="upCallback">
10   - <view class="camera-container">
11   - <view class="container-item">
12   - <view v-for="(item, index) in list" :key="item.id" class="item">
13   - <video :data-id="item.id" :data-accessMode="item.accessMode" :key="item.id" preload="none"
14   - :id="'video' + item.id" class="video" :src="item.videoUrl" controls :title="item.name"
15   - x5-video-player-type="h5" x5-video-orientation="portraint" show-mute-btn
16   - :poster="item.avatar" @play="playVideo"></video>
17   - <view style="width:300rpx" class="bottom-text text-clip">
18   - <text class="text">{{ item.name }}</text>
19   - </view>
20   - </view>
21   - </view>
22   - </view>
23   - <mescroll-empty v-if="!list.length" />
24   - </mescroll-body>
25   - <!-- 自带分页组件 -->
26   - <view style="height: 60rpx;"></view>
27   - </view>
28   -</template>
29   -
30   -<script>
31   - import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js';
32   - import api from '@/api/index.js'
33   - import {
34   - useNavigateTo
35   - } from '@/plugins/utils.js'
36   - import headerOrg from '@/components/common/header-org.vue'
37   -
38   - export default {
39   - mixins: [MescrollMixin], // 使用mixin (在main.js注册全局组件)
40   - components:{
41   - headerOrg
42   - },
43   - data() {
44   - return {
45   - imageSrc:'/static/org.png',
46   - page: {
47   - num: 0,
48   - size: 10
49   - },
50   - downOption: {
51   - auto: true //是否在初始化后,自动执行downCallback; 默认true
52   - },
53   - upOption: {
54   - auto: false // 不自动加载
55   - },
56   - current: 0,
57   - cameraTotal: 0,
58   - list: [],
59   - ordId: '',
60   - };
61   - },
62   - onShow() {
63   - if (this.ordId) {
64   - this.loadData(1, this.ordId);
65   - }
66   - },
67   - onHide() {
68   - this.ordId = '';
69   - },
70   - onLoad() {
71   - // 隐藏原生的tabbar
72   - uni.hideTabBar();
73   - },
74   - methods: {
75   - /*下拉刷新的回调 */
76   - downCallback() {
77   - //联网加载数据
78   - this.page.num = 1;
79   - this.loadData(1);
80   - },
81   - /*上拉加载的回调: 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10 */
82   - upCallback() {
83   - //联网加载数据
84   - this.page.num += 1;
85   - this.loadData(this.page.num);
86   - },
87   - async loadData(pageNo, organizationV) {
88   - let httpData = {
89   - page: pageNo,
90   - pageSize: 10,
91   - organizationId: organizationV
92   - };
93   - const res = await api.homeApi.getCameraApi({
94   - params: httpData,
95   - custom: {
96   - load: false
97   - }
98   - })
99   - if (res) {
100   - uni.stopPullDownRefresh();
101   - this.mescroll.endByPage(res.items.length, res.total);
102   - this.cameraTotal = res.total;
103   - if (pageNo == 1) {
104   - this.list = res.items;
105   - } else {
106   - this.list = this.list.concat(res.items);
107   - }
108   - }
109   - },
110   - hideImageUrl(item, index) {
111   - this.current = index;
112   - },
113   - async playVideo(e) {
114   - const {
115   - currentTarget: {
116   - dataset: {
117   - accessmode,
118   - id
119   - }
120   - } = {}
121   - } = e
122   - const isExistVideoUrl = this.list.find(item => item.id == id).videoUrl
123   - if (accessmode === 1 && !isExistVideoUrl) {
124   - const res = api.homeApi.byCameraIdGetDetailApi(id)
125   - if (res) {
126   - const {
127   - data: {
128   - url
129   - } = {}
130   - } = res
131   - const index = this.list.findIndex(item => item.id === id)
132   - if (~index && url) {
133   - this.list.splice(index, 1, {
134   - ...this.list[index],
135   - videoUrl: url
136   - })
137   - this.$nextTick(() => {
138   - let currentId = 'video' + id;
139   - const videoContext = uni.createVideoContext(currentId, this);
140   - videoContext.play()
141   - })
142   - }
143   - }
144   - }
145   - /**
146   - * 点击全屏播放当前视频,暂停其余视频
147   - * 兼容APP和MP端
148   - */
149   - let currentId = 'video' + id;
150   - this.videoContent = uni.createVideoContext(currentId, this);
151   - this.videoContent.requestFullScreen();
152   - // 获取视频列表
153   - let trailer = this.list;
154   - trailer.forEach((item, index) => {
155   - if (item.videoUrl != null && item.videoUrl != '') {
156   - let temp = 'video' + item.id;
157   - if (temp != currentId) {
158   - //暂停不是当前的视频
159   - uni.createVideoContext(temp, this).pause();
160   - }
161   - }
162   - });
163   - },
164   - openOrg() {
165   - useNavigateTo('/pages/organization/organization')
166   - }
167   - }
168   - };
169   -</script>
170   -
171   -<style lang="scss" scoped>
172   - @import '../static/camera.scss';
  1 +<template>
  2 + <view class="camera-page">
  3 + <!-- 公共组件-每个页面必须引入 -->
  4 + <public-module></public-module>
  5 + <header-org @openOrg="openOrg" :total="cameraTotal" :imageSrc="imageSrc"></header-org>
  6 + <view style="height: 150rpx;"></view>
  7 + <!-- 自带分页组件 -->
  8 + <mescroll-body ref="mescrollRef" :up="upOption" @init="mescrollInit" :down="downOption" @down="downCallback"
  9 + @up="upCallback">
  10 + <view class="camera-container">
  11 + <view class="container-item">
  12 + <view v-for="(item, index) in list" :key="item.id" class="item">
  13 + <video :data-id="item.id" :data-accessMode="item.accessMode" :key="item.id" preload="none"
  14 + :id="'video' + item.id" class="video" :src="item.videoUrl" controls :title="item.name"
  15 + x5-video-player-type="h5" x5-video-orientation="portraint" show-mute-btn
  16 + :poster="item.avatar" @play="playVideo"></video>
  17 + <view class="bottom-text text-clip w-300">
  18 + <text class="text">{{ item.name }}</text>
  19 + </view>
  20 + </view>
  21 + </view>
  22 + </view>
  23 + <mescroll-empty v-if="!list.length" />
  24 + </mescroll-body>
  25 + <!-- 自带分页组件 -->
  26 + <view style="height: 60rpx;"></view>
  27 + </view>
  28 +</template>
  29 +
  30 +<script>
  31 + import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js';
  32 + import api from '@/api/index.js'
  33 + import {
  34 + useNavigateTo
  35 + } from '@/plugins/utils.js'
  36 + import headerOrg from '@/components/common/header-org.vue'
  37 +
  38 + export default {
  39 + mixins: [MescrollMixin], // 使用mixin (在main.js注册全局组件)
  40 + components:{
  41 + headerOrg
  42 + },
  43 + data() {
  44 + return {
  45 + imageSrc:'/static/org.png',
  46 + page: {
  47 + num: 0,
  48 + size: 10
  49 + },
  50 + downOption: {
  51 + auto: true //是否在初始化后,自动执行downCallback; 默认true
  52 + },
  53 + upOption: {
  54 + auto: false // 不自动加载
  55 + },
  56 + current: 0,
  57 + cameraTotal: 0,
  58 + list: [],
  59 + ordId: '',
  60 + };
  61 + },
  62 + onShow() {
  63 + if (this.ordId) {
  64 + this.loadData(1, this.ordId);
  65 + }
  66 + },
  67 + onHide() {
  68 + this.ordId = '';
  69 + },
  70 + onLoad() {
  71 + // 隐藏原生的tabbar
  72 + uni.hideTabBar();
  73 + },
  74 + methods: {
  75 + /*下拉刷新的回调 */
  76 + downCallback() {
  77 + //联网加载数据
  78 + this.page.num = 1;
  79 + this.loadData(1);
  80 + },
  81 + /*上拉加载的回调: 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10 */
  82 + upCallback() {
  83 + //联网加载数据
  84 + this.page.num += 1;
  85 + this.loadData(this.page.num);
  86 + },
  87 + async loadData(pageNo, organizationId) {
  88 + let httpData = {
  89 + page: pageNo,
  90 + pageSize: 10,
  91 + organizationId
  92 + };
  93 + const res = await api.homeApi.getCameraApi({
  94 + params: httpData,
  95 + custom: {
  96 + load: false
  97 + }
  98 + })
  99 + if (res) {
  100 + uni.stopPullDownRefresh();
  101 + this.mescroll.endByPage(res.items.length, res.total);
  102 + this.cameraTotal = res.total;
  103 + if (pageNo == 1) {
  104 + this.list = res.items;
  105 + } else {
  106 + this.list = this.list.concat(res.items);
  107 + }
  108 + }
  109 + },
  110 + //播放视频
  111 + async playVideo(e) {
  112 + const {currentTarget: {dataset: {accessmode,id}} = {}} = e
  113 + const isExistVideoUrl = this.list.find(item => item.id == id).videoUrl
  114 + if (accessmode === 1 && !isExistVideoUrl) {
  115 + const res = api.homeApi.byCameraIdGetDetailApi(id)
  116 + if (res) {
  117 + const {data: {url} = {}} = res
  118 + const index = this.list.findIndex(item => item.id === id)
  119 + if (~index && url) {
  120 + this.list.splice(index, 1, {
  121 + ...this.list[index],
  122 + videoUrl: url
  123 + })
  124 + this.$nextTick(() => {
  125 + let currentId = 'video' + id;
  126 + const videoContext = uni.createVideoContext(currentId, this);
  127 + videoContext.play()
  128 + })
  129 + }
  130 + }
  131 + }
  132 + /**
  133 + * 点击全屏播放当前视频,暂停其余视频
  134 + * 兼容APP和MP端
  135 + */
  136 + let currentId = 'video' + id;
  137 + this.videoContent = uni.createVideoContext(currentId, this);
  138 + this.videoContent.requestFullScreen();
  139 + // 获取视频列表
  140 + let trailer = this.list;
  141 + trailer.forEach((item, index) => {
  142 + if (item.videoUrl != null && item.videoUrl != '') {
  143 + let temp = 'video' + item.id;
  144 + if (temp != currentId) {
  145 + //暂停不是当前的视频
  146 + uni.createVideoContext(temp, this).pause();
  147 + }
  148 + }
  149 + });
  150 + },
  151 + openOrg() {
  152 + useNavigateTo('/pages/organization/organization')
  153 + }
  154 + }
  155 + };
  156 +</script>
  157 +
  158 +<style lang="scss" scoped>
  159 + @import '../../static/camera.scss';
173 160 </style>
\ No newline at end of file
... ...
pages/index/components/configuration/configuration-detail.vue renamed from pages/index/configuration/configuration-detail.vue
1 1 <template>
2   - <view class="content">
  2 + <view class="configuation-detail-page">
3 3 <!-- 公共组件-每个页面必须引入 -->
4 4 <public-module></public-module>
5   - <web-view :src="showConfiguration" bindload="bindload" binderror="binderror"></web-view>
  5 + <web-view :src="showConfiguration"></web-view>
6 6 </view>
7 7 </template>
8 8
... ... @@ -38,14 +38,6 @@
38 38 uni.removeStorageSync('config');
39 39 },
40 40 methods: {
41   - // 网页加载成功时候触发此事件
42   - bindload(res) {
43   - console.log(res, res.detail);
44   - },
45   - // 网页加载失败的时候触发此事件
46   - binderror(err) {
47   - console.log(err, err.detail);
48   - },
49 41 async requestUrl(e) {
50 42 const httpData = {
51 43 configurationId: e,
... ... @@ -59,7 +51,6 @@
59 51 });
60 52 const pathUrl = uni.getStorageSync('config');
61 53 const userInfo = uni.getStorageSync('userInfo')
62   - console.log(this.params)
63 54 this.showConfiguration = this.params
64 55 }
65 56 }
... ... @@ -67,8 +58,5 @@
67 58 </script>
68 59
69 60 <style lang="scss" scoped>
70   - .content {
71   - background: #f8f9fa;
72   - min-height: 100vh;
73   - }
74   -</style>
  61 + @import '../../static/configuration.scss';
  62 +</style>
\ No newline at end of file
... ...
pages/index/components/configuration/configuration.vue renamed from pages/index/configuration/configuration.vue
1 1 <template>
2   - <view class="status-page">
3   - <view style="margin-left:15rpx;background-color: #f8f9fa;position:fixed;top:0rpx;z-index: 99999;">
4   - <view style="height:35rpx;background-color: #f8f9fa;"></view>
5   - <view class="u-flex search-top">
  2 + <view class="configuation-page">
  3 + <view class="configuation-header">
  4 + <view class="header-gap"></view>
  5 + <view class="search-top">
6 6 <view class="search-main">
7 7 <u--input @change="inputChanged" prefixIcon="search" placeholder="请输入组态名称" border="surround"
8 8 shape="circle"></u--input>
... ... @@ -41,7 +41,7 @@
41 41 mixins: [MescrollMixin], // 使用mixin (在main.js注册全局组件)
42 42 data() {
43 43 return {
44   - defaultConfigImage: '../../../static/test.png',
  44 + defaultConfigImage: '../../../../static/test.png',
45 45 page: {
46 46 num: 0,
47 47 size: 10
... ... @@ -76,7 +76,7 @@
76 76 openConfigDetail(e) {
77 77 const href = createScadaPageLink(e)
78 78 uni.navigateTo({
79   - url: 'configurationDetail?configurationHref=' + href
  79 + url: 'configuration-detail?configurationHref=' + href
80 80 });
81 81 },
82 82 /*下拉刷新的回调 */
... ... @@ -120,5 +120,5 @@
120 120 </script>
121 121
122 122 <style lang="scss" scoped>
123   - @import '../static/configuration.scss';
  123 + @import '../../static/configuration.scss';
124 124 </style>
\ No newline at end of file
... ...
pages/index/components/configuration/help.js renamed from pages/index/configuration/help.js
1   -import config from '../../../config/baseUrl.js'
2   -import {
3   - atob,
4   - btoa
5   -} from './weapp.atob.js'
6   -const getRandomString = () => Number(Math.random().toString().substring(2)).toString(36);
7   -
8   -export const ScadaModeEnum = {
9   - PRIVATE_VIEW: 'PRIVATE_VIEW',
10   - PUBLIC_VIEW: 'PUBLIC_VIEW',
11   -}
12   -
13   -export const encode = (record) => {
14   - let hash = JSON.stringify(record);
15   - const mixinString = getRandomString()
16   - .slice(0, 10)
17   - .padEnd(10, getRandomString())
18   - .split('')
19   - .map((item) => (Math.random() > 0.5 ? item.toUpperCase() : item))
20   - .join('');
21   - hash = btoa(hash);
22   - hash = hash.substring(0, 6) + mixinString + hash.substring(6);
23   - hash = btoa(hash);
24   - return hash;
25   -};
26   -
27   -
28   -export const createScadaPageLink = (
29   - record,
30   - mode = ScadaModeEnum.PRIVATE_VIEW,
31   - open = false
32   -) => {
33   - const userInfo = uni.getStorageSync('userInfo')
34   - const params = {
35   - configurationId: record?.id,
36   - organizationId: record?.organizationId,
37   - mode: record?.viewType === ScadaModeEnum.PRIVATE_VIEW ? 'lightbox' : 'share',
  1 +import config from '../../../../config/baseUrl.js'
  2 +import {
  3 + atob,
  4 + btoa
  5 +} from './weapp.atob.js'
  6 +const getRandomString = () => Number(Math.random().toString().substring(2)).toString(36);
  7 +
  8 +export const ScadaModeEnum = {
  9 + PRIVATE_VIEW: 'PRIVATE_VIEW',
  10 + PUBLIC_VIEW: 'PUBLIC_VIEW',
  11 +}
  12 +
  13 +export const encode = (record) => {
  14 + let hash = JSON.stringify(record);
  15 + const mixinString = getRandomString()
  16 + .slice(0, 10)
  17 + .padEnd(10, getRandomString())
  18 + .split('')
  19 + .map((item) => (Math.random() > 0.5 ? item.toUpperCase() : item))
  20 + .join('');
  21 + hash = btoa(hash);
  22 + hash = hash.substring(0, 6) + mixinString + hash.substring(6);
  23 + hash = btoa(hash);
  24 + return hash;
  25 +};
  26 +
  27 +
  28 +export const createScadaPageLink = (
  29 + record,
  30 + mode = ScadaModeEnum.PRIVATE_VIEW,
  31 + open = false
  32 +) => {
  33 + const userInfo = uni.getStorageSync('userInfo')
  34 + const params = {
  35 + configurationId: record?.id,
  36 + organizationId: record?.organizationId,
  37 + mode: record?.viewType === ScadaModeEnum.PRIVATE_VIEW ? 'lightbox' : 'share',
38 38 platform: record?.platform,
39   - userId: userInfo.userId
40   - };
41   -
42   - if (record?.viewType === ScadaModeEnum.PUBLIC_VIEW) {
43   - params.publicId = record.publicId;
44   - }
45   -
46   - const hash = encode(params);
47   -
48   - const href = `${config.baseDrawioUrl}#${hash}`
49   -
50   - return href
  39 + userId: userInfo.userId
  40 + };
  41 +
  42 + if (record?.viewType === ScadaModeEnum.PUBLIC_VIEW) {
  43 + params.publicId = record.publicId;
  44 + }
  45 +
  46 + const hash = encode(params);
  47 +
  48 + const href = `${config.baseDrawioUrl}#${hash}`
  49 +
  50 + return href
51 51 };
\ No newline at end of file
... ...
pages/index/components/configuration/weapp.atob.js renamed from pages/index/configuration/weapp.atob.js
1   -var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
2   -var b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
3   -export const btoa = function(string) {
4   - string = String(string);
5   - var bitmap, a, b, c, result = "",
6   - i = 0,
7   - rest = string.length % 3;
8   - for (; i < string.length;) {
9   - if ((a = string.charCodeAt(i++)) > 255 ||
10   - (b = string.charCodeAt(i++)) > 255 ||
11   - (c = string.charCodeAt(i++)) > 255)
12   - throw new TypeError(
13   - "Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range."
14   - );
15   - bitmap = (a << 16) | (b << 8) | c;
16   - result += b64.charAt(bitmap >> 18 & 63) + b64.charAt(bitmap >> 12 & 63) +
17   - b64.charAt(bitmap >> 6 & 63) + b64.charAt(bitmap & 63);
18   - }
19   - return rest ? result.slice(0, rest - 3) + "===".substring(rest) : result;
20   -};
21   -
22   -export const atob = function(string) {
23   - string = String(string).replace(/[\t\n\f\r ]+/g, "");
24   - if (!b64re.test(string))
25   - throw new TypeError(
26   - "Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.");
27   - string += "==".slice(2 - (string.length & 3));
28   - var bitmap, result = "",
29   - r1, r2, i = 0;
30   - for (; i < string.length;) {
31   - bitmap = b64.indexOf(string.charAt(i++)) << 18 | b64.indexOf(string.charAt(i++)) << 12 |
32   - (r1 = b64.indexOf(string.charAt(i++))) << 6 | (r2 = b64.indexOf(string.charAt(i++)));
33   - result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255) :
34   - r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255) :
35   - String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255);
36   - }
37   - return result;
38   -};
39   -
40   -function b64DecodeUnicode(str) {
41   - return decodeURIComponent(exports.weAtob(str).replace(/(.)/g, function(p) {
42   - var code = p.charCodeAt(0).toString(16).toUpperCase();
43   - if (code.length < 2) {
44   - code = "0" + code;
45   - }
46   - return "%" + code;
47   - }));
48   -}
49   -
50   -function base64_url_decode(str) {
51   - var output = str.replace(/-/g, "+").replace(/_/g, "/");
52   - switch (output.length % 4) {
53   - case 0:
54   - break;
55   - case 2:
56   - output += "==";
57   - break;
58   - case 3:
59   - output += "=";
60   - break;
61   - default:
62   - throw "Illegal base64url string!";
63   - }
64   - try {
65   - return b64DecodeUnicode(output);
66   - } catch (err) {
67   - return exports.weAtob(output);
68   - }
69   -}
70   -
71   -function weappJwtDecode(token, options) {
72   - if (typeof token !== "string") {
73   - throw ("Invalid token specified");
74   - }
75   - options = options || {};
76   - var pos = options.header === true ? 0 : 1;
77   - try {
78   - return JSON.parse(base64_url_decode(token.split(".")[pos]));
79   - } catch (e) {
80   - throw ("Invalid token specified: " + e.message);
81   - }
  1 +var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  2 +var b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
  3 +export const btoa = function(string) {
  4 + string = String(string);
  5 + var bitmap, a, b, c, result = "",
  6 + i = 0,
  7 + rest = string.length % 3;
  8 + for (; i < string.length;) {
  9 + if ((a = string.charCodeAt(i++)) > 255 ||
  10 + (b = string.charCodeAt(i++)) > 255 ||
  11 + (c = string.charCodeAt(i++)) > 255)
  12 + throw new TypeError(
  13 + "Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range."
  14 + );
  15 + bitmap = (a << 16) | (b << 8) | c;
  16 + result += b64.charAt(bitmap >> 18 & 63) + b64.charAt(bitmap >> 12 & 63) +
  17 + b64.charAt(bitmap >> 6 & 63) + b64.charAt(bitmap & 63);
  18 + }
  19 + return rest ? result.slice(0, rest - 3) + "===".substring(rest) : result;
  20 +};
  21 +
  22 +export const atob = function(string) {
  23 + string = String(string).replace(/[\t\n\f\r ]+/g, "");
  24 + if (!b64re.test(string))
  25 + throw new TypeError(
  26 + "Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.");
  27 + string += "==".slice(2 - (string.length & 3));
  28 + var bitmap, result = "",
  29 + r1, r2, i = 0;
  30 + for (; i < string.length;) {
  31 + bitmap = b64.indexOf(string.charAt(i++)) << 18 | b64.indexOf(string.charAt(i++)) << 12 |
  32 + (r1 = b64.indexOf(string.charAt(i++))) << 6 | (r2 = b64.indexOf(string.charAt(i++)));
  33 + result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255) :
  34 + r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255) :
  35 + String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255);
  36 + }
  37 + return result;
  38 +};
  39 +
  40 +function b64DecodeUnicode(str) {
  41 + return decodeURIComponent(exports.weAtob(str).replace(/(.)/g, function(p) {
  42 + var code = p.charCodeAt(0).toString(16).toUpperCase();
  43 + if (code.length < 2) {
  44 + code = "0" + code;
  45 + }
  46 + return "%" + code;
  47 + }));
  48 +}
  49 +
  50 +function base64_url_decode(str) {
  51 + var output = str.replace(/-/g, "+").replace(/_/g, "/");
  52 + switch (output.length % 4) {
  53 + case 0:
  54 + break;
  55 + case 2:
  56 + output += "==";
  57 + break;
  58 + case 3:
  59 + output += "=";
  60 + break;
  61 + default:
  62 + throw "Illegal base64url string!";
  63 + }
  64 + try {
  65 + return b64DecodeUnicode(output);
  66 + } catch (err) {
  67 + return exports.weAtob(output);
  68 + }
  69 +}
  70 +
  71 +function weappJwtDecode(token, options) {
  72 + if (typeof token !== "string") {
  73 + throw ("Invalid token specified");
  74 + }
  75 + options = options || {};
  76 + var pos = options.header === true ? 0 : 1;
  77 + try {
  78 + return JSON.parse(base64_url_decode(token.split(".")[pos]));
  79 + } catch (e) {
  80 + throw ("Invalid token specified: " + e.message);
  81 + }
82 82 }
\ No newline at end of file
... ...
... ... @@ -12,6 +12,7 @@ const basicGridList = [{
12 12
13 13 const basicStatistics = [{
14 14 text: '设备统计',
  15 + key: 'device',
15 16 icon: '/static/device-total.png',
16 17 leftParam: 'ONLINE',
17 18 centerParam: 'OFFLINE',
... ... @@ -19,7 +20,7 @@ const basicStatistics = [{
19 20 value: {
20 21 leftValue: 0,
21 22 centerValue: 0,
22   - rightrValue: 0
  23 + rightValue: 0
23 24 },
24 25 label: {
25 26 leftText: "在线",
... ... @@ -29,6 +30,7 @@ const basicStatistics = [{
29 30 },
30 31 {
31 32 text: '告警统计',
  33 + key: 'alarm',
32 34 icon: '/static/alert.png',
33 35 leftParam: ['ACTIVE_ACK'],
34 36 centerParam: 'CLEARED_ACK',
... ... @@ -36,7 +38,7 @@ const basicStatistics = [{
36 38 value: {
37 39 leftValue: 0,
38 40 centerValue: 0,
39   - rightrValue: 0
  41 + rightValue: 0
40 42 },
41 43 label: {
42 44 leftText: "未处理",
... ...
... ... @@ -4,7 +4,7 @@
4 4 <public-module></public-module>
5 5 <view>
6 6 <!-- 基础统计 -->
7   - <view class="basic-sty">
  7 + <view class="basic-statistics">
8 8 <view class="basic-text"><text class="text text-bold">基础统计</text></view>
9 9 <view class="basic">
10 10 <view class="basic-item" v-for="(item,index) in basicStatistics" :key="index">
... ... @@ -29,7 +29,7 @@
29 29 </view>
30 30 <view @click="navigatorPage(item,item.rightParam)" class="u-flex sigle-child">
31 31 <view class="sigle-text">
32   - <text class="home-text-total">{{item.value.rightrValue}}</text>
  32 + <text class="home-text-total">{{item.value.rightValue}}</text>
33 33 </view>
34 34 <view class="sigle-value"><text
35 35 class="home-text-total-bottom">{{item.label.rightText}}</text></view>
... ... @@ -96,33 +96,40 @@
96 96 setTimeout(function() {
97 97 uni.stopPullDownRefresh();
98 98 uni.$u.toast('下拉刷新成功...');
99   - }, 800);
  99 + }, 200);
100 100 },
101 101 methods: {
102 102 ...mapActions(['updateBadgeTotal']),
103 103 async getDeviceTotalData() {
104 104 const res = await api.homeApi.getHomeStatisticsApi()
105 105 if (res) {
106   - this.basicStatistics[0].value.leftValue = res.totalDevice.onLine
107   - this.basicStatistics[0].value.centerValue = res.totalDevice.offLine
108   - this.basicStatistics[0].value.rightrValue = res.totalDevice.inActive
109   - this.basicStatistics[1].value.leftValue = res.totalAlarm.activedAlarm
110   - this.basicStatistics[1].value.centerValue = res.totalAlarm.clearedAck
111   - this.basicStatistics[1].value.rightrValue = res.totalAlarm.clearedUnack
  106 + const { onLine,offLine,inActive } = res.totalDevice
  107 + const { activedAlarm,clearedAck,clearedUnack } = res.totalAlarm
  108 + this.basicStatistics.map(item=>{
  109 + const { key, value } = item
  110 + if(key === 'device'){
  111 + value.leftValue = onLine
  112 + value.centerValue =offLine
  113 + value.rightValue = inActive
  114 + }else{
  115 + value.leftValue = activedAlarm
  116 + value.centerValue =clearedAck
  117 + value.rightValue = clearedUnack
  118 + }
  119 + })
112 120 //异步实时更新告警徽标数
113 121 this.updateBadgeTotal(res.totalAlarm?.activedAlarm);
114 122 }
115 123 },
116 124 openCamera() {
117   - useNavigateTo('camera/camera')
  125 + useNavigateTo('components/camera/camera')
118 126 },
119 127 openConfiguration() {
120   - useNavigateTo('configuration/configuration')
  128 + useNavigateTo('components/configuration/configuration')
121 129 },
122 130 handleEvent(event) {
123   - if (event === 'openCamera') {
124   - this.openCamera()
125   - } else {
  131 + if (event === 'openCamera') this.openCamera()
  132 + else {
126 133 this.openConfiguration()
127 134 }
128 135 },
... ... @@ -130,9 +137,8 @@
130 137 const {
131 138 text
132 139 } = item
133   - if (text === '设备统计') {
134   - this.navigatorDeviceStatus(type)
135   - } else {
  140 + if (text === '设备统计') this.navigatorDeviceStatus(type)
  141 + else {
136 142 this.navigatorAlarmStatus(type)
137 143 }
138 144 },
... ...
1 1 <template>
2   - <view class="container">
3   - <view class="container-box">
4   - <image v-if="mpOwnConfig.logo" :src="mpOwnConfig.logo"></image>
  2 + <view class="splash-container">
  3 + <view class="splash-container-box">
  4 + <image v-if="initConfig.logo" :src="initConfig.logo"></image>
5 5 <image v-else :src="staticLogo"></image>
6 6 <text class="splash-text-muted">连接世界 创造价值</text>
7 7 </view>
... ... @@ -21,7 +21,7 @@
21 21 data() {
22 22 return {
23 23 staticLogo: '/static/logo.png',
24   - mpOwnConfig: {}
  24 + initConfig: {}
25 25 };
26 26 },
27 27 onLoad() {
... ... @@ -47,7 +47,7 @@
47 47 methods: {
48 48 async getPlateForm() {
49 49 const res = await api.loginApi.getPlateCustomApi()
50   - this.mpOwnConfig = {
  50 + this.initConfig = {
51 51 bg: res.background,
52 52 logo: res.logo ? res.logo : this.staticLogo,
53 53 name: res.name
... ... @@ -57,22 +57,7 @@
57 57 };
58 58 </script>
59 59
60   -<style lang="scss">
61   - .container {
62   - width: 100%;
63   - height: 100%;
64   - margin-top: 300rpx;
65 60
66   - .container-box {
67   - display: flex;
68   - align-items: center;
69   - justify-content: space-between;
70   - flex-direction: column;
71   -
72   - image {
73   - width: 100rpx;
74   - height: 100rpx;
75   - }
76   - }
77   - }
  61 +<style lang="scss" scoped>
  62 + @import './static/splash.scss';
78 63 </style>
\ No newline at end of file
... ...
... ... @@ -55,3 +55,8 @@
55 55 }
56 56 }
57 57 }
  58 +
  59 +.configuation-detail-page {
  60 + background: #f8f9fa;
  61 + min-height: 100vh;
  62 + }
\ No newline at end of file
... ...
... ... @@ -56,7 +56,7 @@
56 56 }
57 57 }
58 58 }
59   -.basic-sty {
  59 +.basic-statistics {
60 60 padding: 0 10rpx;
61 61 .basic-text {
62 62 .text {
... ...
  1 +.splash-container {
  2 + width: 100%;
  3 + height: 100%;
  4 + margin-top: 300rpx;
  5 +
  6 + .splash-container-box {
  7 + display: flex;
  8 + align-items: center;
  9 + justify-content: space-between;
  10 + flex-direction: column;
  11 +
  12 + image {
  13 + width: 100rpx;
  14 + height: 100rpx;
  15 + }
  16 + }
  17 + }
\ No newline at end of file
... ...
... ... @@ -17,6 +17,7 @@
17 17
18 18 <script>
19 19 import { transOrgFunc } from '@/config/common.js';
  20 +import api from '@/api/index.js'
20 21
21 22 export default {
22 23 data() {
... ... @@ -33,16 +34,12 @@ export default {
33 34 this.loadData();
34 35 },
35 36 methods: {
36   - loadData() {
37   - uni.$u.http
38   - .get('/yt/organization/me/list')
39   - .then(res => {
40   - if (res) {
41   - const list = transOrgFunc(res);
42   - this.tree = list;
43   - }
44   - })
45   - .catch(e => {});
  37 + async loadData() {
  38 + const res = await api.loginApi.getMeOrgListApi()
  39 + if (res) {
  40 + const list = transOrgFunc(res);
  41 + this.tree = list;
  42 + }
46 43 },
47 44 confirm(val) {
48 45 this.id = val[0].id;
... ...
  1 +<template>
  2 + <view>
  3 + <u-popup bgColor="transparent" :overlay="true" :show="show" mode="bottom">
  4 + <view class="u-flex logout-main">
  5 + <view class="main"><text style="color: #999999">您确定要退出当前账号吗?</text></view>
  6 + <view @click="$emit('logoutBtn')" class="main"><text style="color: #f95e5a">退出登录</text></view>
  7 + <view class="cancel-text"><text @click="$emit('closeLogoutPopup')" style="color: #3478f7">取消</text>
  8 + </view>
  9 + </view>
  10 + </u-popup>
  11 + </view>
  12 +</template>
  13 +
  14 +<script>
  15 + export default {
  16 + props: {
  17 + show: {
  18 + type: Boolean,
  19 + default: false
  20 + }
  21 + },
  22 + }
  23 +</script>
  24 +
  25 +<style lang="scss" scoped>
  26 + @import '../static/personal.scss';
  27 +</style>
\ No newline at end of file
... ...
  1 +const systemList = [{
  2 + url: '/sysnotify-subpackage/sys-notify/system-notify',
  3 + text: '系统通知',
  4 + leftIcon: '/static/sys-not.png',
  5 + rightIcon: '/static/arrow-right.png'
  6 + },
  7 + {
  8 + url: '/feedback-subpackage/feedback/feedback',
  9 + text: '意见反馈',
  10 + leftIcon: '/static/find-sugg.png',
  11 + rightIcon: '/static/arrow-right.png'
  12 + }
  13 +]
  14 +export {
  15 + systemList
  16 +}
\ No newline at end of file
... ...
1 1 <template>
2   - <view class="personal">
  2 + <view class="personal-page">
3 3 <!-- 公共组件-每个页面必须引入 -->
4 4 <public-module></public-module>
5   - <view class="head-box">
  5 + <view class="header-box">
6 6 <view class="u-flex u-p-l-30 u-p-r-20 u-p-t-75 u-p-b-30">
7 7 <block v-if="userInfo.isToken || userInfo.isThirdLogin">
8 8 <view @click.top="navigatorPersonal" class="u-m-r-20">
... ... @@ -38,7 +38,7 @@
38 38 </view>
39 39 <view class="u-flex my-nav">
40 40 <view class="nav-main">
41   - <view v-for="(item,index) in systemList" @click="onTokenJump(item.url)" class="u-flex nav-link">
  41 + <view v-for="(item,index) in systemList" :key="index" @click="onTokenJump(item.url)" class="u-flex nav-link">
42 42 <view class="nav-image">
43 43 <image class="image" :src="item.leftIcon"></image>
44 44 </view>
... ... @@ -53,21 +53,9 @@
53 53 </view>
54 54 </view>
55 55 <!-- 绑定账号 -->
56   - <view>
57   - <bind-account-modal ref="bindAccountRef" :show="showBindAccount"
58   - @cancelAccountModal="handleCancelAccountModal" />
59   - </view>
  56 + <bind-account-modal ref="bindAccountRef" :show="showBindAccount" @cancelAccountModal="handleCancelAccountModal" />
60 57 <!-- 退出登录 -->
61   - <view>
62   - <u-popup bgColor="transparent" :overlay="true" :show="showLogout" mode="bottom">
63   - <view class="u-flex logout-main">
64   - <view class="main"><text style="color: #999999">您确定要退出当前账号?</text></view>
65   - <view @click="logoutBtn" class="main"><text style="color: #f95e5a">退出登录</text></view>
66   - <view class="cancel-text"><text @click="closeLogoutPopup" style="color: #3478f7">取消</text>
67   - </view>
68   - </view>
69   - </u-popup>
70   - </view>
  58 + <logout-account-modal ref="logoutAccountRef" :show="showLogout" @logoutBtn="logoutBtn" @closeLogoutPopup="closeLogoutPopup"/>
71 59 <f-tabbar></f-tabbar>
72 60 </view>
73 61 </template>
... ... @@ -76,40 +64,24 @@
76 64 import fTabbar from '@/components/module/f-tabbar/f-tabbar';
77 65 import fNavbar from '@/components/module/f-navbar/f-navbar';
78 66 import bindAccountModal from './components/bind-account-modal.vue'
79   - import {
80   - mapState,
81   - mapMutations
82   - } from 'vuex';
83   - import {
84   - useNavigateTo,
85   - useReLaunch,
86   - useShowModal
87   - } from '@/plugins/utils.js'
  67 + import logoutAccountModal from './components/logout-account-modal.vue'
  68 + import { mapState,mapMutations } from 'vuex';
  69 + import { useNavigateTo,useReLaunch,useShowModal } from '@/plugins/utils.js'
  70 + import { systemList } from './config/data.js'
88 71
89 72 export default {
90 73 components: {
91 74 fTabbar,
92 75 fNavbar,
93   - bindAccountModal
  76 + bindAccountModal,
  77 + logoutAccountModal,
94 78 },
95 79 data() {
96 80 return {
97 81 showBindAccount: false,
98 82 showLogout: false,
99 83 thirdObj: {},
100   - systemList: [{
101   - url: '/sysnotify-subpackage/sys-notify/system-notify',
102   - text: '系统通知',
103   - leftIcon: '/static/sys-not.png',
104   - rightIcon: '/static/arrow-right.png'
105   - },
106   - {
107   - url: '/feedback-subpackage/feedback/feedback',
108   - text: '意见反馈',
109   - leftIcon: '/static/find-sugg.png',
110   - rightIcon: '/static/arrow-right.png'
111   - }
112   - ]
  84 + systemList,
113 85 };
114 86 },
115 87 onLoad(e) {
... ... @@ -132,11 +104,13 @@
132 104 },
133 105 // 跳转前判断登录
134 106 onTokenJump(url) {
  107 + if(!url) return
135 108 this.judgeLogin(() => {
136 109 useNavigateTo(url)
137 110 });
138 111 },
139 112 onJump(url) {
  113 + if(!url) return
140 114 useNavigateTo(url)
141 115 },
142 116 navigatorLogin() {
... ...
1   -.personal {
  1 +.personal-page {
2 2 background-color: #ffffff;
3 3 height: 100vh;
4 4 }
5   -.head-box {
  5 +.header-box {
6 6 background: linear-gradient(90deg, #8c9ef2 0%, #5f6ee6 100%);
7 7 border-top: 0.01px solid #f5f5f5;
8 8 height: 250rpx;
... ...
... ... @@ -68,6 +68,9 @@ button {
68 68 .mt-15{
69 69 margin-top: 15rpx;
70 70 }
  71 +.mt-20{
  72 + margin-top: 20rpx;
  73 +}
71 74 .mr-1{
72 75 margin-right: 10rpx;
73 76 }
... ... @@ -86,10 +89,21 @@ button {
86 89 .w-100{
87 90 width: 100%;
88 91 }
  92 +.w-300{
  93 + width:300rpx;
  94 +}
  95 +.w-500{
  96 + width:500rpx;
  97 +}
  98 +.h-25{
  99 + height:25rpx;
  100 +}
89 101 .h-30{
90 102 height:30rpx;
91 103 }
92   -
  104 +.h-140{
  105 + height:140rpx;
  106 +}
93 107 //通用(设备、告警、摄像头分页头部组织和设备数和设备、告警里面的详情(左边的文本)
94 108 .ml-10{
95 109 margin-left: 10rpx;
... ...
  1 +const actions = [{
  2 + url: '/sysnotify-subpackage/sys-notify/system-notify',
  3 + text: '系统通知',
  4 + leftIcon: '/static/sys-not.png',
  5 + rightIcon: '/static/arrow-right.png'
  6 + },
  7 + {
  8 + url: '/feedback-subpackage/feedback/feedback',
  9 + text: '意见反馈',
  10 + leftIcon: '/static/find-sugg.png',
  11 + rightIcon: '/static/arrow-right.png'
  12 + }
  13 +]
  14 +export {
  15 + actions
  16 +}
\ No newline at end of file
... ...
... ... @@ -5,11 +5,11 @@
5 5 <view class="notify-column">
6 6 <view class="column-list">
7 7 <view class="column-title">
8   - <view class="text-clip" style="width:500rpx">
  8 + <view class="text-clip w-500">
9 9 <text class="notify-detail-text ">{{ notifyList.title }}</text>
10 10 </view>
11 11 </view>
12   - <view style="height: 25rpx;"></view>
  12 + <view class="h-25"></view>
13 13 <u-list height="140rpx">
14 14 <u-list-item>
15 15 <u-cell :value="`${notifyList.senderDate}`" :title="`${notifyList.senderName}`">
... ... @@ -19,10 +19,9 @@
19 19 </u-list>
20 20 <view class="bottom-text">
21 21 <view class="u-flex column"></view>
22   - <view style="margin-top: 21rpx;">
  22 + <view class="mt-20">
23 23 <!-- 富文本解析 -->
24 24 <u-parse :content="notifyList.content"></u-parse>
25   - <!-- 富文本解析 -->
26 25 </view>
27 26 </view>
28 27 </view>
... ...
... ... @@ -44,6 +44,7 @@
44 44 import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js';
45 45 import api from '@/api/index.js'
46 46 import { useNavigateTo } from '@/plugins/utils.js'
  47 + import { actions } from './config/data.js'
47 48
48 49 export default {
49 50 mixins: [MescrollMixin],
... ... @@ -51,23 +52,7 @@
51 52 return {
52 53 notifyType:'',
53 54 showType: false,
54   - actions: [{
55   - name: '全部',
56   - value: ''
57   - },
58   - {
59   - name: '会议',
60   - value: 'MEETING'
61   - },
62   - {
63   - name: '公告',
64   - value: 'NOTICE'
65   - },
66   - {
67   - name: '其他',
68   - value: 'OTHER'
69   - }
70   - ],
  55 + actions,
71 56 page: {
72 57 page: 0,
73 58 pageSize: 10
... ... @@ -86,7 +71,9 @@
86 71 },
87 72 methods: {
88 73 formatType(e) {
89   - return this.actions.find((item)=>item.value===e && item.value!=='').name
  74 + const findName = this.actions.find((item)=>item.value===e && item.value!=='')
  75 + if(!findName) return
  76 + return findName.name
90 77 },
91 78 handleTypeClick() {
92 79 this.showType = true;
... ...