index.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. <template>
  2. <div class="report-page">
  3. <h2 class="title">Report</h2>
  4. <div class="button-list">
  5. <el-button
  6. v-for="item in tagList"
  7. :key="item.id"
  8. :class="['report-btn', { 'is-active': activeReportItem && activeReportItem.id === item.id }]"
  9. type="primary"
  10. plain
  11. :loading="reportingId === item.id"
  12. @click="onReport(item)"
  13. >
  14. <span class="btn-content">
  15. <span class="btn-name">{{ item.name }}</span>
  16. <span class="btn-id">#{{ item.id }}</span>
  17. </span>
  18. </el-button>
  19. <el-button
  20. class="report-btn stop-btn"
  21. type="danger"
  22. plain
  23. :disabled="!activeReportItem"
  24. @click="onStopReport()"
  25. >
  26. <span class="btn-content">
  27. <span class="btn-name">结束上报</span>
  28. </span>
  29. </el-button>
  30. </div>
  31. <p v-if="activeReportItem" class="status-text">
  32. Reporting: {{ activeReportItem.name }} #{{ activeReportItem.id }} (every 1s)
  33. </p>
  34. <div v-if="lastReportedItem" class="report-result">
  35. <h3>Last Report Payload</h3>
  36. <pre>{{ JSON.stringify(lastReportedItem, null, 2) }}</pre>
  37. </div>
  38. </div>
  39. </template>
  40. <script>
  41. import { ElMessage } from 'element-plus'
  42. import { reportTagInfo } from '@/api.js'
  43. import tagCoordinateList from './tagCoordinateList.json'
  44. export default {
  45. name: 'ReportPage',
  46. data() {
  47. return {
  48. tagList: tagCoordinateList,
  49. reportingId: null,
  50. activeReportItem: null,
  51. lastReportedItem: null,
  52. reportTimer: null,
  53. isRequesting: false,
  54. }
  55. },
  56. beforeUnmount() {
  57. this.clearReportTimer()
  58. },
  59. methods: {
  60. clearReportTimer() {
  61. if (this.reportTimer) {
  62. clearInterval(this.reportTimer)
  63. this.reportTimer = null
  64. }
  65. },
  66. sendReportOnce() {
  67. if (!this.activeReportItem || this.isRequesting) {
  68. return
  69. }
  70. const item = this.activeReportItem
  71. this.reportingId = item.id
  72. this.isRequesting = true
  73. reportTagInfo(item).then(() => {
  74. this.lastReportedItem = item
  75. }).catch((err) => {
  76. ElMessage({
  77. message: err?.message || err || 'report failed',
  78. type: 'error',
  79. })
  80. }).finally(() => {
  81. this.isRequesting = false
  82. this.reportingId = null
  83. })
  84. },
  85. onReport(item) {
  86. const switched = !this.activeReportItem || this.activeReportItem.id !== item.id
  87. this.activeReportItem = item
  88. this.clearReportTimer()
  89. this.sendReportOnce()
  90. this.reportTimer = setInterval(() => {
  91. this.sendReportOnce()
  92. }, 1000)
  93. if (switched) {
  94. // ElMessage({
  95. // message: `start reporting ${item.name} #${item.id}`,
  96. // type: 'success',
  97. // })
  98. }
  99. },
  100. onStopReport() {
  101. this.clearReportTimer()
  102. this.activeReportItem = null
  103. this.reportingId = null
  104. this.isRequesting = false
  105. ElMessage({
  106. message: 'report stopped',
  107. type: 'info',
  108. })
  109. },
  110. },
  111. }
  112. </script>
  113. <style scoped>
  114. .report-page {
  115. padding: calc(12px + env(safe-area-inset-top)) 12px calc(16px + env(safe-area-inset-bottom));
  116. max-width: 920px;
  117. margin: 0 auto;
  118. }
  119. .title {
  120. margin: 0 0 12px;
  121. font-size: 20px;
  122. line-height: 1.2;
  123. }
  124. .button-list {
  125. display: grid;
  126. grid-template-columns: 1fr;
  127. gap: 8px;
  128. }
  129. .report-btn {
  130. width: 100%;
  131. min-height: 42px;
  132. margin: 0;
  133. padding: 8px 10px;
  134. margin-left: 0 !important;
  135. }
  136. .report-btn .btn-content {
  137. display: flex;
  138. align-items: center;
  139. justify-content: space-between;
  140. width: 100%;
  141. text-align: left;
  142. }
  143. .report-btn .btn-name {
  144. font-size: 13px;
  145. line-height: 1.1;
  146. padding-right: 8px;
  147. }
  148. .report-btn .btn-id {
  149. margin-left: 0;
  150. opacity: 0.8;
  151. font-size: 12px;
  152. min-width: 34px;
  153. text-align: right;
  154. }
  155. .report-btn.is-active {
  156. border-color: #409eff;
  157. background-color: #ecf5ff;
  158. }
  159. .stop-btn :deep(span) {
  160. justify-content: center;
  161. }
  162. .status-text {
  163. margin: 10px 0 0;
  164. color: #606266;
  165. font-size: 12px;
  166. }
  167. .report-result {
  168. margin-top: 20px;
  169. }
  170. .report-result pre {
  171. background: #f5f7fa;
  172. padding: 12px;
  173. border-radius: 6px;
  174. overflow-x: auto;
  175. font-size: 12px;
  176. line-height: 1.5;
  177. }
  178. @media (min-width: 640px) {
  179. .report-page {
  180. padding: 20px;
  181. }
  182. .button-list {
  183. grid-template-columns: repeat(2, minmax(0, 1fr));
  184. gap: 10px;
  185. }
  186. .report-btn {
  187. min-height: 40px;
  188. padding: 7px 10px;
  189. }
  190. }
  191. </style>