record.vue 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  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 }">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. <view class="main-content">
  20. <!-- 接收窗口 -->
  21. <view class="receive-section">
  22. <text class="section-title">接收窗口</text>
  23. <view class="receive-window">
  24. <scroll-view scroll-y="true" class="receive-textarea">
  25. <view
  26. v-for="(log, index) in sortedWriteLogs"
  27. :key="index"
  28. class="log-item"
  29. >
  30. <view class="log-time">{{log.time}}{{log.data}}</view>
  31. </view>
  32. </scroll-view>
  33. </view>
  34. </view>
  35. <!-- 输入控制区域 -->
  36. <view class="input-section">
  37. <u-row customStyle="margin-bottom: 10px" gutter="10">
  38. <u-col span="8">
  39. <u-input
  40. v-model="inputValue"
  41. placeholder="输入指令"
  42. class="command-input"
  43. ></u-input>
  44. </u-col>
  45. <u-col span="4">
  46. <u-checkbox-group
  47. placement="column">
  48. <u-checkbox v-model="cmdChecked" label="cmd" @change="changeCmd"></u-checkbox>
  49. </u-checkbox-group>
  50. </u-col>
  51. </u-row>
  52. <!-- 操作按钮 -->
  53. <u-row justify="end" customStyle="margin-bottom: 10px">
  54. <u-col span="4">
  55. <u-button type="info" size="mini" class="write-btn" @click="sendMsg">指令发送</u-button>
  56. </u-col>
  57. </u-row>
  58. <u-row customStyle="margin-bottom: 10px" gutter="10">
  59. <u-col span="6">
  60. <u-button text="清空发送" @click="removeLogsByType('rx')"></u-button>
  61. </u-col>
  62. <u-col span="6">
  63. <u-button text="清空接受" @click="removeLogsByType('tx')"></u-button>
  64. </u-col>
  65. </u-row>
  66. </view>
  67. </view>
  68. </view>
  69. </template>
  70. <script>
  71. import ecBLEApp from '@/utils/ecBLE/ecBLEApp.js'
  72. import UniDataPickerView
  73. from "../../../uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue";
  74. export default {
  75. components: {UniDataPickerView},
  76. data() {
  77. return {
  78. communicationLink: false,
  79. communicationTimer_3: null, // 添加这一行用于保存定时器 ID
  80. writeLogs: [],
  81. showSex: false,
  82. checkboxValue1: [],
  83. inputValue: '',
  84. cmdChecked: false,
  85. carriageReturnChecked: false,
  86. wtypeValue: '',
  87. wtypeChecked: false,
  88. componentType: '单面',
  89. activeTab: 'receive',
  90. componentList: [
  91. { name: '单面'},
  92. { name: '双面'},
  93. { name: '多面'}
  94. ]
  95. }
  96. },
  97. onShow() {
  98. // 从全局变量加载日志
  99. this.writeLogs = ecBLEApp.getGlobalWriteLogs()
  100. // 添加监听器以实时更新
  101. ecBLEApp.addLogListener(this.onLogUpdate)
  102. },
  103. onHide() {
  104. // 移除监听器
  105. ecBLEApp.removeLogListener(this.onLogUpdate)
  106. },
  107. computed: {
  108. bleConnected() {
  109. return this.$store.getters['ble/connected']
  110. },
  111. bleData() {
  112. return this.$store.getters['ble/data']
  113. },
  114. // 修改排序计算属性
  115. sortedWriteLogs() {
  116. return this.writeLogs.slice().sort((a, b) => {
  117. return new Date(b.time) - new Date(a.time); // 倒序排列
  118. });
  119. }
  120. },
  121. watch: {
  122. bleData: {
  123. handler(newData, oldData) {
  124. if (newData) {
  125. console.log('接收到蓝牙数据:', newData)
  126. // 清除之前的定时器
  127. if (this.communicationTimer_3) {
  128. clearTimeout(this.communicationTimer_3)
  129. this.communicationTimer_3 = null
  130. }
  131. // 设置通信链接状态为 true
  132. this.communicationLink = true
  133. this.updateSensorData(newData)
  134. // 设置6秒后将 communicationLink 设置为 false 的定时器
  135. this.communicationTimer_3 = setTimeout(() => {
  136. this.communicationLink = false
  137. this.communicationTimer_3 = null
  138. }, 5000)
  139. }
  140. },
  141. deep: true, // 深度监听,确保嵌套对象变化时也能触发
  142. immediate: true // 立即执行一次
  143. }
  144. },
  145. methods: {
  146. updateSensorData(data) {
  147. },
  148. sendMsg(){
  149. uni.showModal({
  150. title: '提示',
  151. content: `是否确定发送消息`+this.inputValue+`?`,
  152. success: (res) => {
  153. if (res.confirm) {
  154. ecBLEApp.writeBLECharacteristicValueTwo(this.inputValue,!this.cmdChecked);
  155. }
  156. }
  157. });
  158. },
  159. changeCmd(e) {
  160. this.cmdChecked = e
  161. },
  162. changeWtype(e){
  163. this.wtypeChecked = e
  164. },
  165. // 日志更新回调
  166. onLogUpdate(logs) {
  167. // this.writeLogs = [...logs] // 创建新数组以触发响应式更新
  168. this.writeLogs.splice(0, this.writeLogs.length, ...logs)
  169. },
  170. loadLogs() {
  171. // 从全局变量获取日志
  172. const newLogs = ecBLEApp.getGlobalWriteLogs()
  173. // 使用数组变更方法保持响应式
  174. this.writeLogs.splice(0, this.writeLogs.length, ...newLogs)
  175. },
  176. selectValue(e) {
  177. this.componentType = e.name
  178. },
  179. switchTab(tab) {
  180. this.activeTab = tab;
  181. },
  182. sendCommand() {
  183. // 发送指令逻辑
  184. console.log('发送指令:', this.inputValue);
  185. },
  186. writeType() {
  187. // 类型写入逻辑
  188. console.log('写入类型:', this.wtypeValue);
  189. },
  190. clearSend() {
  191. this.inputValue = '';
  192. },
  193. clearReceive() {
  194. // 清空接收窗口
  195. console.log('清空接收窗口');
  196. },
  197. removeLogsByType(type) {
  198. uni.showModal({
  199. title: '确认删除',
  200. content: `确定要删除所有类型为 '${type}' 的日志吗?`,
  201. success: (res) => {
  202. if (res.confirm) {
  203. const result = ecBLEApp.removeWriteDataByType(type)
  204. if (result.success) {
  205. uni.showToast({
  206. title: `已删除${result.deletedCount}条日志`,
  207. icon: 'success'
  208. })
  209. // 重新加载日志
  210. this.loadLogs();
  211. console.log('删除日志结果:', result)
  212. console.log(this.writeLogs)
  213. } else {
  214. uni.showToast({
  215. title: '删除失败',
  216. icon: 'none'
  217. })
  218. }
  219. }
  220. }
  221. })
  222. },
  223. }
  224. }
  225. </script>
  226. <style lang="scss" >
  227. @import '@/static/scss/custom-theme.scss';
  228. .container {
  229. height: calc(100vh - 120px);
  230. display: flex;
  231. flex-direction: column;
  232. background-color: #f5f5f5;
  233. }
  234. .header {
  235. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  236. padding: 20rpx;
  237. .link-btn {
  238. background-color: #ff4757;
  239. border: none;
  240. width: 60px;
  241. margin-left: 0px;
  242. }
  243. .title {
  244. color: #fff;
  245. font-size: 36rpx;
  246. font-weight: bold;
  247. }
  248. .status-btn {
  249. background-color: #ff4757;
  250. border: none;
  251. margin-left: 0px;
  252. padding: 0px;
  253. width: 40px;
  254. text-align: center;
  255. color: white;
  256. border-radius: 4px;
  257. height: 20px;
  258. line-height: 20px;
  259. }
  260. .active_btn {
  261. background-color: yellowgreen !important;
  262. }
  263. }
  264. .status-bar {
  265. height: 60rpx;
  266. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  267. display: flex;
  268. align-items: center;
  269. justify-content: space-between;
  270. padding: 0 20rpx;
  271. color: white;
  272. font-size: 24rpx;
  273. }
  274. .status-left {
  275. display: flex;
  276. align-items: center;
  277. gap: 20rpx;
  278. }
  279. .status-center {
  280. flex: 1;
  281. text-align: center;
  282. }
  283. .app-title {
  284. font-size: 32rpx;
  285. font-weight: bold;
  286. }
  287. .status-right {
  288. display: flex;
  289. align-items: center;
  290. gap: 10rpx;
  291. }
  292. .network-info {
  293. font-size: 20rpx;
  294. }
  295. .signal {
  296. font-size: 20rpx;
  297. }
  298. .signal-bars {
  299. display: flex;
  300. gap: 2rpx;
  301. }
  302. .bar {
  303. width: 4rpx;
  304. height: 12rpx;
  305. background-color: white;
  306. border-radius: 1rpx;
  307. }
  308. .battery {
  309. font-size: 20rpx;
  310. }
  311. .main-content {
  312. flex: 1;
  313. padding: 20rpx;
  314. background-color: #f5f5f5;
  315. }
  316. .receive-section {
  317. margin-bottom: 30rpx;
  318. }
  319. .section-title {
  320. font-size: 28rpx;
  321. font-weight: bold;
  322. color: #333;
  323. margin-bottom: 10rpx;
  324. display: block;
  325. }
  326. .receive-window {
  327. background-color: white;
  328. border-radius: 10rpx;
  329. border: 2rpx solid #e0e0e0;
  330. height: 40vh;
  331. overflow: auto;
  332. }
  333. .receive-textarea {
  334. height: 100%;
  335. padding: 20rpx;
  336. }
  337. .placeholder-text {
  338. color: #999;
  339. font-size: 24rpx;
  340. }
  341. .input-section {
  342. background-color: white;
  343. border-radius: 10rpx;
  344. padding: 20rpx;
  345. }
  346. .input-row {
  347. display: flex;
  348. align-items: center;
  349. margin-bottom: 20rpx;
  350. gap: 20rpx;
  351. }
  352. .input-group {
  353. display: flex;
  354. align-items: center;
  355. flex: 1;
  356. gap: 10rpx;
  357. }
  358. .command-input, .wtype-input {
  359. flex: 1;
  360. }
  361. .scroll-btn {
  362. width: 60rpx;
  363. height: 60rpx;
  364. }
  365. .checkbox-group {
  366. display: flex;
  367. align-items: center;
  368. }
  369. .send-btn {
  370. width: 120rpx;
  371. }
  372. .component-section {
  373. margin-bottom: 20rpx;
  374. }
  375. .component-select {
  376. width: 100%;
  377. }
  378. .wtype-section {
  379. margin-bottom: 20rpx;
  380. }
  381. .write-btn {
  382. padding: 2px;
  383. color: #a7a7a7;
  384. margin: 5px;
  385. height: 30px;
  386. }
  387. .action-buttons {
  388. display: flex;
  389. gap: 20rpx;
  390. margin-bottom: 20rpx;
  391. }
  392. .clear-btn {
  393. flex: 1;
  394. }
  395. .device-info {
  396. display: flex;
  397. align-items: center;
  398. gap: 10rpx;
  399. margin-bottom: 10px;
  400. }
  401. .info-label {
  402. font-size: 28rpx;
  403. color: #333;
  404. }
  405. .info-value {
  406. font-size: 28rpx;
  407. color: #666;
  408. }
  409. ::v-deep .input-section .u-button--mini{
  410. width: 100px !important;
  411. height: 30px !important;
  412. }
  413. </style>