detail.vue 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065
  1. <template>
  2. <view class="content">
  3. <view class="header" style="margin:0;padding: 0px;">
  4. <view class="bg" style="position: fixed;top:0px;bottom:0px;left:0px;right:0px;background-image: url('https://hyscancode.oss-cn-hangzhou.aliyuncs.com/jianyaoji/images/device/bg.png');background-size: 100% 100%;padding:0 40rpx">
  5. <view style="position: absolute;right:10rpx;top:30rpx;z-index: 9999">
  6. <u-button @click="reportError" color="#EC6D2F" text="上报异常" type="error" size="mini"></u-button>
  7. </view>
  8. <view style="position: absolute;right:52rpx;top:116rpx;">
  9. <view>
  10. <u-image :showLoading="true" src="/static/images/device/zaixian.png" width="200rpx" height="200rpx" ></u-image>
  11. </view>
  12. <view style="position: absolute;color:#48C373;top:110rpx;left:70rpx">在线</view>
  13. </view>
  14. <view style="font-weight: bold;font-size: 30rpx;margin-top:20rpx">
  15. {{deviceInfo.deviceName}}
  16. </view>
  17. <view class="prop-text">
  18. <text class="text-left">所属用户:</text>
  19. <text class="text-right">{{sysDept.deptName}}</text>
  20. </view>
  21. <view class="prop-text">
  22. <text class="text-left">设备编号:</text>
  23. <text class="text-right">{{deviceInfo.serialNumber}}</text>
  24. </view>
  25. <view class="prop-text">
  26. <text class="text-left">二维码ID:</text>
  27. <text class="text-right">{{deviceInfo.qrcodeId}}</text>
  28. </view>
  29. <view class="prop-text">
  30. <text class="text-left">激活时间:</text>
  31. <text class="text-right">{{deviceInfo.activeTime}}</text>
  32. </view>
  33. <view class="prop-text">
  34. <text class="text-left">查看位置:</text>
  35. <view style="position: absolute;top:0px;left:120rpx">
  36. <u-icon name="map-fill" label="查看位置" color="#2979ff" size="20" labelSize="12"></u-icon>
  37. </view>
  38. </view>
  39. <view class="prop-card-area">
  40. <view class="prop-card">
  41. <view class="prop-card-top">{{ deviceInfo.rssi }}</view>
  42. <view class="prop-card-bottom">设备信号</view>
  43. </view>
  44. <view class="prop-card">
  45. <view class="prop-card-top">{{ timeobj.alltime }}</view>
  46. <view class="prop-card-bottom">累计时长</view>
  47. </view>
  48. <view class="prop-card">
  49. <view class="prop-card-top">{{ timeobj.avgtime }}</view>
  50. <view class="prop-card-bottom">平均时长</view>
  51. </view>
  52. </view>
  53. <view class="tab-area">
  54. <u-tabs lineWidth="80" :activeStyle="{ color: '#3E9CFC' }" :list="summary" keyName="tabName" @change="getDeviceStatus"></u-tabs>
  55. <view>
  56. <uni-row class="demo-uni-row">
  57. <uni-col :span="12">
  58. </uni-col>
  59. </uni-row>
  60. <uni-row class="demo-uni-row">
  61. <uni-col :span="12">
  62. </uni-col>
  63. </uni-row>
  64. <view class="prop-item">
  65. <view class="prop-item-left">开机</view>
  66. <view class="prop-item-right"> <u-switch inactiveColor="lightgray" activeColor="rgb(96,195,113)" v-model="power.value" :loading ="power.loading" @change="changeProp('PowerControl')"></u-switch>
  67. </view>
  68. </view>
  69. <view class="prop-item">
  70. <view class="prop-item-left">锁定</view>
  71. <view class="prop-item-right">
  72. <u-switch inactiveColor="lightgray" activeColor="rgb(96,195,113)" v-model="lock.value" :loading ="lock.loading" @change="changeProp('LockControl')"></u-switch>
  73. </view>
  74. </view>
  75. <view v-for="item in inputProp" v-if="checkCommonProp(item)">
  76. <view class="prop-item">
  77. <view class="prop-item-left">{{item.name}}</view>
  78. <view class="prop-item-right">
  79. <view v-if="item.type === 'integer'" style="width:240rpx;position: absolute;left: -260rpx;top: -10rpx;">
  80. <u-input placeholder="请输入整数" v-model="item.shadow">
  81. </u-input>
  82. </view>
  83. <view style="padding:0 10rpx;width:260rpx;position: absolute;left: -270rpx;top: -10rpx;" v-if="item.type === 'string'">
  84. <u-input placeholder="请输入字符串" v-model="item.shadow">
  85. </u-input>
  86. </view>
  87. <view style="padding:0 10rpx;width:260rpx;position: absolute;left: -270rpx;top: -10rpx;" v-if="item.type === 'array'">
  88. <u-input placeholder="请使用英文逗号分隔的字符串" v-model="item.shadow">
  89. </u-input>
  90. </view>
  91. <view style="padding:0 10rpx;position: absolute;left: -300rpx;top: -10rpx;" v-if="item.type === 'enum'">
  92. <u-cell customStyle="border:0px;" size="mini" @click="chooseItemData(item)" arrow-direction="left" v-if="item.text != null && item.text.length>0" :title="item.text">
  93. <u-icon slot="icon" size="12" name="arrow-down"></u-icon>
  94. </u-cell>
  95. <u-cell customStyle="border:0px;" size="mini" @click="chooseItemData(item)" arrow-direction="down" v-else title="请选择">
  96. <u-icon slot="icon" size="12" name="arrow-down"></u-icon>
  97. </u-cell>
  98. </view>
  99. <view class="item" style="padding-top:14rpx">
  100. <u-button v-if="deviceInfo.status==3"
  101. @tap="send(item)"
  102. text="发送"
  103. type="success"
  104. size="mini"
  105. ></u-button>
  106. <u-button v-if="deviceInfo.status!=3"
  107. @tap="send(item)"
  108. text="发送"
  109. type="info"
  110. size="mini"
  111. ></u-button>
  112. </view>
  113. </view>
  114. </view>
  115. </view>
  116. <view style="margin-top:20rpx;margin-left:20rpx">
  117. <u--text text="属性监控" style="margin-top:20px"></u--text>
  118. </view>
  119. <view class="prop-item" v-if="checkCommonProp(item)" v-for="item in deviceInfo.readOnlyList">
  120. <view class="prop-item-left">{{item.name}}</view>
  121. <view class="prop-item-right" style="top:0rpx;">
  122. <u-input v-if="checkItemValue(item)" placeholder="请输入字符串" disabled="" :value="item.shadow+' '+item.unit">
  123. </u-input>
  124. </view>
  125. </view>
  126. </view>
  127. </view>
  128. </view>
  129. <!-- <u&#45;&#45;form>-->
  130. <!-- <u-form-item style="border:0px"-->
  131. <!-- label="设备名称:"-->
  132. <!-- labelWidth="auto"-->
  133. <!-- :borderBottom="false"-->
  134. <!-- >-->
  135. <!-- <u&#45;&#45;input disabled-->
  136. <!-- placeholder="请选择分组"-->
  137. <!-- border="none"-->
  138. <!-- color="gray"-->
  139. <!-- disabledColor="white"-->
  140. <!-- v-model="deviceInfo.deviceName"-->
  141. <!-- ></u&#45;&#45;input>-->
  142. <!-- </u-form-item>-->
  143. <!-- <u-form-item style="border:0px"-->
  144. <!-- label="所属机构:"-->
  145. <!-- labelWidth="auto"-->
  146. <!-- :borderBottom="false"-->
  147. <!-- >-->
  148. <!-- <u&#45;&#45;input v-if="sysDept != null" disabled-->
  149. <!-- placeholder="请选择分组22"-->
  150. <!-- border="none"-->
  151. <!-- color="gray"-->
  152. <!-- disabledColor="white"-->
  153. <!-- :value="sysDept.deptName"-->
  154. <!-- ></u&#45;&#45;input>-->
  155. <!-- <u&#45;&#45;input v-else-if="deviceInfo.deptId == -1" disabled-->
  156. <!-- placeholder="请选择分组11"-->
  157. <!-- border="none"-->
  158. <!-- color="gray"-->
  159. <!-- disabledColor="white"-->
  160. <!-- value="已注销"-->
  161. <!-- ></u&#45;&#45;input>-->
  162. <!-- <u&#45;&#45;input v-else disabled-->
  163. <!-- placeholder="未绑定"-->
  164. <!-- border="none"-->
  165. <!-- color="gray"-->
  166. <!-- disabledColor="white"-->
  167. <!-- value="未绑定"-->
  168. <!-- ></u&#45;&#45;input>-->
  169. <!-- </u-form-item>-->
  170. <!-- <u-form-item style="border:0px"-->
  171. <!-- label="设备编号:"-->
  172. <!-- labelWidth="auto"-->
  173. <!-- :borderBottom="false"-->
  174. <!-- ref="item1"-->
  175. <!-- >-->
  176. <!-- <u&#45;&#45;input disabled-->
  177. <!-- border="none"-->
  178. <!-- color="gray"-->
  179. <!-- disabledColor="white"-->
  180. <!-- v-model="deviceInfo.serialNumber"-->
  181. <!-- ></u&#45;&#45;input>-->
  182. <!-- </u-form-item>-->
  183. <!-- <u-form-item style="border:0px"-->
  184. <!-- label="二维码ID:"-->
  185. <!-- labelWidth="auto"-->
  186. <!-- :borderBottom="false"-->
  187. <!-- ref="item1"-->
  188. <!-- >-->
  189. <!-- <u&#45;&#45;input disabled-->
  190. <!-- border="none"-->
  191. <!-- color="gray"-->
  192. <!-- disabledColor="white"-->
  193. <!-- v-model="deviceInfo.qrcodeId"-->
  194. <!-- ></u&#45;&#45;input>-->
  195. <!-- </u-form-item>-->
  196. <!-- <u-form-item style="border:0px"-->
  197. <!-- label="激活时间:"-->
  198. <!-- labelWidth="auto"-->
  199. <!-- :borderBottom="false"-->
  200. <!-- ref="item1"-->
  201. <!-- >-->
  202. <!-- <u&#45;&#45;input disabled-->
  203. <!-- border="none"-->
  204. <!-- color="gray"-->
  205. <!-- disabledColor="white"-->
  206. <!-- :value="deviceInfo.activeTime"-->
  207. <!-- ></u&#45;&#45;input>-->
  208. <!-- </u-form-item>-->
  209. <!-- <u-form-item style="border:0px"-->
  210. <!-- label="运行时长:"-->
  211. <!-- labelWidth="auto"-->
  212. <!-- :borderBottom="false"-->
  213. <!-- ref="item1"-->
  214. <!-- >-->
  215. <!-- <view style="width: 20%">-->
  216. <!-- <u-button @click="seeTime()" type="primary" size="mini" text="查看时长"></u-button>-->
  217. <!-- </view>-->
  218. <!-- </u-form-item>-->
  219. <!-- <u-form-item style="border:0px"-->
  220. <!-- label="位置信息:"-->
  221. <!-- labelWidth="auto"-->
  222. <!-- :borderBottom="false"-->
  223. <!-- ref="item1"-->
  224. <!-- >-->
  225. <!-- <view style="width: 20%">-->
  226. <!-- <u-button @click="openLocation(deviceInfo)" type="primary" size="mini" text="查看位置"></u-button>-->
  227. <!-- </view>-->
  228. <!-- </u-form-item>-->
  229. <!-- <u-form-item style="border:0px"-->
  230. <!-- label="设备信号:"-->
  231. <!-- labelWidth="auto"-->
  232. <!-- :borderBottom="false"-->
  233. <!-- >-->
  234. <!-- <u&#45;&#45;input disabled-->
  235. <!-- border="none"-->
  236. <!-- color="gray"-->
  237. <!-- disabledColor="white"-->
  238. <!-- :value="deviceInfo.rssi"-->
  239. <!-- ></u&#45;&#45;input>-->
  240. <!-- </u-form-item>-->
  241. <!-- <u-form-item v-if="deviceInfo.networkAddress != null" style="border:0px"-->
  242. <!-- label="设备网络:"-->
  243. <!-- labelWidth="auto"-->
  244. <!-- :borderBottom="false"-->
  245. <!-- ref="item1"-->
  246. <!-- >-->
  247. <!-- <u&#45;&#45;input disabled-->
  248. <!-- border="none"-->
  249. <!-- color="gray"-->
  250. <!-- disabledColor="white"-->
  251. <!-- :value="deviceInfo.networkAddress+'('+deviceInfo.networkIp+')'"-->
  252. <!-- ></u&#45;&#45;input>-->
  253. <!-- </u-form-item>-->
  254. <!-- <u-form-item style="border:0px"-->
  255. <!-- label="设备状态:"-->
  256. <!-- labelWidth="auto"-->
  257. <!-- :borderBottom="false"-->
  258. <!-- >-->
  259. <!-- <view style="width:90rpx">-->
  260. <!-- <u-tag v-if="deviceInfo.status === 4" text="离线" size="mini" type="info"></u-tag>-->
  261. <!-- <u-tag v-if="deviceInfo.status === 3" text="在线" size="mini" type="success"></u-tag>-->
  262. <!-- <u-tag v-if="deviceInfo.status === 2" text="禁用" size="mini" type="error"></u-tag>-->
  263. <!-- <u-tag v-if="deviceInfo.status === 1" text="未激活" size="mini" type="error"></u-tag>-->
  264. <!-- </view>-->
  265. <!-- </u-form-item>-->
  266. <!-- </u&#45;&#45;form>-->
  267. <!-- </view>-->
  268. <!-- <view class="text-area">-->
  269. <!-- <u-tabs :list="summary" keyName="tabName" @change="getDeviceStatus"></u-tabs>-->
  270. <!-- <view class="prop-container" style="background: white;padding:10px ">-->
  271. <!-- <u-form>-->
  272. <!-- <u-form-item style="border:0px;position: relative"-->
  273. <!-- label=" "-->
  274. <!-- labelWidth="auto"-->
  275. <!-- :borderBottom="false"-->
  276. <!-- >-->
  277. <!-- <uni-row class="demo-uni-row">-->
  278. <!-- <uni-col :span="12">-->
  279. <!-- 开机: <u-switch v-model="power.value" :loading ="power.loading" @change="changeProp('PowerControl')"></u-switch>-->
  280. <!-- </uni-col>-->
  281. <!-- <uni-col :span="12">-->
  282. <!-- 锁定: <u-switch v-model="lock.value" :loading ="lock.loading" @change="changeProp('LockControl')"></u-switch>-->
  283. <!-- </uni-col>-->
  284. <!-- </uni-row>-->
  285. <!-- </u-form-item>-->
  286. <!-- <u-line></u-line>-->
  287. <!-- <view>-->
  288. <!-- <uni-row class="demo-uni-row" v-if="checkCommonProp(item)" v-for="item in deviceInfo.readOnlyList">-->
  289. <!-- <uni-col :span="10">-->
  290. <!-- <view class="item">{{item.name}}</view>-->
  291. <!-- </uni-col>-->
  292. <!-- <uni-col :span="10">-->
  293. <!-- <view style="padding:0 10rpx">-->
  294. <!-- <u-input placeholder="请输入字符串" disabled="" :value="item.shadow+' '+item.unit">-->
  295. <!-- </u-input>-->
  296. <!-- </view>-->
  297. <!-- </uni-col>-->
  298. <!-- </uni-row>-->
  299. <!-- </view>-->
  300. <!-- </u-form>-->
  301. <!-- </view>-->
  302. <u-picker @cancel="show=null" :show="show!=null" :columns="columns" @confirm="confirmItemData" keyName="text"></u-picker>
  303. <u-modal @cancel="cancel" :show="showErrDlg" title="异常上报" :showCancelButton="true" @confirm="doReportError" >
  304. <view class="slot-content">
  305. <view style="margin:10px">
  306. <textarea auto-height ="true" v-model="errorMsg" placeholder="请输入异常内容" ></textarea>
  307. </view>
  308. </view>
  309. </u-modal>
  310. <!-- <u-modal :show="showTimeDlg" title="查看时长" @confirm="closeTime" >-->
  311. <!-- <view class="slot-content">-->
  312. <!-- <view v-if="timeobj!=null && deviceInfo.status == 3">本次运行时长:{{ timeobj.runtime }}</view>-->
  313. <!-- <view v-if="timeobj!=null ">累计时长:{{ timeobj.alltime }}</view>-->
  314. <!-- <view v-if="timeobj!=null ">平均每天运行时长:{{ timeobj.avgtime }}</view>-->
  315. <!-- </view>-->
  316. <!-- </u-modal>-->
  317. </view>
  318. </view>
  319. </template>
  320. <script>
  321. import { getDetail,getDeviceStatus,cacheJsonThingsModel,reportError ,getDeviceRunTime} from '@/api/device/device.js'
  322. import UButton from "../../uni_modules/uview-ui/components/u-button/u-button";
  323. import UForm from "../../uni_modules/uview-ui/components/u--form/u--form";
  324. import UInput from "../../uni_modules/uview-ui/components/u--input/u--input";
  325. import UImage from "../../uni_modules/uview-ui/components/u--image/u--image";
  326. export default {
  327. components: {UImage, UInput, UForm, UButton},
  328. data(){
  329. return {
  330. modelKey:['PowerControl','LockControl'],
  331. power:{
  332. loading:true,
  333. value:0,
  334. },
  335. lock:{
  336. loading:true,
  337. value:0,
  338. },
  339. showTimeDlg:false,
  340. showErrDlg:null,
  341. errorMsg:"asdasdasdasd",
  342. show:null,
  343. value:"",
  344. deviceInfo:{},
  345. id:0,
  346. summary:[],
  347. activeName:0,
  348. childId:"",
  349. oneToMul:false,
  350. inputProp:[],
  351. watchProp:[],
  352. columns:[],
  353. location:{},
  354. sysDept:null,
  355. timeobj:{alltime:0,avgtime:0},
  356. publishMsg:false,
  357. checkTimer:null,
  358. }
  359. },
  360. onLoad: function(opt) {
  361. this.id = opt.id;
  362. // this.id = 61;
  363. this.connectMqtt();
  364. this.getDetail();
  365. },
  366. destroyed() {
  367. // 取消订阅主题
  368. this.mqttUnSubscribe(this.deviceInfo);
  369. clearInterval(this.checkTimer);
  370. },
  371. methods:{
  372. checkItemValue(item){
  373. if(!item.shadow){
  374. item.shadow = 0;
  375. }
  376. if(!item.unit){
  377. item.unit = "";
  378. }
  379. return true;
  380. },
  381. changeProp(key){
  382. let item = null;
  383. let obj = null;
  384. if(key === "LockControl"){
  385. item = this.lock;
  386. }else if(key === "PowerControl"){
  387. item = this.power;
  388. }
  389. let value = item.value;
  390. obj = item.item;
  391. if(value){
  392. obj.value = 1;
  393. obj.shadow = 1;
  394. }else{
  395. obj.value = 0;
  396. obj.shadow = 0;
  397. }
  398. this.publishThingsModel(this.deviceInfo,obj);
  399. },
  400. checkCommonProp(item){
  401. let id =item.id;
  402. let isCommonKey = this.modelKey.some(res=>{
  403. return id === res;
  404. })
  405. return !isCommonKey;
  406. },
  407. getRunTime(){
  408. let self = this;
  409. getDeviceRunTime(this.id).then(res=>{
  410. self.timeobj = res.data;
  411. if(self.timeobj.avgtime == ""){
  412. self.timeobj.avgtime = 0;
  413. }
  414. if(self.timeobj.alltime == ""){
  415. self.timeobj.alltime = 0;
  416. }
  417. })
  418. },
  419. seeTime(){
  420. this.showTimeDlg = true;
  421. this.getRunTime();
  422. },
  423. closeTime(){
  424. this.showTimeDlg = false;
  425. },
  426. cancel(){
  427. this.showErrDlg = false;
  428. },
  429. reportError(){
  430. this.showErrDlg = true;
  431. },
  432. doReportError(){
  433. if(!this.errorMsg){
  434. this.$modal.showToast('异常信息不能为空')
  435. }else{
  436. let self = this;
  437. let errObj = {};
  438. errObj.deviceId = this.deviceInfo.deviceId;
  439. errObj.deviceName = this.deviceInfo.deviceName
  440. errObj.desc = this.errorMsg;
  441. errObj.deptId= this.deviceInfo.deptId;
  442. reportError(errObj).then(res=>{
  443. self.$modal.showToast(res.msg)
  444. self.cancel();
  445. })
  446. }
  447. },
  448. openLocation(){
  449. uni.openLocation({
  450. latitude: this.location.latitude,
  451. longitude: this.location.longitude,
  452. success: function () {
  453. console.log('success');
  454. }
  455. });
  456. },
  457. confirmItemData(e){
  458. let data = e.value[0];
  459. this.show.text = data.text;
  460. this.show.shadow=data.value;
  461. this.show = null;
  462. console.log(data);
  463. },
  464. send(item){
  465. if(this.deviceInfo.status != 3){
  466. uni.showToast({
  467. title:"设备暂未上线",
  468. icon:"error"
  469. })
  470. return;
  471. }
  472. if(!item.shadow){
  473. uni.showToast({
  474. title:"数据不能为空",
  475. icon:"error"
  476. })
  477. return;
  478. }
  479. this.publishThingsModel(this.deviceInfo,item)
  480. },
  481. /** 更新设备状态 */
  482. updateDeviceStatus(device) {
  483. },
  484. chooseItemData(data){
  485. if(this.deviceInfo.status != 3){
  486. uni.showToast({
  487. title:"设备暂未上线",
  488. icon:"error"
  489. })
  490. return;
  491. }
  492. this.columns = [data.enumList];
  493. this.show =data;
  494. },
  495. getDetail(){
  496. let self = this;
  497. getDetail(this.id).then(res=>{
  498. self.deviceInfo = res.data;
  499. self.location = {
  500. latitude: self.deviceInfo.latitude,
  501. longitude: self.deviceInfo.longitude};
  502. self.sysDept = self.deviceInfo.sysDept;
  503. self.parseSummay(res.data.summary)
  504. self.mqttSubscribe(res.data);
  505. self.getDeviceStatus();
  506. self.seeTime();
  507. });
  508. },
  509. getDeviceStatus(e){
  510. let self = this;
  511. if(!e){
  512. e = {index:0};
  513. }
  514. this.activeName = e.index;
  515. this.childId = this.summary[this.activeName].id;
  516. getDeviceStatus(this.id,this.childId).then(res=>{
  517. let data =res.data;
  518. this.deviceInfo = data;
  519. self.parseStatusData(data)
  520. });
  521. },
  522. parseEnumList(){
  523. let enumList = this.deviceInfo.enumList;
  524. for (let enumListElement of enumList) {
  525. let id = enumListElement.id;
  526. let isCommonKey = this.modelKey.some(res=>{
  527. return id === res;
  528. })
  529. if(isCommonKey){
  530. if(id.indexOf("LockControl") !=-1){
  531. let shadow = enumListElement.shadow;
  532. this.lock.item = enumListElement;
  533. if(shadow == 1){
  534. this.lock.value = true;
  535. this.lock.loading = false;
  536. }else if(shadow == 0){
  537. this.lock.value = false;
  538. this.lock.loading = false;
  539. }else{
  540. this.lock.loading = true;
  541. }
  542. }
  543. if(id.indexOf("PowerControl") !=-1){
  544. let shadow = enumListElement.shadow;
  545. this.power.item = enumListElement;
  546. if(shadow == 1){
  547. this.power.value = true;
  548. this.power.loading = false;
  549. }else if(shadow == 0){
  550. this.power.value = false;
  551. this.power.loading = false;
  552. }else{
  553. this.power.loading = true;
  554. }
  555. }
  556. }
  557. let shadow = enumListElement.shadow
  558. let valueList = enumListElement.enumList;
  559. for (let valueObj of valueList){
  560. if(valueObj.value == shadow){
  561. enumListElement.text = valueObj.text;
  562. }
  563. }
  564. }
  565. },
  566. parseStatusData(data){
  567. let arr = [];
  568. let arrayList = data.arrayList;
  569. arr = arr.concat(arrayList);
  570. let enumList = data.enumList;
  571. arr = arr.concat(enumList);
  572. let integerList = data.integerList;
  573. arr = arr.concat(integerList);
  574. let stringList = data.stringList;
  575. arr = arr.concat(stringList);
  576. this.inputProp = arr;
  577. let readOnlyList = data.readOnlyList;
  578. this.watchProp = readOnlyList;
  579. this.parseEnumList();
  580. },
  581. parseSummay(summary){
  582. let self = this;
  583. if(!summary){
  584. summary = "";
  585. }
  586. if(summary.length>0){
  587. this.summary = JSON.parse(summary);
  588. if(self.summary.length>0){
  589. this.oneToMul = true;
  590. }
  591. for (let i = 0; i < self.summary.length; i++) {
  592. self.summary[i].tabName = self.summary[i].id+"_"+self.summary[i].name
  593. }
  594. let childId = "";
  595. if(this.oneToMul){
  596. let info = self.summary[self.activeName];
  597. childId = info.id;
  598. }
  599. this.childId = childId;
  600. }else{
  601. this.summary = [{tabName:"详情查看"}]
  602. }
  603. },
  604. goDeviceDetail(id){
  605. uni.navigateTo({
  606. url: '/pages/device/detail/detail?id='+id
  607. });
  608. },
  609. async connectMqtt() {
  610. if (this.$mqttTool.client == null) {
  611. await this.$mqttTool.connect(this.vuex_token);
  612. }
  613. this.mqttCallback();
  614. this.startCheck();
  615. },
  616. /** Mqtt订阅主题 */
  617. mqttSubscribe(device) {
  618. // 订阅当前设备状态和实时监测
  619. let topicStatus = '/' + device.productId + '/' + device.serialNumber + '/status/post';
  620. let topicProperty = '/' + device.productId + '/' + device.serialNumber + '/property/post';
  621. let topicFunction = '/' + device.productId + '/' + device.serialNumber + '/function/post';
  622. let topics = [];
  623. topics.push(topicStatus);
  624. topics.push(topicProperty);
  625. topics.push(topicFunction);
  626. this.$mqttTool.subscribe(topics);
  627. },
  628. /** Mqtt取消订阅主题 */
  629. mqttUnSubscribe(device) {
  630. // 订阅当前设备状态和实时监测
  631. let topicStatus = '/' + device.productId + '/' + device.serialNumber + '/status/post';
  632. let topicProperty = '/' + device.productId + '/' + device.serialNumber + '/property/post';
  633. let topicFunction = '/' + device.productId + '/' + device.serialNumber + '/function/post';
  634. let topics = [];
  635. topics.push(topicStatus);
  636. topics.push(topicProperty);
  637. topics.push(topicFunction);
  638. console.log('取消订阅', topics);
  639. this.$mqttTool.unsubscribe(topics);
  640. },
  641. /* Mqtt回调处理 */
  642. mqttCallback() {
  643. this.$mqttTool.client.on('message', (topic, message, buffer) => {
  644. let topics = topic.split('/');
  645. let productId = topics[1];
  646. let deviceNum = topics[2];
  647. console.log('接收到内容:'+message);
  648. message = JSON.parse(message.toString());
  649. if (topics[3] == 'status') {
  650. console.log('接收到【设备状态-运行】主题:', topic);
  651. console.log('接收到【设备状态-运行】内容:', message);
  652. // 更新列表中设备的状态
  653. if (this.deviceInfo.serialNumber == deviceNum) {
  654. this.deviceInfo.status = message.status;
  655. this.deviceInfo.isShadow = message.isShadow;
  656. this.deviceInfo.rssi = message.rssi;
  657. this.updateDeviceStatus(this.deviceInfo);
  658. }
  659. }
  660. if (topics[3] == 'property' || topics[3] == 'function') {
  661. console.log('接收到【物模型】主题:', topic);
  662. console.log('接收到【物模型】内容:', message);
  663. if(this.oneToMul){
  664. let curTabId = this.summary[this.activeName].id;
  665. let msg = [];
  666. for (let i = 0; i < message.length; i++) {
  667. let curMsg = message[i];
  668. let id = curMsg.id;
  669. let ids = id.split("_");
  670. let value = curMsg.value;
  671. if(ids.length == 2){
  672. if(curTabId == ids[1]){
  673. msg.push({id:ids[0],value:value});
  674. }
  675. }
  676. }
  677. message = msg;
  678. }
  679. // 更新列表中设备的属性
  680. if (this.deviceInfo.serialNumber == deviceNum) {
  681. for (let j = 0; j < message.length; j++) {
  682. let isComplete = false;
  683. // 布尔类型
  684. for (let k = 0; k < this.deviceInfo.boolList.length && !isComplete; k++) {
  685. if (this.deviceInfo.boolList[k].id == message[j].id) {
  686. this.deviceInfo.boolList[k].shadow = message[j].value;
  687. isComplete = true;
  688. break;
  689. }
  690. }
  691. // 枚举类型
  692. for (let k = 0; k < this.deviceInfo.enumList.length && !isComplete; k++) {
  693. if (this.deviceInfo.enumList[k].id == message[j].id) {
  694. this.deviceInfo.enumList[k].shadow = message[j].value;
  695. isComplete = true;
  696. break;
  697. }
  698. }
  699. // 字符串类型
  700. for (let k = 0; k < this.deviceInfo.stringList.length && !isComplete; k++) {
  701. if (this.deviceInfo.stringList[k].id == message[j].id) {
  702. this.deviceInfo.stringList[k].shadow = message[j].value;
  703. isComplete = true;
  704. break;
  705. }
  706. }
  707. // 数组类型
  708. for (let k = 0; k < this.deviceInfo.arrayList.length && !isComplete; k++) {
  709. if (this.deviceInfo.arrayList[k].id == message[j].id) {
  710. this.deviceInfo.arrayList[k].shadow = message[j].value;
  711. isComplete = true;
  712. break;
  713. }
  714. }
  715. // 整数类型
  716. for (let k = 0; k < this.deviceInfo.integerList.length && !isComplete; k++) {
  717. if (this.deviceInfo.integerList[k].id == message[j].id) {
  718. this.deviceInfo.integerList[k].shadow = message[j].value;
  719. isComplete = true;
  720. break;
  721. }
  722. }
  723. // 小数类型
  724. for (let k = 0; k < this.deviceInfo.decimalList.length && !isComplete; k++) {
  725. if (this.deviceInfo.decimalList[k].id == message[j].id) {
  726. this.deviceInfo.decimalList[k].shadow = message[j].value;
  727. isComplete = true;
  728. break;
  729. }
  730. }
  731. // 监测数据
  732. for (let k = 0; k < this.deviceInfo.readOnlyList.length && !isComplete; k++) {
  733. if (this.deviceInfo.readOnlyList[k].id == message[j].id) {
  734. this.deviceInfo.readOnlyList[k].shadow = message[j].value;
  735. // 更新图表
  736. // for (let m = 0; m < this.monitorChart.length; m++) {
  737. // if (message[j].id == this.monitorChart[m].data.id) {
  738. // let data = [{
  739. // value: message[j].value,
  740. // name: this.monitorChart[m].data.name
  741. // }];
  742. // this.monitorChart[m].chart.setOption({
  743. // series: [{
  744. // data: data
  745. // }]
  746. // });
  747. // break;
  748. // }
  749. // }
  750. isComplete = true;
  751. break;
  752. }
  753. }
  754. }
  755. this.parseEnumList();
  756. }
  757. }
  758. });
  759. },
  760. /** 发布物模型 类型(1=属性,2=功能) */
  761. publishThingsModel(device, model) {
  762. // 获取缓存的Json物模型
  763. cacheJsonThingsModel(device.productId).then(response => {
  764. let thingsModel = JSON.parse(response.data);
  765. let type = 0;
  766. for (let i = 0; i < thingsModel.functions.length; i++) {
  767. if (model.id == thingsModel.functions[i].id) {
  768. type = 2;
  769. break;
  770. }
  771. }
  772. if (type == 0) {
  773. for (let i = 0; i < thingsModel.properties.length; i++) {
  774. if (model.id == thingsModel.properties[i].id) {
  775. type = 1;
  776. break;
  777. }
  778. }
  779. }
  780. if (type != 0) {
  781. this.mqttPublish(type, device, model);
  782. }
  783. });
  784. },
  785. notifyError(res){
  786. uni.showToast({
  787. title:res,
  788. icon:"error"
  789. })
  790. },
  791. notifySuccess(res){
  792. uni.showToast({
  793. title:res,
  794. icon:"success"
  795. })
  796. },
  797. /**
  798. * Mqtt发布消息
  799. * @type 类型(1=属性,2=功能,3=OTA升级,4=实时监测)
  800. * @device 设备
  801. * @model 物模型
  802. * */
  803. mqttPublish(type, device, model) {
  804. let topic = "";
  805. let message = ""
  806. let oneToMul = false;
  807. if(this.summary.length>0){
  808. oneToMul = true;
  809. }
  810. let modelId = model.id;
  811. if(oneToMul){
  812. let info = this.summary[this.activeName];
  813. let childId = info.id;
  814. modelId = modelId+"_"+childId;
  815. }
  816. if (type == 1) {
  817. if (device.status == 3) {
  818. // 属性,在线模式
  819. topic = "/" + device.productId + "/" + device.serialNumber + "/property-online/get";
  820. } else if (device.isShadow) {
  821. // 属性,离线模式
  822. topic = "/" + device.productId + "/" + device.serialNumber + "/property-offline/post";
  823. }
  824. message = '[{"id":"' + modelId + '","value":"' + model.shadow + '"}]';
  825. } else if (type == 2) {
  826. if (device.status == 3) {
  827. // 功能,在线模式
  828. topic = "/" + device.productId + "/" + device.serialNumber + "/function-online/get";
  829. } else if (device.isShadow) {
  830. // 功能,离线模式
  831. topic = "/" + device.productId + "/" + device.serialNumber + "/function-offline/post";
  832. }
  833. message = '[{"id":"' + modelId + '","value":"' + model.shadow + '"}]';
  834. } else if (type == 3) {
  835. // OTA升级
  836. topic = "/" + device.productId + "/" + device.serialNumber + "/ota/get";
  837. message = '{"version":' + this.firmware.version + ',"downloadUrl":"' + this.getDownloadUrl(this.firmware.filePath) + '"}';
  838. } else {
  839. return;
  840. }
  841. if (topic != "") {
  842. // 发布
  843. let self = this;
  844. this.$mqttTool.publish(topic, message, model.name).then(res => {
  845. this.notifySuccess(res);
  846. }).catch(res => {
  847. this.notifyError(res);
  848. });
  849. }
  850. },
  851. startCheck(){
  852. let self = this;
  853. this.checkTimer = setInterval(function (){
  854. self.sendHeart();
  855. },20000);
  856. },
  857. checkActive(){
  858. let self = this;
  859. setTimeout(function (){
  860. if(self.publishMsg){
  861. self.resetConn()
  862. }
  863. },3000);
  864. },
  865. sendHeart(){
  866. console.log("发送心跳")
  867. let device = this.deviceInfo;
  868. let self = this;
  869. let topic = "/property-offline/post";
  870. self.publishMsg = true;
  871. self.checkActive();
  872. this.$mqttTool.publish(topic, "ok", "heart").then(res => {
  873. self.publishMsg = false;
  874. }).catch(res => {
  875. self.publishMsg = false;
  876. });
  877. },
  878. resetConn(){
  879. console.log("检测异常,重连")
  880. this.$mqttTool.end();
  881. this.$mqttTool.client = null;
  882. this.connectMqtt();
  883. this.getDetail();
  884. }
  885. }
  886. }
  887. </script>
  888. <style>
  889. .header{
  890. width: 100%;
  891. background: white;
  892. padding:0px 20rpx;
  893. position: relative;
  894. }
  895. .content {
  896. display: flex;
  897. align-items: center;
  898. justify-content: center;
  899. }
  900. .logo {
  901. height: 200rpx;
  902. width: 200rpx;
  903. margin-top: 200rpx;
  904. margin-left: auto;
  905. margin-right: auto;
  906. margin-bottom: 50rpx;
  907. }
  908. .text-area {
  909. margin:10px;
  910. padding-bottom: 10px;
  911. justify-content: center;
  912. width: 100%;
  913. }
  914. .grid-text {
  915. font-size: 14px;
  916. color: #909399;
  917. padding: 10rpx 0 20rpx 0rpx;
  918. /* #ifndef APP-PLUS */
  919. box-sizing: border-box;
  920. /* #endif */
  921. }
  922. .title {
  923. font-size: 36rpx;
  924. color: #8f8f94;
  925. }
  926. .item{
  927. height: 80rpx;
  928. line-height: 80rpx;
  929. }
  930. .bg{
  931. position: relative;
  932. }
  933. .text-left{
  934. color: #8A92A5;
  935. }
  936. .text-right{
  937. color: #545454;
  938. }
  939. .prop-text{
  940. position: relative;
  941. margin:20rpx 0;
  942. font-size: 26rpx;
  943. }
  944. .prop-card-area{
  945. }
  946. .prop-card{
  947. width: 29%;
  948. height: 100rpx;
  949. text-align: center;
  950. display: inline-block;
  951. background: #F5FCFF;
  952. box-shadow: 0px 9rpx 8rpx 0px rgba(0,0,0,0.09);
  953. border-radius: 8rpx;
  954. margin:0px 15rpx;
  955. line-height: 48rpx;
  956. }
  957. .prop-card-top{
  958. color: #3E9CFC;
  959. }
  960. .prop-card-bottom{
  961. color: #8A92A5;
  962. }
  963. .tab-area {
  964. background: white;
  965. position: absolute;
  966. left: 0px;
  967. right: 0px;
  968. top:480rpx;
  969. bottom:-20px;
  970. min-height: 200rpx;
  971. box-shadow: 0rpx 5rpx 27rpx 0rpx rgba(195, 195, 195, 0.4);
  972. border-radius: 40rpx;
  973. overflow-y: auto;
  974. padding-bottom:80rpx;
  975. }
  976. .prop-item{
  977. justify-content:center;
  978. position: relative;
  979. border-bottom: 1px solid lightgray;
  980. height: 80rpx;
  981. margin:0 20rpx;
  982. }
  983. .prop-item-left{
  984. position: absolute;
  985. left:10rpx;
  986. top:22rpx;
  987. color: #545454;
  988. }
  989. .prop-item-right{
  990. position: absolute;
  991. right:10rpx;
  992. top:10rpx;
  993. }
  994. </style>