deviceControl.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. <template>
  2. <view class="device-detail">
  3. <view class="device-detail__header">
  4. <u-icon
  5. size="36"
  6. class="arrow-left"
  7. name="arrow-left"
  8. @click="handleBack"
  9. ></u-icon>
  10. {{ title }}
  11. </view>
  12. <view class="device-detail__body">
  13. <view class="tabs">
  14. <view class="tab-container">
  15. <view class="tab-item" :class="activeTab === 'pestAnalysis'?'active':''" @click="handleTabClick('pestAnalysis')">
  16. 管理员
  17. </view>
  18. <view class="tab-item" :class="activeTab === 'viewImage'?'active':''" @click="handleTabClick('viewImage')">
  19. 设置
  20. </view>
  21. </view>
  22. </view>
  23. <view class="device-detail-content" v-if="activeTab === 'pestAnalysis'">
  24. <view class="device-detail-item">
  25. <text class="device-detail-label">联网模块</text>
  26. <view class="device-detail-btn-container">
  27. <view class="device-detail-btn" @click="setDeviceContorl('dtu_update')">升级</view>
  28. <view class="device-detail-btn" @click="setDeviceContorl('dtu_reboot')">重启</view>
  29. <!-- <view class="device-detail-btn" @click="showMqttConfig">MQTT配置</view> -->
  30. </view>
  31. </view>
  32. <!-- <view class="device-detail-item">
  33. <text class="device-detail-label">板子设置</text>
  34. <view class="device-detail-btn-container">
  35. <view class="device-detail-btn" @click="showMqttConfig('imei')">更改IMEI</view>
  36. </view>
  37. </view>
  38. <view class="device-detail-item">
  39. <text class="device-detail-label">强制操作</text>
  40. <view class="device-detail-btn-container">
  41. <view class="device-detail-btn force-btn" @click="setDeviceContorl('takephoto')">拍照</view>
  42. <view class="device-detail-btn force-btn" @click="setDeviceContorl('update')">升级</view>
  43. <view class="device-detail-btn force-btn" @click="setDeviceContorl('reboot')">重启</view>
  44. <view class="device-detail-btn force-btn" @click="setDeviceContorl('autotakephoto')">对焦拍照</view>
  45. <view class="device-detail-btn force-btn" @click="setDeviceContorl('turn')">转仓</view>
  46. </view>
  47. </view> -->
  48. </view>
  49. <view class="device-detail-content" style="padding-bottom: 50rpx" v-if="activeTab === 'viewImage'">
  50. <view class="device-detail-viewImage">
  51. <u-icon name="clock" color="#0bbc58" size="46"></u-icon>
  52. <text class="device-detail-label" style="margin-left: 10rpx">
  53. 采集开始和关闭时间
  54. </text>
  55. <view class="clear-btn" @click="clearTime">清空</view>
  56. </view>
  57. <view class="time-container" v-for="(item,index) in coll_time" :key="index">
  58. <view class="start-time" @click="showPickerHandler(index,'start_time')">{{item.start_time_label || '开始时间'}}</view>-
  59. <view class="end-time" @click="showPickerHandler(index,'end_time')">{{item.end_time_label || '结束时间'}}
  60. </view><u-icon name="clock" color="#4E5969" size="26" style="padding-right: 20rpx"></u-icon>
  61. </view>
  62. <view class="device-detail-viewImage">
  63. <text class="device-detail-label">高温保护阀值(℃)
  64. {{ equipContrlForm.tph }}</text>
  65. </view>
  66. <view class="slider-container">
  67. <view class="slider-min-value">50</view>
  68. <u-slider :value="equipContrlForm.tph" @input="e => equipContrlForm.tph = e" class="slider" :min="50" :max="70" active-color="#0bbc58"></u-slider>
  69. <view class="slider-max-value">70</view>
  70. </view>
  71. <view class="device-detail-viewImage">
  72. <text class="device-detail-label">低温保护阀值(℃)
  73. {{ equipContrlForm.tpl }}</text>
  74. </view>
  75. <view class="slider-container">
  76. <view class="slider-min-value">-30</view>
  77. <u-slider :value="equipContrlForm.tpl" @input="e => equipContrlForm.tpl = e" class="slider" :min="-30" :max="20" active-color="#0bbc58"></u-slider>
  78. <view class="slider-max-value">20</view>
  79. </view>
  80. <view class="device-detail-viewImage">
  81. <text class="device-detail-label">数据上传间隔(min)
  82. {{ equipContrlForm.datt }}</text>
  83. </view>
  84. <view class="slider-container">
  85. <view class="slider-min-value">10</view>
  86. <u-slider :value="equipContrlForm.datt" @input="e => equipContrlForm.datt = e" :max="60" :min="10" active-color="#0bbc58" class="slider"></u-slider>
  87. <view class="slider-max-value">60</view>
  88. </view>
  89. </view>
  90. </view>
  91. <view class="device-detail-btn-footer" v-if="activeTab === 'viewImage'">
  92. <view class="device-detail-btn" @click="saveSettings">保存</view>
  93. </view>
  94. <u-popup v-model="show" mode="bottom">
  95. <view class="device-detail-content" style="height: 50vh">
  96. <view class="device-detail-item">
  97. <text class="device-detail-label">请输入imei</text>
  98. <u-input v-model="equipContrlForm.imei" placeholder="请输入imei"></u-input>
  99. </view>
  100. </view>
  101. <view class="device-detail-btn-footer">
  102. <view class="device-detail-btn" @click="setDeviceContorl('imei')">保存</view>
  103. </view>
  104. </u-popup>
  105. <u-select v-model="showPicker" :list="timeList" @confirm="confirmPicker"></u-select>
  106. </view>
  107. </template>
  108. <script>
  109. export default {
  110. data(){
  111. return {
  112. showPicker: false,
  113. value: 10,
  114. timeList: [],
  115. imageList: [],
  116. coll_time:[{
  117. start_time: '',
  118. start_time_label: '',
  119. end_time: '',
  120. end_time_label: '',
  121. },{
  122. start_time: '',
  123. start_time_label: '',
  124. end_time: '',
  125. end_time_label: '',
  126. },{
  127. start_time: '',
  128. start_time_label: '',
  129. end_time: '',
  130. end_time_label: '',
  131. }],
  132. equipContrlForm: {
  133. tph: 0,
  134. tpl: 0,
  135. datt: 0,
  136. },
  137. time: '',
  138. activeTab: 'pestAnalysis',
  139. title: '设置控制',
  140. deviceType: '',
  141. location: '',
  142. d_id: '',
  143. show: false,
  144. checked: false,
  145. currentIndex: -1,
  146. currentType: ''
  147. }
  148. },
  149. onLoad(options){
  150. this.d_id = options.d_id;
  151. this.getControlDeviceConfigInfo();
  152. this.timeList = [];
  153. for(let i = 0;i<24;i++){
  154. this.timeList.push({
  155. value:i,
  156. label:i < 10 ? '0' + i + ':00' : i + ':00'
  157. })
  158. }
  159. },
  160. methods: {
  161. clearTime(){
  162. this.coll_time.forEach(item => {
  163. item.start_time = '';
  164. item.start_time_label = '';
  165. item.end_time = '';
  166. item.end_time_label = '';
  167. })
  168. },
  169. confirmPicker(e){
  170. const value = e[0].value;
  171. const label = e[0].label;
  172. if(this.currentType == 'end_time'){
  173. if(this.coll_time[this.currentIndex]['start_time'] > value){
  174. uni.showToast({
  175. title: '结束时间不能早于开始时间',
  176. icon: 'none',
  177. })
  178. return
  179. }
  180. }
  181. if(this.currentType == 'start_time' && this.currentIndex > 0){
  182. if(this.coll_time[this.currentIndex-1]['end_time'] > value){
  183. uni.showToast({
  184. title: '开始时间不能早于前面采集时间的结束时间',
  185. icon: 'none',
  186. })
  187. return
  188. }
  189. }
  190. if(this.currentType == 'start_time' && this.coll_time[this.currentIndex]['end_time'] !== ''){
  191. if(value > this.coll_time[this.currentIndex]['end_time']){
  192. uni.showToast({
  193. title: '开始时间不能晚于结束时间',
  194. icon: 'none',
  195. })
  196. return
  197. }
  198. }
  199. this.coll_time[this.currentIndex][this.currentType] = value;
  200. this.coll_time[this.currentIndex][this.currentType + '_label'] = label;
  201. },
  202. showPickerHandler(index,type){
  203. if(type == 'end_time'){
  204. if(this.coll_time[index]['start_time'] === ''){
  205. uni.showToast({
  206. title: '请先选择开始时间',
  207. icon: 'none',
  208. })
  209. return
  210. }
  211. }
  212. if(index != 0){
  213. if(this.coll_time[index-1]['start_time_label'] === '' || this.coll_time[index-1]['end_time_label'] === ''){
  214. uni.showToast({
  215. title: '请先选择前面采集时间的开始和结束时间',
  216. icon: 'none',
  217. })
  218. return
  219. }
  220. }
  221. this.showPicker = true;
  222. this.currentIndex = index
  223. this.currentType = type
  224. },
  225. closePicker(){
  226. this.showPicker = false;
  227. this.currentType = ''
  228. this.currentIndex = -1
  229. },
  230. handleBack() {
  231. uni.navigateBack({
  232. delta: 1
  233. });
  234. },
  235. handleTabClick(tab) {
  236. this.activeTab = tab;
  237. },
  238. showMqttConfig(){
  239. this.show = true;
  240. },
  241. closeMqttConfig(){
  242. this.show = false;
  243. },
  244. async setDeviceContorl(type){
  245. const data = {
  246. device_type_id: 2,
  247. d_id: this.d_id,
  248. cmd: type,
  249. }
  250. if(type === 'imei'){
  251. data.imei = this.equipContrlForm.imei
  252. }else{
  253. delete data.imei
  254. }
  255. this.$myRequest({
  256. url: '/api/api_gateway?method=forecast.send_control.admin_device_control',
  257. method: 'POST',
  258. data
  259. }).then(res => {
  260. this.closeMqttConfig()
  261. if (res) {
  262. uni.showToast({
  263. title: '设备控制修改成功!',
  264. icon: 'success',
  265. });
  266. } else {
  267. uni.showToast({
  268. title: '设备控制修改失败',
  269. icon: 'error',
  270. });
  271. }
  272. });
  273. },
  274. saveSettings(){
  275. let newForm = Object.assign({}, this.equipContrlForm) // 深拷贝
  276. newForm.st = newForm.st + ''
  277. newForm.et = newForm.et + ''
  278. newForm.st && newForm.st.slice(0, 2).charAt(0) != '0'
  279. ? newForm.st.slice(0, 2)
  280. : newForm.st.slice(1, 2)
  281. newForm.et =
  282. newForm.et && newForm.et.slice(0, 2).charAt(0) != '0'
  283. ? newForm.et.slice(0, 2)
  284. : newForm.et.slice(1, 2)
  285. for (let k in newForm) {
  286. if (typeof newForm[k] === 'number') {
  287. newForm[k] = newForm[k] + ''
  288. }
  289. }
  290. newForm.st = newForm.st.replace(':00', '')
  291. console.log(this.coll_time,'coll_timecoll_timecoll_time')
  292. const coll_time = [];
  293. for(let i = 0;i< this.coll_time.length;i++){
  294. const coll_item = this.coll_time[i];
  295. if(String(coll_item.start_time) && String(coll_item.end_time)){
  296. coll_time.push(String(coll_item.start_time) + '-' + String(coll_item.end_time))
  297. }
  298. }
  299. newForm.coll_time = coll_time
  300. this.$myRequest({
  301. url: '/api/api_gateway?method=forecast.send_control.device_control',
  302. method: 'POST',
  303. data: {
  304. device_type_id: 2,
  305. d_id: this.d_id,
  306. config: JSON.stringify(newForm)
  307. }
  308. }).then(res => {
  309. if (res) {
  310. // 设备控制修改成功
  311. uni.showToast({
  312. title: '设备控制修改成功!',
  313. icon: 'success',
  314. });
  315. } else {
  316. uni.showToast({
  317. title: '设备控制修改失败',
  318. icon: 'error',
  319. });
  320. }
  321. })
  322. },
  323. async getControlDeviceConfigInfo(){
  324. const res = await this.$myRequest({
  325. url: '/api/api_gateway?method=forecast.send_control.device_control_info',
  326. method: 'POST',
  327. data: {
  328. d_id: this.d_id,
  329. cmd:'paramconf'
  330. },
  331. });
  332. this.equipContrlForm = res
  333. const coll_time = res?.coll_time || [];
  334. for(let i = 0;i< coll_time.length;i++){
  335. const coll_item = coll_time[i];
  336. const start_time = coll_item.split('-')[0];
  337. const end_time = coll_item.split('-')[1];
  338. this.coll_time[i]['start_time'] = start_time;
  339. this.coll_time[i]['end_time'] = end_time;
  340. this.coll_time[i]['start_time_label'] = start_time >= 10 ? start_time + ':00' : '0' + start_time + ':00';
  341. this.coll_time[i]['end_time_label'] = end_time >= 10 ? end_time + ':00' : '0' + end_time + ':00';
  342. }
  343. console.log(this.coll_time,'coll_timecoll_timecoll_time')
  344. // 确保值是数字类型,并且使用默认值时也要在合理范围内
  345. this.equipContrlForm.tph = this.equipContrlForm.tph !== undefined && this.equipContrlForm.tph !== '' && !isNaN(this.equipContrlForm.tph) ? Number(this.equipContrlForm.tph) : 50;
  346. this.equipContrlForm.tpl = this.equipContrlForm.tpl !== undefined && this.equipContrlForm.tpl !== '' && !isNaN(this.equipContrlForm.tpl) ? Number(this.equipContrlForm.tpl) : 0;
  347. this.equipContrlForm.datt = this.equipContrlForm.datt !== undefined && this.equipContrlForm.datt !== '' && !isNaN(this.equipContrlForm.datt) ? Number(this.equipContrlForm.datt) : 10;
  348. },
  349. }
  350. }
  351. </script>
  352. <style scoped lang="scss">
  353. .device-detail {
  354. display: flex;
  355. width: 100%;
  356. height: calc(100vh - 112rpx);
  357. padding-top: 112rpx;
  358. flex-direction: column;
  359. align-items: center;
  360. background: linear-gradient(180deg, #ffffff00 0%, #F5F6FA 23.64%, #F5F6FA 100%), linear-gradient(102deg, #BFEADD 6.77%, #B8F1E7 40.15%, #B9EEF5 84.02%);
  361. .device-detail__header {
  362. width: 100%;
  363. font-size: 28rpx;
  364. color: #999;
  365. color: #042118;
  366. font-family: 'Source Han Sans CN VF';
  367. font-weight: 700;
  368. position: relative;
  369. text-align: center;
  370. .arrow-left {
  371. position: absolute;
  372. left: 32rpx;
  373. margin-right: 12rpx;
  374. }
  375. }
  376. .time-container{
  377. display: flex;
  378. justify-content: center;
  379. align-items: center;
  380. color: #999999;
  381. border-radius: 8rpx;
  382. background:#F6F8FC;
  383. gap: 12rpx;
  384. .start-time{
  385. width: 250rpx;
  386. height: 50rpx;
  387. line-height: 50rpx;
  388. text-align: left;
  389. font-size: 24rpx;
  390. color: #999999;
  391. font-family: 'Source Han Sans CN VF';
  392. border-radius: 16rpx;
  393. padding: 0 24rpx;
  394. }
  395. .end-time{
  396. width: 200rpx;
  397. height: 50rpx;
  398. line-height: 50rpx;
  399. text-align: left;
  400. font-size: 24rpx;
  401. color: #999999;
  402. font-family: 'Source Han Sans CN VF';
  403. border-radius: 16rpx;
  404. padding: 0 24rpx;
  405. }
  406. }
  407. .device-detail__body {
  408. width: calc(100% - 64rpx);
  409. margin: 0 auto;
  410. border-radius: 16rpx;
  411. overflow-x: hidden;
  412. overflow-y: auto;
  413. // 隐藏滚动条
  414. -ms-overflow-style: none;
  415. scrollbar-width: none;
  416. }
  417. .tabs {
  418. margin: 24rpx 0;
  419. border-radius: 16rpx;
  420. padding: 16rpx 0;
  421. padding-top: 0;
  422. .tab-container{
  423. display: flex;
  424. width: 100%;
  425. height: 88rpx;
  426. line-height: 88rpx;
  427. text-align: center;
  428. font-size: 28rpx;
  429. color: #042118;
  430. font-family: 'Source Han Sans CN VF';
  431. }
  432. .tab-item {
  433. margin-right: 40rpx;
  434. color:#999999;
  435. }
  436. .active{
  437. position: relative;
  438. color: #0bbc58;
  439. text-align: center;
  440. font-family: "Source Han Sans CN VF";
  441. font-size: 28rpx;
  442. font-weight: 700;
  443. &::after {
  444. content: '';
  445. position: absolute;
  446. bottom: 10rpx;
  447. left: 50%;
  448. transform: translateX(-50%);
  449. width: 100%;
  450. height: 36rpx;
  451. border-bottom: 6rpx solid #0bbc58;
  452. }
  453. }
  454. }
  455. .device-detail-content{
  456. display: flex;
  457. padding: 24rpx 32rpx;
  458. flex-direction: column;
  459. align-items: flex-start;
  460. gap: 20rpx;
  461. border-radius: 16rpx;
  462. background: #FFF;
  463. .device-detail-item{
  464. .device-detail-label{
  465. color: #303133;
  466. font-family: "Source Han Sans CN VF";
  467. font-size: 28rpx;
  468. font-weight: 400;
  469. }
  470. .device-detail-btn-container{
  471. display: flex;
  472. gap: 24rpx;
  473. margin-top: 12rpx;
  474. }
  475. .device-detail-btn{
  476. display: flex;
  477. padding: 10rpx 16rpx;
  478. justify-content: center;
  479. align-items: center;
  480. gap: 16rpx;
  481. border-radius: 16rpx;
  482. background: #0bbc58;
  483. color: #ffffff;
  484. font-family: "Source Han Sans CN VF";
  485. font-size: 24rpx;
  486. font-weight: 400;
  487. }
  488. .force-btn{
  489. background: #FB4E52;
  490. }
  491. }
  492. .device-detail-viewImage{
  493. width: 100%;
  494. display: flex;
  495. align-items: center;
  496. padding-bottom: 20rpx;
  497. position: relative;
  498. .clear-btn{
  499. position: absolute;
  500. right: 0rpx;
  501. border: 1rpx solid #0bbc58;
  502. border-radius: 8rpx;
  503. padding: 4rpx 12rpx;
  504. font-size: 24rpx;
  505. color: #0bbc58;
  506. font-family: 'Source Han Sans CN VF';
  507. font-weight: 400;
  508. }
  509. }
  510. }
  511. .slider-container{
  512. position: relative;
  513. margin-bottom: 20rpx;
  514. .slider-min-value{
  515. position: absolute;
  516. left: 0;
  517. top: -50rpx;
  518. }
  519. .slider{
  520. width: 600rpx;
  521. }
  522. .slider-max-value{
  523. position: absolute;
  524. right: 0;
  525. top: -50rpx;
  526. }
  527. }
  528. .device-detail-btn-footer{
  529. position: fixed;
  530. bottom: 0;
  531. left: 0;
  532. width: 100%;
  533. height: 112rpx;
  534. line-height: 112rpx;
  535. text-align: center;
  536. font-size: 28rpx;
  537. font-weight: 700;
  538. color: #042118;
  539. font-family: 'Source Han Sans CN VF';
  540. background: #ffffff;
  541. display: flex;
  542. justify-content: center;
  543. align-items: center;
  544. .device-detail-btn{
  545. display: flex;
  546. height: 80rpx;
  547. width: 90%;
  548. margin: 0 auto;
  549. padding: 0rpx 20rpx;
  550. justify-content: center;
  551. align-items: center;
  552. gap: 8rpx;
  553. border-radius: 16rpx;
  554. background:#0bbc58;
  555. color: #ffffff;
  556. text-align: center;
  557. font-family: "Source Han Sans CN VF";
  558. font-size: 14px;
  559. font-style: normal;
  560. font-weight: 500;
  561. }
  562. }
  563. }
  564. </style>