detail.vue 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593
  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">
  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;" v-if="deviceInfo.status == 3">
  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="position: absolute;right:52rpx;top:116rpx;" v-if="deviceInfo.status == 4">
  15. <view>
  16. <u-image :showLoading="true" src="/static/images/device/offline.png" width="200rpx" height="200rpx" ></u-image>
  17. </view>
  18. <view style="position: absolute;color:lightgray;top:110rpx;left:70rpx">离线</view>
  19. </view>
  20. <view style="font-weight: bold;font-size: 30rpx;margin-top:20rpx">
  21. {{deviceInfo.deviceName}}
  22. </view>
  23. <view class="prop-text">
  24. <text class="text-left">所属用户:</text>
  25. <text class="text-right">{{sysDept.deptName}}</text>
  26. </view>
  27. <view class="prop-text">
  28. <text class="text-left">设备编号:</text>
  29. <text class="text-right">{{deviceInfo.serialNumber}}</text>
  30. </view>
  31. <view class="prop-text">
  32. <text class="text-left">二维码ID:</text>
  33. <text class="text-right">{{deviceInfo.qrcodeId==null?"未绑定":deviceInfo.qrcodeId}}</text>
  34. </view>
  35. <view class="prop-text">
  36. <text class="text-left">激活时间:</text>
  37. <text class="text-right">{{deviceInfo.activeTime}}</text>
  38. </view>
  39. <view class="prop-text">
  40. <text class="text-left">查看位置:</text>
  41. <view style="position: absolute;top:0px;left:120rpx">
  42. <u-icon name="map-fill" label="查看位置" color="#2979ff" size="20" labelSize="12"></u-icon>
  43. </view>
  44. </view>
  45. <view class="prop-card-area">
  46. <view class="prop-card">
  47. <view class="prop-card-top">{{ deviceInfo.rssi }}</view>
  48. <view class="prop-card-bottom">设备信号</view>
  49. </view>
  50. <view class="prop-card">
  51. <view class="prop-card-top">{{ timeobj.alltime }}</view>
  52. <view class="prop-card-bottom">累计时长</view>
  53. </view>
  54. <view class="prop-card">
  55. <view class="prop-card-top">{{ timeobj.avgtime }}</view>
  56. <view class="prop-card-bottom">平均时长</view>
  57. </view>
  58. </view>
  59. <view class="tab-area">
  60. <!-- <u-tabs lineWidth="80" :activeStyle="{ color: '#3E9CFC' }" :list="summary" keyName="tabName" @change="getDeviceStatus"></u-tabs>-->
  61. <u-tabs lineWidth="80" :activeStyle="{ color: '#3E9CFC' }" :list="summary" :current="current" keyName="tabName" @change="getNewDeviceStatus"></u-tabs>
  62. <view>
  63. <uni-row class="demo-uni-row">
  64. <uni-col :span="12">
  65. </uni-col>
  66. </uni-row>
  67. <uni-row class="demo-uni-row">
  68. <uni-col :span="12">
  69. </uni-col>
  70. </uni-row>
  71. <!--
  72. <view v-if="deviceInfo.status == 3">
  73. <view class="prop-item">
  74. <view class="prop-item-left">开机</view>
  75. <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>
  76. </view>
  77. </view>
  78. <view class="prop-item">
  79. <view class="prop-item-left">锁定</view>
  80. <view class="prop-item-right">
  81. <u-switch inactiveColor="lightgray" activeColor="rgb(96,195,113)" v-model="lock.value" :loading ="lock.loading" @change="changeProp('LockControl')"></u-switch>
  82. </view>
  83. </view>
  84. </view>
  85. <view v-if="deviceInfo.status != 3">
  86. <view class="prop-item">
  87. <view class="prop-item-left">开机</view>
  88. <view class="prop-item-right"> <u-switch inactiveColor="lightgray" activeColor="rgb(96,195,113)" value="0" :loading ="power.loading" @change="changeProp('PowerControl')"></u-switch>
  89. </view>
  90. </view>
  91. <view class="prop-item">
  92. <view class="prop-item-left">锁定</view>
  93. <view class="prop-item-right">
  94. <u-switch inactiveColor="lightgray" activeColor="rgb(96,195,113)" value="0" :loading ="lock.loading" @change="changeProp('LockControl')"></u-switch>
  95. </view>
  96. </view>
  97. </view>
  98. -->
  99. <!-- <view class="demo-uni-row" v-if="deviceInfo.status != 3">-->
  100. <!-- <view span="12" style="width: 50vw; float: left;">-->
  101. <!-- <uni-card v-if="power.value > 0" extra="设备开关" thumbnail="/static/images/device/opened.png" @click="changeProp('PowerControl',0)">-->
  102. <!-- <text>已开启,点击图标关闭</text>-->
  103. <!-- &lt;!&ndash; <text>已开启</text>&ndash;&gt;-->
  104. <!-- &lt;!&ndash; <u-image src="/static/images/device/opened.png" width="200rpx" height="200rpx"></u-image>&ndash;&gt;-->
  105. <!-- </uni-card>-->
  106. <!-- <uni-card v-else extra="设备开关" thumbnail="/static/images/device/closed.png" @click="changeProp('PowerControl',1)">-->
  107. <!-- <text>已关闭,点击图标开启</text>-->
  108. <!-- &lt;!&ndash; <text>已关闭</text>&ndash;&gt;-->
  109. <!-- &lt;!&ndash; <u-image src="/static/images/device/opened.png" width="200rpx" height="200rpx"></u-image>&ndash;&gt;-->
  110. <!-- </uni-card>-->
  111. <!-- </view>-->
  112. <!-- <view span="12" style="width: 50vw; float: left;">-->
  113. <!-- <uni-card v-if="lock.value > 0" extra="设备锁定" thumbnail="/static/images/device/locked.png" @click="changeProp('LockControl',0)" >-->
  114. <!-- <text>已上锁,点击图标解锁</text>-->
  115. <!-- &lt;!&ndash; <text>已上锁</text>&ndash;&gt;-->
  116. <!-- &lt;!&ndash; <u-image src="/static/images/device/locked.png" width="200rpx" height="200rpx"></u-image>&ndash;&gt;-->
  117. <!-- </uni-card>-->
  118. <!-- <uni-card v-else extra="设备锁定" thumbnail="/static/images/device/unlocked.png" @click="changeProp('LockControl',1)" >-->
  119. <!-- <text>未上锁,点击图标上锁</text>-->
  120. <!-- &lt;!&ndash; <text>未上锁</text>&ndash;&gt;-->
  121. <!-- &lt;!&ndash; <u-image src="/static/images/device/locked.png" width="200rpx" height="200rpx"></u-image>&ndash;&gt;-->
  122. <!-- </uni-card>-->
  123. <!-- </view>-->
  124. <!-- <view style="clear: both"></view>-->
  125. <!-- </view>-->
  126. <!-- 煎药控制 -->
  127. <view class="demo-uni-row" v-if="DecoctControlStatus">
  128. <!-- 子tab -->
  129. <view style="width:70%;margin:0 auto">
  130. <u-tabs :list="subDecoctTabList" :current="subCurrent" @change="changeSub"></u-tabs>
  131. </view>
  132. <!-- 设备和锁定开关 -->
  133. <view class="demo-uni-row clearfix">
  134. <view span="12" style="width: 50vw; float: left;">
  135. <uni-card v-if="power.value > 0" extra="设备开关" thumbnail="/static/images/device/opened.png" @click="changeProp('PowerControl',0)">
  136. <text>已开启,点击图标关闭</text>
  137. <!-- <text>已开启</text>-->
  138. <!-- <u-image src="/static/images/device/opened.png" width="200rpx" height="200rpx"></u-image>-->
  139. </uni-card>
  140. <uni-card v-else extra="设备开关" thumbnail="/static/images/device/closed.png" @click="changeProp('PowerControl',1)">
  141. <text>已关闭,点击图标开启</text>
  142. <!-- <text>已关闭</text>-->
  143. <!-- <u-image src="/static/images/device/opened.png" width="200rpx" height="200rpx"></u-image>-->
  144. </uni-card>
  145. </view>
  146. <view span="12" style="width: 50vw; float: left;">
  147. <uni-card v-if="lock.value > 0" extra="设备锁定" thumbnail="/static/images/device/locked.png" @click="changeProp('LockControl',0)" >
  148. <text>已上锁,点击图标解锁</text>
  149. <!-- <text>已上锁</text>-->
  150. <!-- <u-image src="/static/images/device/locked.png" width="200rpx" height="200rpx"></u-image>-->
  151. </uni-card>
  152. <uni-card v-else extra="设备锁定" thumbnail="/static/images/device/unlocked.png" @click="changeProp('LockControl',1)" >
  153. <text>未上锁,点击图标上锁</text>
  154. <!-- <text>未上锁</text>-->
  155. <!-- <u-image src="/static/images/device/locked.png" width="200rpx" height="200rpx"></u-image>-->
  156. </uni-card>
  157. </view>
  158. <view style="clear: both"></view>
  159. </view>
  160. <!-- 头部 -->
  161. <view class="decoctControlHeader">
  162. <uni-icons custom-prefix="iconfont" type="icon-fuzhushuxian" size="30"></uni-icons>
  163. <text>煎药控制</text>
  164. </view>
  165. <!-- 腰部 -->
  166. <view>
  167. <!-- 上边部份 -->
  168. <view class="decoctControlTop">
  169. <!-- 左边 -->
  170. <view class="decoctControlTopLeft">
  171. <text>温度设置</text>
  172. <u-input placeholder="请输入"></u-input>
  173. <view class="addTemperature">
  174. <u-button class="addTemperatureBtn" @click="addTemperature"></u-button>
  175. <!-- <uni-icons custom-prefix="iconfont" type="icon-zengjia-huoyue" size="30"></uni-icons>-->
  176. </view>
  177. <view class="subTemperature">
  178. <u-button class="subTemperatureBtn" @click="subTemperature"></u-button>
  179. <!-- <uni-icons custom-prefix="iconfont" type="icon-jianshao-huoyue" size="30"></uni-icons>-->
  180. </view>
  181. </view>
  182. <!-- 右边 -->
  183. <view class="decoctControlTopRight">
  184. <text>时间设置</text>
  185. <u-input placeholder="请输入"></u-input>
  186. <view class="addTime">
  187. <u-button class="addTimeBtn"></u-button>
  188. </view>
  189. <view class="subTime">
  190. <u-button class="subTimeBtn"></u-button>
  191. </view>
  192. </view>
  193. </view>
  194. <!-- 下边部份 -->
  195. <view class="decoctControlTop">
  196. <!-- 左边 -->
  197. <view class="decoctControlTopLeft">
  198. <text>当前温度</text>
  199. <u-input placeholder="请输入"></u-input>
  200. <view class="addTemperature">
  201. <u-button class="addTemperatureBtn"></u-button>
  202. </view>
  203. <view class="subTime">
  204. <u-button class="subTimeBtn"></u-button>
  205. </view>
  206. </view>
  207. <!-- 右边 -->
  208. <view class="decoctControlTopRight">
  209. <text>高温时间</text>
  210. <u-input placeholder="请输入"></u-input>
  211. <view class="addTemperature">
  212. <u-button class="addTemperatureBtn"></u-button>
  213. </view>
  214. <view class="subTime">
  215. <u-button class="subTimeBtn"></u-button>
  216. </view>
  217. </view>
  218. </view>
  219. </view>
  220. <!-- 尾部 -->
  221. <view>
  222. <!-- 上边 -->
  223. <view class="decoctControlBottom" >
  224. <!-- 左边 -->
  225. <view>
  226. <text>开关状态</text>
  227. </view>
  228. <!-- 右边 -->
  229. <view style="display: flex;align-items: center">
  230. <text style="margin-right: 15px">已开机</text>
  231. <u-switch v-model="decoctControlOnOffStatus" @change="decoctControlOnOffChange"></u-switch>
  232. </view>
  233. </view>
  234. <!-- 下边 -->
  235. <view class="decoctControlBottom">
  236. <!-- 左边 -->
  237. <view>
  238. <text>煎药状态</text>
  239. </view>
  240. <!-- 右边 -->
  241. <view style="display: flex;align-items: center">
  242. <text style="margin-right: 15px">煎药中</text>
  243. <u-switch v-model="decoctControlStatus" @change="decoctControlChange"></u-switch>
  244. </view>
  245. </view>
  246. </view>
  247. </view>
  248. <!-- 包装控制 -->
  249. <view class="demo-uni-row" v-if="PackagControlStatus">
  250. <view class="demo-uni-row clearfix">
  251. <view span="12" style="width: 50vw; float: left;">
  252. <uni-card v-if="power.value > 0" extra="设备开关" thumbnail="/static/images/device/opened.png" @click="changeProp('PowerControl',0)">
  253. <text>已开启,点击图标关闭</text>
  254. <!-- <text>已开启</text>-->
  255. <!-- <u-image src="/static/images/device/opened.png" width="200rpx" height="200rpx"></u-image>-->
  256. </uni-card>
  257. <uni-card v-else extra="设备开关" thumbnail="/static/images/device/closed.png" @click="changeProp('PowerControl',1)">
  258. <text>已关闭,点击图标开启</text>
  259. <!-- <text>已关闭</text>-->
  260. <!-- <u-image src="/static/images/device/opened.png" width="200rpx" height="200rpx"></u-image>-->
  261. </uni-card>
  262. </view>
  263. <view span="12" style="width: 50vw; float: left;">
  264. <uni-card v-if="lock.value > 0" extra="设备锁定" thumbnail="/static/images/device/locked.png" @click="changeProp('LockControl',0)" >
  265. <text>已上锁,点击图标解锁</text>
  266. <!-- <text>已上锁</text>-->
  267. <!-- <u-image src="/static/images/device/locked.png" width="200rpx" height="200rpx"></u-image>-->
  268. </uni-card>
  269. <uni-card v-else extra="设备锁定" thumbnail="/static/images/device/unlocked.png" @click="changeProp('LockControl',1)" >
  270. <text>未上锁,点击图标上锁</text>
  271. <!-- <text>未上锁</text>-->
  272. <!-- <u-image src="/static/images/device/locked.png" width="200rpx" height="200rpx"></u-image>-->
  273. </uni-card>
  274. </view>
  275. <view style="clear: both"></view>
  276. </view>
  277. <!-- 头部 -->
  278. <view class="decoctControlHeader">
  279. <uni-icons custom-prefix="iconfont" type="icon-fuzhushuxian" size="30"></uni-icons>
  280. <text>包装控制</text>
  281. </view>
  282. <!-- 腰部 -->
  283. <view>
  284. <!-- 上边部份 -->
  285. <view class="decoctControlTop">
  286. <!-- 左边 -->
  287. <view class="decoctControlTopLeft">
  288. <text>封边温度</text>
  289. <u-input placeholder="请输入"></u-input>
  290. <view class="addTemperature">
  291. <u-button class="addTemperatureBtn"></u-button>
  292. </view>
  293. <view class="subTime">
  294. <u-button class="subTimeBtn"></u-button>
  295. </view>
  296. </view>
  297. <!-- 右边 -->
  298. <view class="decoctControlTopRight">
  299. <text>封口温度</text>
  300. <u-input placeholder="请输入"></u-input>
  301. <view class="addTemperature">
  302. <u-button class="addTemperatureBtn"></u-button>
  303. </view>
  304. <view class="subTime">
  305. <u-button class="subTimeBtn"></u-button>
  306. </view>
  307. </view>
  308. </view>
  309. <!-- 下边部份 -->
  310. <view class="decoctControlTop">
  311. <!-- 左边 -->
  312. <view class="decoctControlTopLeft">
  313. <text>包装容量</text>
  314. <u-input placeholder="请输入"></u-input>
  315. <view class="addTemperature">
  316. <u-button class="addTemperatureBtn"></u-button>
  317. </view>
  318. <view class="subTime">
  319. <u-button class="subTimeBtn"></u-button>
  320. </view>
  321. </view>
  322. <!-- 右边 -->
  323. <view style="width:40%;line-height: 2;text-align: center;margin: 0 15px;position: relative">
  324. <text>包装数量</text>
  325. <u-input placeholder="请输入"></u-input>
  326. <view class="addTemperature">
  327. <u-button class="addTemperatureBtn"></u-button>
  328. </view>
  329. <view class="subTime" >
  330. <u-button class="subTimeBtn"></u-button>
  331. </view>
  332. </view>
  333. </view>
  334. </view>
  335. <!-- 尾部 -->
  336. <view>
  337. <!-- 上边 -->
  338. <view class="decoctControlBottom">
  339. <!-- 左边 -->
  340. <view>
  341. <text>开关</text>
  342. </view>
  343. <!-- 右边 -->
  344. <view style="display: flex;align-items: center">
  345. <text style="margin-right: 15px">已开机</text>
  346. <u-switch v-model="packageControlOnOffStatus" @change="packageControlOnOffChange"></u-switch>
  347. </view>
  348. </view>
  349. <!-- 下边 -->
  350. <view class="decoctControlBottom">
  351. <!-- 左边 -->
  352. <view>
  353. <text>模式</text>
  354. </view>
  355. <!-- 右边 -->
  356. <view style="display: flex;align-items: center">
  357. <text class="packageControlBottomRight">包装</text>
  358. <text class="packageControlBottomClear">清洗</text>
  359. </view>
  360. </view>
  361. </view>
  362. </view>
  363. <view class="action-btn">
  364. <button @click="showDrawer" class="login-btn cu-btn block bg-blue lg round" style="flex: 0 0 auto;width: 55%;margin: 0 auto;margin-top:20px;">查看更多属性</button>
  365. </view>
  366. <uni-drawer ref="showLeft" :width="320" :maskClick="true" mode="left" @change="change($event,'showLeft')">
  367. <!-- <view class="item" style="padding-top:10rpx">-->
  368. <!-- <u-button v-if="deviceInfo.status==3"-->
  369. <!-- @tap="send(item)"-->
  370. <!-- text="发送"-->
  371. <!-- type="success"-->
  372. <!-- size="mini"-->
  373. <!-- ></u-button>-->
  374. <!-- <u-button v-if="deviceInfo.status!=3"-->
  375. <!-- @tap="send(item)"-->
  376. <!-- text="发送"-->
  377. <!-- type="info"-->
  378. <!-- size="mini"-->
  379. <!-- ></u-button>-->
  380. <!-- </view>-->
  381. <scroll-view style="height: 88%;" scroll-y="true">
  382. <view style="margin-top:20rpx;margin-left:20rpx" v-if="properties.length>0">属性区</view>
  383. <view v-for="item in properties" v-if="checkCommonProp(item)">
  384. <view class="prop-item">
  385. <view class="prop-item-left">{{item.name}}</view>
  386. <view class="prop-item-right">
  387. <view v-if="item.type === 'integer'" style="width:240rpx;position: absolute;top: 10rpx;;">
  388. <u-input :customStyle="inputStyle" fontSize="20rpx" type="number" placeholder="请输入整数" v-model="item.shadow">
  389. </u-input>
  390. </view>
  391. <view style="width:240rpx;position: absolute;top:0rpx;" v-if="item.type === 'string'">
  392. <u-input :customStyle="inputStyle" fontSize="20rpx" placeholder="请输入字符串" v-model="item.shadow">
  393. </u-input>
  394. </view>
  395. <view style="width:240rpx;position: absolute;top: 0rpx;" v-if="item.type === 'array'">
  396. <u-input :customStyle="inputStyle" fontSize="20rpx" placeholder="请使用英文逗号分隔的字符串" v-model="item.shadow">
  397. </u-input>
  398. </view>
  399. <view style="padding:0 10rpx;position: absolute;top: -10rpx;left: -40rpx;" v-if="item.type === 'enum'">
  400. <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">
  401. <u-icon slot="icon" size="12" name="arrow-down"></u-icon>
  402. </u-cell>
  403. <u-cell customStyle="border:0px;" size="mini" @click="chooseItemData(item)" arrow-direction="down" v-else title="请选择">
  404. <u-icon slot="icon" size="12" name="arrow-down"></u-icon>
  405. </u-cell>
  406. </view>
  407. </view>
  408. </view>
  409. </view>
  410. <view v-if="properties.length>0">
  411. <button style="width: 30%; height: 58rpx;
  412. margin-top: 20rpx; float: right;
  413. margin-right: 140rpx;" @click="sendProperties" class="login-btn cu-btn block bg-blue lg round send_btn">发送</button>
  414. </view>
  415. <view style="margin-top:20rpx;margin-left:20rpx" v-if="functions.length>0">功能区</view>
  416. <view v-for="item in functions" v-if="checkCommonProp(item)">
  417. <view class="prop-item">
  418. <view class="prop-item-left">{{item.name}}</view>
  419. <view class="prop-item-right">
  420. <view v-if="item.type === 'integer'" style="width:240rpx;position: absolute;top: 10rpx;;">
  421. <u-input :customStyle="inputStyle" fontSize="20rpx" placeholder="请输入整数" v-model="item.shadow">
  422. </u-input>
  423. </view>
  424. <view style="width:240rpx;position: absolute;top:0rpx;" v-if="item.type === 'string'">
  425. <u-input :customStyle="inputStyle" fontSize="20rpx" placeholder="请输入字符串" v-model="item.shadow">
  426. </u-input>
  427. </view>
  428. <view style="width:240rpx;position: absolute;top: 0rpx;" v-if="item.type === 'array'">
  429. <u-input :customStyle="inputStyle" fontSize="20rpx" placeholder="请使用英文逗号分隔的字符串" v-model="item.shadow">
  430. </u-input>
  431. </view>
  432. <view style="padding:0 10rpx;position: absolute;top: -10rpx;left: -40rpx;" v-if="item.type === 'enum'">
  433. <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">
  434. <u-icon slot="icon" size="12" name="arrow-down"></u-icon>
  435. </u-cell>
  436. <u-cell customStyle="border:0px;" size="mini" @click="chooseItemData(item)" arrow-direction="down" v-else title="请选择">
  437. <u-icon slot="icon" size="12" name="arrow-down"></u-icon>
  438. </u-cell>
  439. </view>
  440. </view>
  441. </view>
  442. </view>
  443. <view v-if="functions.length>0">
  444. <button style="width: 30%; height: 58rpx;
  445. margin-top: 20rpx; float: right;
  446. margin-right: 140rpx;" @click="sendFunctions" class="login-btn cu-btn block bg-blue lg round send_btn">发送</button>
  447. </view>
  448. <view style="margin-top:20rpx;margin-left:20rpx">
  449. <u--text text="属性监控" style="margin-top:20px"></u--text>
  450. </view>
  451. <view class="prop-item" v-if="checkCommonProp(item)" v-for="item in deviceInfo.readOnlyList">
  452. <view class="prop-item-left">{{item.name}}</view>
  453. <view class="prop-item-right" style="width:240rpx;position: absolute;top: 10rpx;right: 70rpx;">
  454. <u-input v-if="checkItemValue(item)" :customStyle="inputStyle" placeholder="请输入字符串" disabled="" :value="item.shadow+' '+item.unit">
  455. </u-input>
  456. </view>
  457. </view>
  458. </scroll-view>
  459. <button @click="closeDrawer" class="login-btn cu-btn block bg-blue lg round">关闭</button>
  460. </uni-drawer>
  461. </view>
  462. </view>
  463. </view>
  464. <u-picker @cancel="show=null" :show="show!=null" :columns="columns" @confirm="confirmItemData" keyName="text"></u-picker>
  465. <u-modal @cancel="cancel" :show="showErrDlg" title="异常上报" :showCancelButton="true" @confirm="doReportError" >
  466. <view class="slot-content">
  467. <view style="margin:10px">
  468. <textarea auto-height ="true" v-model="errorMsg" placeholder="请输入异常内容" ></textarea>
  469. </view>
  470. </view>
  471. </u-modal>
  472. <!-- <u-modal :show="showTimeDlg" title="查看时长" @confirm="closeTime" >-->
  473. <!-- <view class="slot-content">-->
  474. <!-- <view v-if="timeobj!=null && deviceInfo.status == 3">本次运行时长:{{ timeobj.runtime }}</view>-->
  475. <!-- <view v-if="timeobj!=null ">累计时长:{{ timeobj.alltime }}</view>-->
  476. <!-- <view v-if="timeobj!=null ">平均每天运行时长:{{ timeobj.avgtime }}</view>-->
  477. <!-- </view>-->
  478. <!-- </u-modal>-->
  479. </view>
  480. </view>
  481. </template>
  482. <script>
  483. import { getDetail,getDeviceStatus,cacheJsonThingsModel,reportError ,getDeviceRunTime} from '@/api/device/device.js'
  484. import UButton from "../../uni_modules/uview-ui/components/u-button/u-button";
  485. import UForm from "../../uni_modules/uview-ui/components/u--form/u--form";
  486. import UInput from "../../uni_modules/uview-ui/components/u--input/u--input";
  487. import UImage from "../../uni_modules/uview-ui/components/u--image/u--image";
  488. export default {
  489. components: {UImage, UInput, UForm, UButton},
  490. data(){
  491. return {
  492. decoctControlStatus:true,
  493. decoctControlOnOffStatus:true,
  494. packageControlOnOffStatus:true,
  495. subDecoctTabList:[
  496. {name:'子煎药1'},
  497. {name:'子煎药2'},
  498. {name:'子煎药3'},
  499. ],
  500. DecoctControlStatus:true,
  501. PackagControlStatus:false,
  502. subCurrent:0,
  503. current:0,
  504. inputStyle:{height:'44rpx','fontSize':'20rpx'},
  505. modelKey:['PowerControl','LockControl'],
  506. power:{
  507. loading:true,
  508. value:0,
  509. },
  510. lock:{
  511. loading:true,
  512. value:0,
  513. },
  514. showTimeDlg:false,
  515. showErrDlg:null,
  516. errorMsg:"asdasdasdasd",
  517. show:null,
  518. value:"",
  519. deviceInfo:{},
  520. id:0,
  521. summary:[
  522. {tabName:"煎药控制"},
  523. {tabName:"包装控制"},
  524. ],
  525. activeName:0,
  526. childId:"",
  527. oneToMul:false,
  528. inputProp:[],
  529. watchProp:[],
  530. columns:[],
  531. location:{},
  532. sysDept:null,
  533. timeobj:{alltime:0,avgtime:0},
  534. publishMsg:false,
  535. checkTimer:null,
  536. functions:[],
  537. properties:[]
  538. }
  539. },
  540. onLoad: function(opt) {
  541. this.id = opt.id;
  542. // this.id = 61;
  543. this.connectMqtt();
  544. this.getDetail();
  545. },
  546. destroyed() {
  547. // 取消订阅主题
  548. this.mqttUnSubscribe(this.deviceInfo);
  549. clearTimeout(this.checkTimer);
  550. },
  551. methods:{
  552. addTemperature(){
  553. console.log("增加煎药温度")
  554. },
  555. subTemperature(){
  556. console.log("减少煎药温度")
  557. },
  558. decoctControlChange(){
  559. if(this.decoctControlStatus){
  560. console.log("煎药打开")
  561. }else{
  562. console.log("煎药关闭")
  563. }
  564. },
  565. decoctControlOnOffChange(){
  566. if(this.decoctControlOnOffStatus){
  567. console.log("煎药开关打开")
  568. }else{
  569. console.log("煎药开关关闭")
  570. }
  571. },
  572. packageControlOnOffChange(){
  573. if(this.packageControlOnOffStatus){
  574. console.log("包装控制打开")
  575. }else{
  576. console.log("包装控制关闭")
  577. }
  578. },
  579. // 抽屉状态发生变化触发
  580. change(e, type) {
  581. console.log(e);
  582. },
  583. showDrawer() {
  584. this.$refs.showLeft.open();
  585. },
  586. closeDrawer() {
  587. this.$refs.showLeft.close();
  588. },
  589. checkItemValue(item){
  590. if(!item.shadow){
  591. item.shadow = 0;
  592. }
  593. if(!item.unit){
  594. item.unit = "";
  595. }
  596. return true;
  597. },
  598. sendProperties(){
  599. let properties = this.properties;
  600. for (let i = 0; i < properties; i++) {
  601. let property = this.properties[i];
  602. let shadow = property.shadow;
  603. if(shadow){
  604. arr.push(property);
  605. }
  606. }
  607. this.mqttPublish(1,this.deviceInfo,arr)
  608. },
  609. sendFunctions(){
  610. let arr = [];
  611. let functions = this.functions;
  612. for (let i = 0; i < functions.length; i++) {
  613. let functionObj = this.functions[i];
  614. let shadow = functionObj.shadow;
  615. if(shadow){
  616. arr.push(functionObj);
  617. }
  618. }
  619. this.mqttPublish(2,this.deviceInfo,arr)
  620. },
  621. changeProp(key,val){
  622. let item = null;
  623. let obj = null;
  624. if(key === "LockControl"){
  625. this.lock.value = val;
  626. item = this.lock;
  627. }else if(key === "PowerControl"){
  628. this.power.value = val;
  629. item = this.power;
  630. }
  631. let value = val;
  632. obj = item.item;
  633. if(value){
  634. obj.value = 1;
  635. obj.shadow = 1;
  636. }else{
  637. obj.value = 0;
  638. obj.shadow = 0;
  639. }
  640. this.publishThingsModel(this.deviceInfo,obj);
  641. },
  642. checkCommonProp(item){
  643. let id =item.id;
  644. let isCommonKey = this.modelKey.some(res=>{
  645. return id === res;
  646. })
  647. return !isCommonKey;
  648. },
  649. getRunTime(){
  650. let self = this;
  651. getDeviceRunTime(this.id).then(res=>{
  652. self.timeobj = res.data;
  653. if(self.timeobj.avgtime == ""){
  654. self.timeobj.avgtime = 0;
  655. }
  656. if(self.timeobj.alltime == ""){
  657. self.timeobj.alltime = 0;
  658. }
  659. })
  660. },
  661. seeTime(){
  662. this.showTimeDlg = true;
  663. this.getRunTime();
  664. },
  665. closeTime(){
  666. this.showTimeDlg = false;
  667. },
  668. cancel(){
  669. this.showErrDlg = false;
  670. },
  671. reportError(){
  672. this.showErrDlg = true;
  673. },
  674. doReportError(){
  675. if(!this.errorMsg){
  676. this.$modal.showToast('异常信息不能为空')
  677. }else{
  678. let self = this;
  679. let errObj = {};
  680. errObj.deviceId = this.deviceInfo.deviceId;
  681. errObj.deviceName = this.deviceInfo.deviceName
  682. errObj.desc = this.errorMsg;
  683. errObj.deptId= this.deviceInfo.deptId;
  684. reportError(errObj).then(res=>{
  685. self.$modal.showToast(res.msg)
  686. self.cancel();
  687. })
  688. }
  689. },
  690. openLocation(){
  691. uni.openLocation({
  692. latitude: this.location.latitude,
  693. longitude: this.location.longitude,
  694. success: function () {
  695. console.log('success');
  696. }
  697. });
  698. },
  699. confirmItemData(e){
  700. let data = e.value[0];
  701. this.show.text = data.text;
  702. this.show.shadow=data.value;
  703. this.show = null;
  704. console.log(data);
  705. },
  706. send(){
  707. let shadow = false
  708. let _arr = []
  709. this.inputProp.forEach((item)=>{
  710. _arr.push(item.value)
  711. })
  712. // if(_arr.some(val => val === '' || val.length < 0)){
  713. // shadow = true
  714. // }
  715. if(this.deviceInfo.status != 3){
  716. uni.showToast({
  717. title:"设备暂未上线",
  718. icon:"error"
  719. })
  720. return;
  721. }
  722. if(shadow){
  723. uni.showToast({
  724. title:"数据不能为空",
  725. icon:"error"
  726. })
  727. return;
  728. }
  729. this.publishThingsModel(this.deviceInfo,this.inputProp.map(item=>{return{"id":item.id,"value":item.value}}))
  730. },
  731. /** 更新设备状态 */
  732. updateDeviceStatus(device) {
  733. },
  734. chooseItemData(data){
  735. if(this.deviceInfo.status != 3){
  736. uni.showToast({
  737. title:"设备暂未上线",
  738. icon:"error"
  739. })
  740. return;
  741. }
  742. this.columns = [data.enumList];
  743. this.show =data;
  744. },
  745. getDetail(){
  746. let self = this;
  747. getDetail(this.id).then(res=>{
  748. self.deviceInfo = res.data;
  749. self.location = {
  750. latitude: self.deviceInfo.latitude,
  751. longitude: self.deviceInfo.longitude};
  752. self.sysDept = self.deviceInfo.sysDept;
  753. //self.parseSummay(res.data.summary)
  754. self.mqttSubscribe(res.data);
  755. self.getDeviceStatus();
  756. self.seeTime();
  757. });
  758. },
  759. getDeviceStatus(e){
  760. let self = this;
  761. if(!e){
  762. e = {index:0};
  763. this.childId = 0;
  764. }else{
  765. this.activeName = e.index;
  766. //this.childId = this.summary[this.activeName].id;
  767. }
  768. getDeviceStatus(this.id,this.childId).then(res=>{
  769. let data =res.data;
  770. this.deviceInfo = data;
  771. self.parseStatusData(data)
  772. });
  773. },
  774. getNewDeviceStatus(item){
  775. /*{
  776. "tabName": "包装控制",
  777. "rect": {
  778. "id": "",
  779. "dataset": {},
  780. "left": 82,
  781. "right": 164,
  782. "top": 205,
  783. "bottom": 249,
  784. "width": 82,
  785. "height": 44
  786. },
  787. "index": 1
  788. }
  789. */
  790. if(item.index == 0){
  791. this.DecoctControlStatus = true;
  792. this.PackagControlStatus = false;
  793. }
  794. if(item.index == 1){
  795. this.DecoctControlStatus = false;
  796. this.PackagControlStatus = true;
  797. }
  798. },
  799. changeSub(item){
  800. console.log(item);
  801. },
  802. parseEnumList(){
  803. let enumList = this.deviceInfo.enumList;
  804. for (let enumListElement of enumList) {
  805. let id = enumListElement.id;
  806. let isCommonKey = this.modelKey.some(res=>{
  807. return id === res;
  808. })
  809. if(isCommonKey){
  810. if(id.indexOf("LockControl") !=-1){
  811. let shadow = enumListElement.shadow;
  812. this.lock.item = enumListElement;
  813. if(shadow == 1){
  814. this.lock.value = true;
  815. this.lock.loading = false;
  816. }else if(shadow == 0){
  817. this.lock.value = false;
  818. this.lock.loading = false;
  819. }else{
  820. this.lock.loading = true;
  821. }
  822. }
  823. if(id.indexOf("PowerControl") !=-1){
  824. let shadow = enumListElement.shadow;
  825. this.power.item = enumListElement;
  826. if(shadow == 1){
  827. this.power.value = true;
  828. this.power.loading = false;
  829. }else if(shadow == 0){
  830. this.power.value = false;
  831. this.power.loading = false;
  832. }else{
  833. this.power.loading = true;
  834. }
  835. }
  836. }
  837. let shadow = enumListElement.shadow
  838. let valueList = enumListElement.enumList;
  839. for (let valueObj of valueList){
  840. if(valueObj.value == shadow){
  841. enumListElement.text = valueObj.text;
  842. }
  843. }
  844. }
  845. },
  846. parseStatusData(data){
  847. let self = this;
  848. cacheJsonThingsModel(data.productId).then(res=>{
  849. let thingsModel = JSON.parse(res.data);
  850. let arr = [];
  851. let arrayList = data.arrayList;
  852. arr = arr.concat(arrayList);
  853. let enumList = data.enumList;
  854. arr = arr.concat(enumList);
  855. let integerList = data.integerList;
  856. arr = arr.concat(integerList);
  857. let stringList = data.stringList;
  858. arr = arr.concat(stringList);
  859. self.inputProp = arr;
  860. for (let i = 0; i < thingsModel.functions.length; i++) {
  861. for (let j = 0; j < arr.length; j++) {
  862. let model = arr[j];
  863. if(model.id == thingsModel.functions[i].id){
  864. self.functions.push(model);
  865. }
  866. }
  867. }
  868. for (let i = 0; i < thingsModel.properties.length; i++) {
  869. for (let j = 0; j < arr.length; j++) {
  870. let model = arr[j];
  871. if(model.id == thingsModel.properties[i].id){
  872. self.properties.push(model);
  873. }
  874. }
  875. }
  876. let readOnlyList = data.readOnlyList;
  877. self.watchProp = readOnlyList;
  878. self.parseEnumList();
  879. })
  880. },
  881. parseSummay(summary){
  882. let self = this;
  883. if(!summary){
  884. summary = "";
  885. }
  886. if(summary.length>0){
  887. this.summary = JSON.parse(summary);
  888. if(self.summary.length>0){
  889. this.oneToMul = true;
  890. }
  891. for (let i = 0; i < self.summary.length; i++) {
  892. self.summary[i].tabName = self.summary[i].id+"_"+self.summary[i].name
  893. }
  894. let childId = "";
  895. if(this.oneToMul){
  896. let info = self.summary[self.activeName];
  897. childId = info.id;
  898. }
  899. this.childId = childId;
  900. }else{
  901. this.summary = [{tabName:"详情查看"}]
  902. }
  903. },
  904. goDeviceDetail(id){
  905. uni.navigateTo({
  906. url: '/pages/device/detail/detail?id='+id
  907. });
  908. },
  909. async connectMqtt() {
  910. if (this.$mqttTool.client == null) {
  911. await this.$mqttTool.connect(this.vuex_token);
  912. }
  913. this.mqttCallback();
  914. this.startCheck();
  915. },
  916. /** Mqtt订阅主题 */
  917. mqttSubscribe(device) {
  918. // 订阅当前设备状态和实时监测
  919. let topicStatus = '/' + device.productId + '/' + device.serialNumber + '/status/post';
  920. let topicProperty = '/' + device.productId + '/' + device.serialNumber + '/property/post';
  921. let topicFunction = '/' + device.productId + '/' + device.serialNumber + '/function/post';
  922. let topics = [];
  923. topics.push(topicStatus);
  924. topics.push(topicProperty);
  925. topics.push(topicFunction);
  926. this.$mqttTool.subscribe(topics);
  927. },
  928. /** Mqtt取消订阅主题 */
  929. mqttUnSubscribe(device) {
  930. // 订阅当前设备状态和实时监测
  931. let topicStatus = '/' + device.productId + '/' + device.serialNumber + '/status/post';
  932. let topicProperty = '/' + device.productId + '/' + device.serialNumber + '/property/post';
  933. let topicFunction = '/' + device.productId + '/' + device.serialNumber + '/function/post';
  934. let topics = [];
  935. topics.push(topicStatus);
  936. topics.push(topicProperty);
  937. topics.push(topicFunction);
  938. console.log('取消订阅', topics);
  939. this.$mqttTool.unsubscribe(topics);
  940. },
  941. /* Mqtt回调处理 */
  942. mqttCallback() {
  943. this.$mqttTool.client.on('message', (topic, message, buffer) => {
  944. let topics = topic.split('/');
  945. let productId = topics[1];
  946. let deviceNum = topics[2];
  947. console.log('接收到内容:'+message);
  948. message = JSON.parse(message.toString());
  949. if (topics[3] == 'status') {
  950. console.log('接收到【设备状态-运行】主题:', topic);
  951. console.log('接收到【设备状态-运行】内容:', message);
  952. // 更新列表中设备的状态
  953. if (this.deviceInfo.serialNumber == deviceNum) {
  954. this.deviceInfo.status = message.status;
  955. this.deviceInfo.isShadow = message.isShadow;
  956. this.deviceInfo.rssi = message.rssi;
  957. this.updateDeviceStatus(this.deviceInfo);
  958. }
  959. }
  960. if (topics[3] == 'property' || topics[3] == 'function') {
  961. console.log('接收到【物模型】主题:', topic);
  962. console.log('接收到【物模型】内容:', message);
  963. if(this.oneToMul){
  964. let curTabId = this.summary[this.activeName].id;
  965. let msg = [];
  966. for (let i = 0; i < message.length; i++) {
  967. let curMsg = message[i];
  968. let id = curMsg.id;
  969. let ids = id.split("_");
  970. let value = curMsg.value;
  971. if(ids.length == 2){
  972. if(curTabId == ids[1]){
  973. msg.push({id:ids[0],value:value});
  974. }
  975. }
  976. }
  977. message = msg;
  978. }
  979. // 更新列表中设备的属性
  980. if (this.deviceInfo.serialNumber == deviceNum) {
  981. for (let j = 0; j < message.length; j++) {
  982. let isComplete = false;
  983. // 布尔类型
  984. for (let k = 0; k < this.deviceInfo.boolList.length && !isComplete; k++) {
  985. if (this.deviceInfo.boolList[k].id == message[j].id) {
  986. this.deviceInfo.boolList[k].shadow = message[j].value;
  987. isComplete = true;
  988. break;
  989. }
  990. }
  991. // 枚举类型
  992. for (let k = 0; k < this.deviceInfo.enumList.length && !isComplete; k++) {
  993. if (this.deviceInfo.enumList[k].id == message[j].id) {
  994. this.deviceInfo.enumList[k].shadow = message[j].value;
  995. isComplete = true;
  996. break;
  997. }
  998. }
  999. // 字符串类型
  1000. for (let k = 0; k < this.deviceInfo.stringList.length && !isComplete; k++) {
  1001. if (this.deviceInfo.stringList[k].id == message[j].id) {
  1002. this.deviceInfo.stringList[k].shadow = message[j].value;
  1003. isComplete = true;
  1004. break;
  1005. }
  1006. }
  1007. // 数组类型
  1008. for (let k = 0; k < this.deviceInfo.arrayList.length && !isComplete; k++) {
  1009. if (this.deviceInfo.arrayList[k].id == message[j].id) {
  1010. this.deviceInfo.arrayList[k].shadow = message[j].value;
  1011. isComplete = true;
  1012. break;
  1013. }
  1014. }
  1015. // 整数类型
  1016. for (let k = 0; k < this.deviceInfo.integerList.length && !isComplete; k++) {
  1017. if (this.deviceInfo.integerList[k].id == message[j].id) {
  1018. this.deviceInfo.integerList[k].shadow = message[j].value;
  1019. isComplete = true;
  1020. break;
  1021. }
  1022. }
  1023. // 小数类型
  1024. for (let k = 0; k < this.deviceInfo.decimalList.length && !isComplete; k++) {
  1025. if (this.deviceInfo.decimalList[k].id == message[j].id) {
  1026. this.deviceInfo.decimalList[k].shadow = message[j].value;
  1027. isComplete = true;
  1028. break;
  1029. }
  1030. }
  1031. // 监测数据
  1032. for (let k = 0; k < this.deviceInfo.readOnlyList.length && !isComplete; k++) {
  1033. if (this.deviceInfo.readOnlyList[k].id == message[j].id) {
  1034. this.deviceInfo.readOnlyList[k].shadow = message[j].value;
  1035. // 更新图表
  1036. // for (let m = 0; m < this.monitorChart.length; m++) {
  1037. // if (message[j].id == this.monitorChart[m].data.id) {
  1038. // let data = [{
  1039. // value: message[j].value,
  1040. // name: this.monitorChart[m].data.name
  1041. // }];
  1042. // this.monitorChart[m].chart.setOption({
  1043. // series: [{
  1044. // data: data
  1045. // }]
  1046. // });
  1047. // break;
  1048. // }
  1049. // }
  1050. isComplete = true;
  1051. break;
  1052. }
  1053. }
  1054. }
  1055. this.parseEnumList();
  1056. }
  1057. }
  1058. });
  1059. },
  1060. /** 发布物模型 类型(1=属性,2=功能) */
  1061. publishThingsModel(device, model) {
  1062. // 获取缓存的Json物模型
  1063. cacheJsonThingsModel(device.productId).then(response => {
  1064. let thingsModel = JSON.parse(response.data);
  1065. let type = 0;
  1066. for (let i = 0; i < thingsModel.functions.length; i++) {
  1067. if (model.id == thingsModel.functions[i].id) {
  1068. type = 2;
  1069. break;
  1070. }
  1071. }
  1072. if (type == 0) {
  1073. for (let i = 0; i < thingsModel.properties.length; i++) {
  1074. if (model.id == thingsModel.properties[i].id) {
  1075. type = 1;
  1076. break;
  1077. }
  1078. }
  1079. }
  1080. if (type != 0) {
  1081. this.mqttPublish(type, device, [model]);
  1082. }
  1083. });
  1084. },
  1085. notifyError(res){
  1086. uni.showToast({
  1087. title:res,
  1088. icon:"error"
  1089. })
  1090. },
  1091. notifySuccess(res){
  1092. uni.showToast({
  1093. title:res,
  1094. icon:"success"
  1095. })
  1096. },
  1097. /**
  1098. * Mqtt发布消息
  1099. * @type 类型(1=属性,2=功能,3=OTA升级,4=实时监测)
  1100. * @device 设备
  1101. * @model 物模型
  1102. * */
  1103. mqttPublish(type, device, modelList) {
  1104. if(modelList.length == 0){
  1105. return;
  1106. }
  1107. let topic = "";
  1108. let message = ""
  1109. let oneToMul = false;
  1110. if(this.summary.length>0){
  1111. oneToMul = true;
  1112. }
  1113. if (type == 1) {
  1114. if (device.status == 3) {
  1115. // 属性,在线模式
  1116. topic = "/" + device.productId + "/" + device.serialNumber + "/property-online/get";
  1117. }
  1118. } else if (type == 2) {
  1119. if (device.status == 3) {
  1120. // 功能,在线模式
  1121. topic = "/" + device.productId + "/" + device.serialNumber + "/function-online/get";
  1122. }
  1123. } else if (type == 3) {
  1124. // OTA升级
  1125. topic = "/" + device.productId + "/" + device.serialNumber + "/ota/get";
  1126. } else {
  1127. return;
  1128. }
  1129. let title = "";
  1130. if(type == 1){
  1131. title = "属性";
  1132. }else if(type == 2){
  1133. title = "功能";
  1134. }
  1135. if (topic != "") {
  1136. // 发布
  1137. let arr = [];
  1138. for (let i = 0; i <modelList.length; i++) {
  1139. let model = modelList[i];
  1140. let modelId = model.id;
  1141. if(oneToMul){
  1142. let info = this.summary[this.activeName];
  1143. let childId = info.id;
  1144. if(childId){
  1145. modelId = modelId+"_"+childId;
  1146. }
  1147. }
  1148. let shadow = model.shadow;
  1149. let modelType = model.type;
  1150. let shadowInt = parseInt(shadow,10);
  1151. let isNumber = false;
  1152. let shadowStr = shadowInt+"";
  1153. if(shadowStr === shadow){
  1154. isNumber = true;
  1155. shadow = shadowInt;
  1156. }
  1157. if(modelType == "integer" && !isNumber){
  1158. this.$modal.showToast(model.name+'的值必须是数字类型')
  1159. return;
  1160. }
  1161. arr.push({id:modelId,value:shadow});
  1162. }
  1163. message = JSON.stringify(arr);
  1164. let self = this;
  1165. this.$mqttTool.publish(topic, message,title).then(res => {
  1166. this.notifySuccess(res);
  1167. }).catch(res => {
  1168. this.notifyError(res);
  1169. });
  1170. }
  1171. },
  1172. startCheck(){
  1173. let self = this;
  1174. this.checkTimer = setTimeout(function (){
  1175. self.sendHeart();
  1176. self.startCheck();
  1177. },20000);
  1178. },
  1179. checkActive(){
  1180. let self = this;
  1181. setTimeout(function (){
  1182. if(self.publishMsg){
  1183. self.resetConn()
  1184. }
  1185. },3000);
  1186. },
  1187. sendHeart(){
  1188. console.log("发送心跳111")
  1189. let device = this.deviceInfo;
  1190. let self = this;
  1191. let topic = "/property-offline/post";
  1192. self.publishMsg = true;
  1193. self.checkActive();
  1194. this.$mqttTool.publish(topic, "ok", "heart").then(res => {
  1195. self.publishMsg = false;
  1196. }).catch(res => {
  1197. self.publishMsg = false;
  1198. });
  1199. },
  1200. resetConn(){
  1201. console.log("检测异常,重连")
  1202. this.$mqttTool.end();
  1203. this.$mqttTool.client = null;
  1204. this.connectMqtt();
  1205. this.getDetail();
  1206. }
  1207. }
  1208. }
  1209. </script>
  1210. <style>
  1211. .send_btn{
  1212. width: 300rpx;
  1213. }
  1214. uni-col{
  1215. width: 150px;
  1216. }
  1217. .header{
  1218. width: 100%;
  1219. background: white;
  1220. padding:0px 20rpx;
  1221. position: relative;
  1222. }
  1223. .content {
  1224. display: flex;
  1225. align-items: center;
  1226. justify-content: center;
  1227. }
  1228. .logo {
  1229. height: 200rpx;
  1230. width: 200rpx;
  1231. margin-top: 200rpx;
  1232. margin-left: auto;
  1233. margin-right: auto;
  1234. margin-bottom: 50rpx;
  1235. }
  1236. .text-area {
  1237. margin:10px;
  1238. padding-bottom: 10px;
  1239. justify-content: center;
  1240. width: 100%;
  1241. }
  1242. .grid-text {
  1243. font-size: 14px;
  1244. color: #909399;
  1245. padding: 10rpx 0 20rpx 0rpx;
  1246. /* #ifndef APP-PLUS */
  1247. box-sizing: border-box;
  1248. /* #endif */
  1249. }
  1250. .title {
  1251. font-size: 36rpx;
  1252. color: #8f8f94;
  1253. }
  1254. .item{
  1255. height: 80rpx;
  1256. line-height: 80rpx;
  1257. }
  1258. .bg{
  1259. position: relative;
  1260. }
  1261. .text-left{
  1262. color: #8A92A5;
  1263. }
  1264. .text-right{
  1265. color: #545454;
  1266. }
  1267. .prop-text{
  1268. position: relative;
  1269. margin:20rpx 0;
  1270. font-size: 26rpx;
  1271. }
  1272. .prop-card-area{
  1273. }
  1274. .prop-card{
  1275. width: 28%;
  1276. height: 100rpx;
  1277. text-align: center;
  1278. display: inline-block;
  1279. background: #F5FCFF;
  1280. box-shadow: 0px 9rpx 8rpx 0px rgba(0,0,0,0.09);
  1281. border-radius: 8rpx;
  1282. margin:0px 15rpx;
  1283. line-height: 48rpx;
  1284. }
  1285. .prop-card-top{
  1286. color: #3E9CFC;
  1287. }
  1288. .prop-card-bottom{
  1289. color: #8A92A5;
  1290. }
  1291. .tab-area {
  1292. background: white;
  1293. position: absolute;
  1294. left: 0px;
  1295. right: 0px;
  1296. top:480rpx;
  1297. bottom:-20px;
  1298. min-height: 200rpx;
  1299. box-shadow: 0rpx 5rpx 27rpx 0rpx rgba(195, 195, 195, 0.4);
  1300. border-radius: 40rpx;
  1301. overflow-y: auto;
  1302. padding-bottom:80rpx;
  1303. }
  1304. .prop-item{
  1305. justify-content:center;
  1306. position: relative;
  1307. border-bottom: 1px solid lightgray;
  1308. height: 80rpx;
  1309. margin:0 20rpx;
  1310. }
  1311. .prop-item-left{
  1312. position: absolute;
  1313. left:10rpx;
  1314. top:22rpx;
  1315. color: #545454;
  1316. width: 50%;
  1317. font-size: 12px;
  1318. }
  1319. .prop-item-right{
  1320. position: absolute;
  1321. right:10rpx;
  1322. top:10rpx;
  1323. width: 50%;
  1324. }
  1325. input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{
  1326. color:#666;
  1327. font-size:12px;
  1328. }
  1329. .clearfix::after {
  1330. content: "";
  1331. display: block;
  1332. clear: both;
  1333. }
  1334. .decoctControlHeader {
  1335. display: flex;
  1336. align-items: center;
  1337. font-weight: 600;
  1338. }
  1339. .decoctControlTop {
  1340. display: flex;
  1341. height: 120px;
  1342. border-bottom:1px #B2B2B2 dotted;
  1343. }
  1344. .decoctControlTopLeft {
  1345. width:40%;
  1346. line-height: 2;
  1347. text-align: center;
  1348. margin: 0 15px;
  1349. position: relative;
  1350. }
  1351. .addTemperature {
  1352. border-radius:5px;
  1353. position:absolute;
  1354. background-color: dodgerblue;
  1355. color:white;
  1356. width: 30px;
  1357. height: 30px;
  1358. left:15px;
  1359. top:71px;
  1360. }
  1361. .addTemperatureBtn {
  1362. border-radius:10px;
  1363. position:absolute;
  1364. clip-path: polygon(50% 0,100% 100%,0 100%);
  1365. transform: scale(0.5);
  1366. left: 0;
  1367. top:0;
  1368. bottom: 0;
  1369. right: 0;
  1370. margin: auto;
  1371. }
  1372. .subTemperature {
  1373. border-radius:5px;
  1374. position:absolute;
  1375. background-color: dodgerblue;
  1376. color:white;
  1377. width: 30px;
  1378. height: 30px;
  1379. right:15px;
  1380. top:71px;
  1381. transform: rotate(180deg);
  1382. }
  1383. .subTemperatureBtn {
  1384. border-radius:10px;
  1385. position:absolute;
  1386. clip-path: polygon(50% 0,100% 100%,0 100%);
  1387. transform: scale(0.5);
  1388. left: 0;
  1389. top:0;
  1390. bottom: 0;
  1391. right: 0;
  1392. margin: auto;
  1393. }
  1394. .decoctControlTopRight {
  1395. width:40%;
  1396. line-height: 2;
  1397. text-align: center;
  1398. margin: 0 15px;
  1399. position: relative;
  1400. }
  1401. .decoctControlBottom {
  1402. border-bottom:1px #B2B2B2 dotted;
  1403. width:85vw;
  1404. margin:0 auto;
  1405. padding:10px;
  1406. display: flex;
  1407. justify-content:space-between;
  1408. align-items: center;
  1409. }
  1410. .addTime {
  1411. border-radius:5px;
  1412. position:absolute;
  1413. background-color: dodgerblue;
  1414. color:white;
  1415. width: 30px;
  1416. height: 30px;
  1417. left:15px;
  1418. top:71px;
  1419. }
  1420. .addTimeBtn {
  1421. border-radius:10px;
  1422. position:absolute;
  1423. clip-path: polygon(50% 0,100% 100%,0 100%);
  1424. transform: scale(0.5);
  1425. left: 0;
  1426. top:0;
  1427. bottom: 0;
  1428. right: 0;
  1429. margin: auto;
  1430. }
  1431. .subTime {
  1432. border-radius:5px;
  1433. position:absolute;
  1434. background-color: dodgerblue;
  1435. color:white;
  1436. width: 30px;
  1437. height: 30px;
  1438. right:15px;
  1439. top:71px;
  1440. transform: rotate(180deg);
  1441. }
  1442. .subTimeBtn {
  1443. border-radius:10px;
  1444. position:absolute;
  1445. clip-path: polygon(50% 0,100% 100%,0 100%);
  1446. transform: scale(0.5);
  1447. left: 0;
  1448. top:0;
  1449. bottom: 0;
  1450. right: 0;
  1451. margin: auto;
  1452. }
  1453. .packageControlBottomRight {
  1454. border-radius:5px;
  1455. padding:5px 10px;
  1456. margin-right: 15px;
  1457. background-color: #3c9cff;
  1458. color: #fff;
  1459. }
  1460. .packageControlBottomClear {
  1461. border-radius:5px;
  1462. padding:5px 10px;
  1463. background-color: #B2B2B2;
  1464. color: #fff;
  1465. }
  1466. </style>