set.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. <template>
  2. <view class="container">
  3. <!-- 头部区域 -->
  4. <view class="header">
  5. <u-row>
  6. <u-col span="2">
  7. <view class="status-btn" :class="{ active_btn: communicationLink_set }">Link</view>
  8. </u-col>
  9. <u-col span="2">
  10. <view class="status-btn" :class="{ active_btn: bleConnected }">blue</view>
  11. </u-col>
  12. <u-col span="6" textAlign="left">
  13. <text class="title">长沙亿旭智能</text>
  14. </u-col>
  15. <u-col span="2">
  16. </u-col>
  17. </u-row>
  18. </view>
  19. <!-- 主要内容区域 -->
  20. <view class="main-content">
  21. <!-- 日期时间显示 -->
  22. <view class="datetime-box">
  23. <text class="datetime-text">{{ currentDateTime }}</text>
  24. </view>
  25. <view class="status-indicators">
  26. <!-- 状态指示器 -->
  27. <view class="indicator-row">
  28. <view class="indicator-item" v-for="(item, index) in indicators1" :key="index">
  29. <view class="status-indicator" :class="{ 'active': item.value }"></view>
  30. <text class="indicator-text">{{ item.label }}</text>
  31. </view>
  32. </view>
  33. <view class="indicator-row">
  34. <view class="indicator-item" v-for="(item, index) in indicators2" :key="index">
  35. <view class="status-indicator" :class="{ 'active': item.value }"></view>
  36. <text class="indicator-text">{{ item.label }}</text>
  37. </view>
  38. </view>
  39. </view>
  40. <!-- 传感器读数和控制 -->
  41. <view class="sensor-controls">
  42. <view class="control-item" v-for="(item, index) in sensorControls" :key="index">
  43. <view class="control-label">{{ item.label }}</view>
  44. <view class="control-value">
  45. <u--input
  46. border="none"
  47. v-model="item.value"
  48. ></u--input>
  49. </view>
  50. <view class="control-buttons">
  51. <u-button
  52. v-for="(btn, btnIndex) in item.buttons"
  53. :key="btnIndex"
  54. :plain="true" :hairline="true"
  55. :class="getButtonClass(btn)"
  56. size="mini"
  57. @click="handleButtonClick(btn.text,btn.action)"
  58. >
  59. {{ btn.text }}
  60. </u-button>
  61. </view>
  62. </view>
  63. </view>
  64. </view>
  65. <u-modal :show="confirmShow" title="提示" :content='confirmContent' :showCancelButton=true @cancel="cancel" @confirm="confirm" ></u-modal>
  66. </view>
  67. </template>
  68. <script>
  69. import {writeRegister,heartbeat} from '@/utils/modbus.js';
  70. export default {
  71. data() {
  72. return {
  73. communicationLink_set: false,
  74. communicationTimer_set: null,
  75. selectAction: '',
  76. currentDateTime: '0000-00-00 00:00:00',
  77. currentTab: 0,
  78. rxCount: 0,
  79. txCount: 0,
  80. confirmShow: false,
  81. confirmContent: '是否确定执行该操作?',
  82. workMode: '', // 添加工作模式变量
  83. indicators1: [
  84. {name: 'tilt', label: '倾角', value: false},
  85. {name: 'limit', label: '限位', value: false},
  86. {name: 'overcurrent', label: '过流', value: false}
  87. ],
  88. indicators2: [
  89. {name: 'rtc', label: 'RTC', value: false},
  90. {name: 'wind', label: '大风', value: false},
  91. {name: 'undervoltage', label: '欠压', value: false}
  92. ],
  93. sensorControls: [
  94. {
  95. name: 'sunAltitude',
  96. label: '太阳高度角',
  97. value: '',
  98. buttons: [
  99. {text: '自动', action: 'auto', type: 'primary'}
  100. ]
  101. },
  102. {
  103. name: 'sunAzimuth',
  104. label: '太阳方位角',
  105. value: '',
  106. buttons: [
  107. {text: '手动', action: 'manual', type: 'primary'},
  108. {text: '标定', action: 'calibrate', type: 'primary'}
  109. ]
  110. },
  111. {
  112. name: 'targetAngle',
  113. label: '目标角度',
  114. value: '',
  115. buttons: [
  116. {text: '向东', action: 'east', type: 'primary'},
  117. {text: '放平', action: 'level', type: 'primary'}
  118. ]
  119. },
  120. {
  121. name: 'angle1',
  122. label: '角度1',
  123. value: '',
  124. buttons: [
  125. {text: '向西', action: 'west', type: 'primary'},
  126. {text: '雪', action: 'snow', type: 'primary'}
  127. ]
  128. },
  129. {
  130. name: 'angle2',
  131. label: '角度2',
  132. value: '',
  133. buttons: [
  134. {text: '雨', action: 'rain', type: 'primary'},
  135. {text: '风', action: 'wind', type: 'primary'}
  136. ]
  137. },
  138. {
  139. name: 'motor1Current',
  140. label: '电机1电流(A)',
  141. value: '',
  142. buttons: []
  143. },
  144. {
  145. name: 'motor2Current',
  146. label: '电机2电流(A)',
  147. value: '',
  148. buttons: []
  149. },
  150. {
  151. name: 'temperature',
  152. label: '温度(°)',
  153. value: '',
  154. buttons: []
  155. },
  156. {
  157. name: 'voltage',
  158. label: '电压(V)',
  159. value: '',
  160. buttons: [
  161. {text: '校正时间', action: 'calibrateTime', type: 'primary', number: 1}
  162. ]
  163. }
  164. ]
  165. }
  166. },
  167. computed: {
  168. bleConnected() {
  169. return this.$store.getters['ble/connected']
  170. },
  171. bleData() {
  172. return this.$store.getters['ble/data']
  173. }
  174. },
  175. watch: {
  176. bleData: {
  177. handler(newData, oldData) {
  178. if (newData) {
  179. console.log('newData:', newData)
  180. // 清除之前的定时器
  181. if (this.communicationTimer_set) {
  182. clearTimeout(this.communicationTimer_set)
  183. this.communicationTimer_set = null
  184. }
  185. // 设置通信链接状态为 true
  186. this.communicationLink_set = true
  187. this.updateSensorData(newData)
  188. }
  189. },
  190. deep: true,
  191. immediate: true
  192. }
  193. },
  194. methods: {
  195. cancel(){
  196. this.confirmShow = false
  197. },
  198. confirm() {
  199. switch (this.selectAction) {
  200. case 'auto': // 自动
  201. writeRegister("READ_AUTO",null);
  202. break
  203. case 'manual': // 手动
  204. writeRegister("READ_MANUAL",null)
  205. break
  206. case 'calibrate': // 标定
  207. // writeRegister("WRITE_REGISTER",null)
  208. break
  209. case 'east': // 向东
  210. writeRegister("READ_DOWN",null)
  211. break
  212. case 'level': // 放平
  213. writeRegister("FLATTEN",null)
  214. break
  215. case 'west': // 向西
  216. writeRegister("READ_UP",null)
  217. break
  218. case 'snow': // 雪
  219. writeRegister("SNOW",null)
  220. break
  221. case 'rain': // 雨
  222. writeRegister("RAIN",null)
  223. break
  224. case 'wind': // 风
  225. writeRegister("WIND",null)
  226. break
  227. case 'calibrateTime': // 校正时间
  228. writeRegister("READ_TIME",this.getCurrentTimeValues())
  229. break
  230. case 'cancel': //取消
  231. writeRegister("READ_CANCEL",null)
  232. }
  233. this.confirmShow = false;
  234. uni.showToast({
  235. title: '操作执行成功!',
  236. icon: 'success',
  237. duration: 2000
  238. });
  239. },
  240. handleButtonClick(text,action) {
  241. console.log(action)
  242. this.selectAction = action;
  243. this.confirmContent = `是否确定执行`+text+`相关的操作?`;
  244. this.confirmShow = true;
  245. },
  246. // 获取按钮的class
  247. getButtonClass(btn) {
  248. // 建立action与工作模式的映射关系
  249. const actionToModeMap = {
  250. 'auto': '自动',
  251. 'manual': '手动',
  252. 'level': '放平',
  253. 'snow': '雪',
  254. 'rain': '雨',
  255. 'wind': '风',
  256. 'east':'向东',
  257. 'west':'向西',
  258. };
  259. let classes = ['btn-broder'];
  260. // 添加宽度类
  261. if (btn.number == 1) {
  262. classes.push('one-btn');
  263. }
  264. // 如果是工作模式按钮且与当前工作模式匹配,则添加绿色背景类
  265. if (actionToModeMap[btn.action] && this.workMode === actionToModeMap[btn.action]) {
  266. classes.push('active-work-mode');
  267. }
  268. return classes;
  269. },
  270. updateSensorData(data) {
  271. // 根据蓝牙数据更新传感器值
  272. this.sensorControls.forEach(control => {
  273. switch (control.name) {
  274. case 'sunAltitude': // 太阳高度角
  275. if (data.qEleAngle_53 !== undefined) {
  276. control.value = data.qEleAngle_53
  277. }
  278. break
  279. case 'sunAzimuth': // 太阳方位角
  280. if (data.qAzimuth_54 !== undefined) {
  281. control.value = data.qAzimuth_54
  282. }
  283. break
  284. case 'targetAngle': // 目标角度
  285. if (data.qTargetAngle_42 !== undefined) {
  286. control.value = data.qTargetAngle_42
  287. }
  288. break
  289. case 'angle1': // 角度1
  290. if (data.qRealAngle_43 !== undefined) {
  291. control.value = data.qRealAngle_43
  292. }
  293. break
  294. case 'angle2': // 角度2
  295. if (data.qRealAngle_31 !== undefined) {
  296. control.value = data.qRealAngle_31
  297. }
  298. break
  299. case 'motor1Current': // 电机1电流
  300. if (data.MotorCurrent_30 !== undefined) {
  301. control.value = data.MotorCurrent_30
  302. }
  303. break
  304. case 'motor2Current': // 电机2电流
  305. if (data.MotorCurrent_35 !== undefined) {
  306. control.value = data.MotorCurrent_35
  307. }
  308. break
  309. case 'temperature': // 温度
  310. if (data.Temperature_33 !== undefined) {
  311. control.value = data.Temperature_33
  312. }
  313. break
  314. case 'voltage': // 电压
  315. if (data.Battery_32 !== undefined) {
  316. control.value = data.Battery_32
  317. }
  318. break
  319. }
  320. })
  321. console.log('WorkModle_41:',data.WorkModle_41);
  322. // 根据C++中的工作模式解析逻辑更新workMode
  323. if (data.WorkModle_41 !== undefined) {
  324. const workModeBits = data.WorkModle_41.toString();
  325. switch (workModeBits) {
  326. case "100000": // 自动
  327. this.workMode = '自动'
  328. break
  329. case "10000": // 手动
  330. this.workMode = '手动'
  331. break
  332. case "1000000": // 放平
  333. this.workMode = '放平'
  334. break
  335. case "1000000000": // 雨
  336. this.workMode = '雨'
  337. break
  338. case "100000000": // 雪
  339. this.workMode = '雪'
  340. break
  341. case "10000000000": // 风
  342. this.workMode = '风'
  343. break
  344. case "10000000": // 指定
  345. this.workMode = '指定'
  346. break
  347. case "11000": // 向东
  348. this.workMode = '向东'
  349. break
  350. case "10100": // 向西
  351. this.workMode = '向西'
  352. break
  353. default:
  354. this.workMode = '未知模式'
  355. break
  356. }
  357. }
  358. if (data.Message_40 !== undefined) {
  359. // 根据二进制字符串更新指示器状态
  360. const messageBits = data.Message_40.toString()
  361. console.log('messageBits:',messageBits)
  362. // 清除所有状态
  363. this.indicators1.forEach(item => item.value = false)
  364. this.indicators2.forEach(item => item.value = false)
  365. // 根据实际协议确定位的含义
  366. if(messageBits === "100") {
  367. this.indicators1[0].value = true // 倾角
  368. } else if(messageBits === "10") {
  369. this.indicators1[2].value = true // 过流
  370. } else if(messageBits === "1") {
  371. this.indicators1[1].value = true // 限位
  372. } else if(messageBits === "110") {
  373. this.indicators1[2].value = true // 过流
  374. this.indicators1[1].value = true // 限位
  375. } else if(messageBits === "101") {
  376. this.indicators1[0].value = true // 倾角
  377. this.indicators1[2].value = true // 过流
  378. } else if(messageBits === "11") {
  379. this.indicators1[1].value = true // 限位
  380. this.indicators1[2].value = true // 过流
  381. } else if(messageBits === "111") {
  382. this.indicators1[0].value = true // 倾角
  383. this.indicators1[1].value = true // 限位
  384. this.indicators1[2].value = true // 过流
  385. }
  386. }
  387. // 更新时间显示
  388. if (data.nowtime !== undefined) {
  389. this.currentDateTime = data.nowtime
  390. }
  391. // 设置6秒后将 communicationLink_set 设置为 false 的定时器
  392. this.communicationTimer_set = setTimeout(() => {
  393. this.communicationLink_set = false
  394. this.communicationTimer_set = null
  395. }, 5000)
  396. },
  397. getCurrentTimeValues(){
  398. const now = new Date();
  399. // 获取各个时间组件
  400. const year = now.getFullYear(); // 年份 (例如: 2024)
  401. const month = now.getMonth() + 1; // 月份 (0-11, 需要+1变为1-12)
  402. const day = now.getDate(); // 日期 (1-31)
  403. const hours = now.getHours(); // 小时 (0-23)
  404. const minutes = now.getMinutes(); // 分钟 (0-59)
  405. const seconds = now.getSeconds(); // 秒 (0-59)
  406. // 返回时间值数组,每个值都是16位整数
  407. return [
  408. year, // 年
  409. month, // 月
  410. day, // 日
  411. hours, // 时
  412. minutes, // 分
  413. seconds // 秒
  414. ];
  415. }
  416. }
  417. }
  418. </script>
  419. <style lang="scss" scoped>
  420. .container {
  421. background-color: #f5f5f5;
  422. height: calc(100vh - 120px);
  423. display: flex;
  424. flex-direction: column;
  425. }
  426. .header {
  427. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  428. padding: 20rpx;
  429. .link-btn {
  430. background-color: #ff4757;
  431. border: none;
  432. width: 60px;
  433. margin-left: 0px;
  434. }
  435. .title {
  436. color: #fff;
  437. font-size: 36rpx;
  438. font-weight: bold;
  439. }
  440. .status-btn {
  441. background-color: #ff4757;
  442. border: none;
  443. margin-left: 0px;
  444. padding: 0px;
  445. width: 40px;
  446. text-align: center;
  447. color: white;
  448. border-radius: 4px;
  449. height: 20px;
  450. line-height: 20px;
  451. }
  452. .active_btn {
  453. background-color: yellowgreen !important;
  454. }
  455. }
  456. .main-content {
  457. flex: 1;
  458. padding: 20rpx;
  459. }
  460. .work-mode-display {
  461. background-color: #fff;
  462. padding: 20rpx;
  463. border-radius: 16rpx;
  464. margin-bottom: 20rpx;
  465. text-align: center;
  466. .work-mode-text {
  467. font-size: 28rpx;
  468. font-weight: bold;
  469. color: #333;
  470. }
  471. }
  472. .datetime-box {
  473. background-color: #fff;
  474. padding: 30rpx;
  475. border-radius: 16rpx;
  476. margin-bottom: 20rpx;
  477. text-align: center;
  478. .datetime-text {
  479. font-size: 32rpx;
  480. font-weight: bold;
  481. color: #333;
  482. }
  483. }
  484. .status-indicators {
  485. background-color: #fff;
  486. padding: 20rpx;
  487. border-radius: 16rpx;
  488. margin-bottom: 20rpx;
  489. .indicator-row {
  490. display: flex;
  491. justify-content: space-around;
  492. align-items: center;
  493. margin-bottom: 20rpx;
  494. &:last-child {
  495. margin-bottom: 0;
  496. }
  497. }
  498. .indicator-item {
  499. display: flex;
  500. align-items: center;
  501. justify-content: center;
  502. flex: 1;
  503. text-align: center;
  504. gap: 10rpx;
  505. }
  506. .indicator-text {
  507. font-size: 24rpx;
  508. color: #666;
  509. }
  510. }
  511. .sensor-controls {
  512. background-color: #fff;
  513. border-radius: 16rpx;
  514. overflow: auto;
  515. height: calc(100% - 220rpx);
  516. .control-item {
  517. display: flex;
  518. align-items: center;
  519. padding: 20rpx;
  520. border-bottom: 1rpx solid #f0f0f0;
  521. &:last-child {
  522. border-bottom: none;
  523. }
  524. }
  525. .control-label {
  526. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  527. color: #fff;
  528. padding: 10rpx 20rpx;
  529. border-radius: 8rpx;
  530. font-size: 24rpx;
  531. width: 240rpx;
  532. text-align: center;
  533. margin-right: 20rpx;
  534. }
  535. .control-value {
  536. background-color: #f8f9fa;
  537. padding: 10rpx 20rpx;
  538. border-radius: 8rpx;
  539. font-size: 28rpx;
  540. font-weight: bold;
  541. color: #333;
  542. width: 140rpx;
  543. height: 60rpx;
  544. text-align: center;
  545. margin-right: 20rpx;
  546. }
  547. .control-buttons {
  548. display: flex;
  549. gap: 20rpx;
  550. }
  551. .u-button--mini {
  552. width: 120rpx;
  553. }
  554. }
  555. .one-btn {
  556. width: 240rpx !important;
  557. }
  558. .btn-broder {
  559. border: 1rpx solid #dadbde;
  560. }
  561. // 活跃的工作模式按钮样式
  562. .active-work-mode {
  563. background-color: #00ff00 !important; // 绿色背景
  564. color: #000 !important;
  565. border-color: #00ff00 !important;
  566. }
  567. .status-indicator {
  568. width: 20rpx;
  569. height: 20rpx;
  570. border-radius: 50%;
  571. background-color: #ccc;
  572. margin-right: 10rpx;
  573. &.active {
  574. background-color: red;
  575. }
  576. }
  577. </style>