index.vue 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. <template>
  2. <!--
  3. <headerBar
  4. title="遥控模拟器"
  5. />-->
  6. <div class="remote-control_main-container">
  7. <div class="te-c" style="color: #8C92A7">遥控器模拟器</div>
  8. <el-row align="middle" class="mar-top-20">
  9. <el-col :span="3"></el-col>
  10. <el-col :span="6"><div class="button up" title="单击鼠标右键可切换配置" @click="runLeft" @contextmenu="handleLeftRightClick($event, 'left')">左脚</div></el-col>
  11. <el-col :span="6"><div class="button up" @click="run_take_picture">拍照</div></el-col>
  12. <el-col :span="6"><div class="button up" title="单击鼠标右键可切换配置" @click="runRight" @contextmenu="handleLeftRightClick($event, 'right')">右脚</div></el-col>
  13. <el-col :span="3"></el-col>
  14. </el-row>
  15. <el-row align="middle" >
  16. <el-col :span="3"></el-col>
  17. <el-col :span="6"><div class="button up" @click="handleLeftRightClick($event, 'left')"><span style="font-size: 12px;">左脚配置</span></div></el-col>
  18. <el-col :span="6"></el-col>
  19. <el-col :span="6"><div class="button up" @click="handleLeftRightClick($event, 'right')"><span style="font-size: 12px;">右脚配置</span></div></el-col>
  20. <el-col :span="3"></el-col>
  21. </el-row>
  22. <el-row align="middle">
  23. <el-col :span="3"></el-col>
  24. <el-col :span="6">
  25. <div class="button up" @click="switchLED(1)" v-log="{ describe: { action: 'LED开启' } }">LED开</div>
  26. </el-col>
  27. <el-col :span="6">
  28. <div class="button up" @click="switchLED(0)" v-log="{ describe: { action: 'LED关闭' } }">LED关</div>
  29. </el-col>
  30. <el-col :span="6">
  31. <div class="button up" :class="{ disabled: !canStop }" @click="oneClickStop" v-log="{ describe: { action: '一键停止拍摄' } }">停止</div>
  32. </el-col>
  33. <el-col :span="3"></el-col>
  34. </el-row>
  35. <!-- 左脚配置菜单 -->
  36. <div v-if="showLeftMenu" class="context-menu" :style="{ left: menuPosition.x + 'px', top: menuPosition.y + 'px' }" @click.stop>
  37. <div class="menu-title">左脚配置</div>
  38. <div class="menu-items">
  39. <div
  40. v-for="tab in leftTabs"
  41. :key="tab.id"
  42. class="menu-item"
  43. :class="{ active: leftConfigId === tab.id }"
  44. @click="selectConfig('left', tab.id)"
  45. >
  46. {{ leftConfigId === tab.id ? '✓ ' : '' }}{{ tab.mode_name }}
  47. </div>
  48. </div>
  49. </div>
  50. <!-- 右脚配置菜单 -->
  51. <div v-if="showRightMenu" class="context-menu" :style="{ left: menuPosition.x + 'px', top: menuPosition.y + 'px' }" @click.stop>
  52. <div class="menu-title">右脚配置</div>
  53. <div class="menu-items">
  54. <div
  55. v-for="tab in rightTabs"
  56. :key="tab.id"
  57. class="menu-item"
  58. :class="{ active: rightConfigId === tab.id }"
  59. @click="selectConfig('right', tab.id)"
  60. >
  61. {{ rightConfigId === tab.id ? '✓ ' : '' }}{{ tab.mode_name }}
  62. </div>
  63. </div>
  64. </div>
  65. <!-- 点击其他地方关闭菜单 -->
  66. <div v-if="showLeftMenu || showRightMenu" class="menu-overlay" @click="closeMenus"></div>
  67. </div>
  68. </template>
  69. <script setup lang="ts">
  70. import { defineEmits, defineProps, ref } from 'vue'
  71. import socket from "@/stores/modules/socket";
  72. import { getTopTabs, setLeftRightConfig } from '@/apis/setting';
  73. import { ElMessage } from 'element-plus';
  74. // 初始化 WebSocket 状态管理
  75. const socketStore = socket()
  76. const props = defineProps<{
  77. canStop: boolean
  78. }>()
  79. const emit = defineEmits(['onRemoteControl'])
  80. // 配置切换相关
  81. const leftConfigId = ref(0)
  82. const rightConfigId = ref(0)
  83. const leftTabs = ref([]) // 左脚配置选项
  84. const rightTabs = ref([]) // 右脚配置选项
  85. const showLeftMenu = ref(false) // 显示左脚菜单
  86. const showRightMenu = ref(false) // 显示右脚菜单
  87. const menuPosition = ref({ x: 0, y: 0 }) // 菜单位置
  88. const runLeft = async () => {
  89. emit('onRemoteControl','left')
  90. }
  91. const runRight = async () => {
  92. emit('onRemoteControl','right')
  93. }
  94. const run_take_picture = () => {
  95. emit('onRemoteControl','take_picture')
  96. }
  97. //LED
  98. const switchLED = async (value) => {
  99. socketStore.sendMessage({
  100. type: 'control_mcu',
  101. data: {
  102. device_name: "laser_position",
  103. value,
  104. }
  105. });
  106. }
  107. // 一键停止
  108. const oneClickStop = () => {
  109. if (!props.canStop) {
  110. return
  111. }
  112. socketStore.sendMessage({
  113. type: 'stop_action',
  114. })
  115. }
  116. // 右击左脚按钮
  117. const handleLeftRightClick = (event, type) => {
  118. event.preventDefault()
  119. menuPosition.value = { x: event.clientX, y: event.clientY }
  120. if (type === 'left') {
  121. showLeftMenu.value = true
  122. showRightMenu.value = false
  123. loadLeftConfig()
  124. } else {
  125. showRightMenu.value = true
  126. showLeftMenu.value = false
  127. loadRightConfig()
  128. }
  129. }
  130. // 加载左脚配置
  131. const loadLeftConfig = async () => {
  132. try {
  133. const result = await getTopTabs({ type: 0 })
  134. if (result.code === 0) {
  135. leftConfigId.value = result.data.select_configs.left
  136. leftTabs.value = result.data.tabs
  137. }
  138. } catch (error) {
  139. console.error('加载左脚配置失败:', error)
  140. }
  141. }
  142. // 加载右脚配置
  143. const loadRightConfig = async () => {
  144. try {
  145. const result = await getTopTabs({ type: 1 })
  146. if (result.code === 0) {
  147. rightConfigId.value = result.data.select_configs.right
  148. rightTabs.value = result.data.tabs
  149. }
  150. } catch (error) {
  151. console.error('加载右脚配置失败:', error)
  152. }
  153. }
  154. // 选择配置
  155. const selectConfig = async (type, configId) => {
  156. try {
  157. const result = await setLeftRightConfig({
  158. type: type,
  159. id: configId
  160. })
  161. if (result.code === 0) {
  162. if (type === 'left') {
  163. leftConfigId.value = configId
  164. showLeftMenu.value = false
  165. } else {
  166. rightConfigId.value = configId
  167. showRightMenu.value = false
  168. }
  169. ElMessage.success('配置切换成功')
  170. }
  171. } catch (error) {
  172. console.error('切换配置失败:', error)
  173. ElMessage.error('配置切换失败')
  174. }
  175. }
  176. // 关闭菜单
  177. const closeMenus = () => {
  178. showLeftMenu.value = false
  179. showRightMenu.value = false
  180. }
  181. </script>
  182. <style scoped lang="scss">
  183. .remote-control_main-container {
  184. background: #EAECED;
  185. height: 450px;
  186. width: 300px;
  187. margin: 0 auto;
  188. margin-top: 10px;
  189. padding-top: 30px;
  190. background: url(@/assets/images/Photography/yk.png) 0px 0px no-repeat;
  191. background-size: 300px 450px;
  192. }
  193. .button {
  194. width: 60px;
  195. height: 60px;
  196. background: #fff;
  197. border-radius: 60px;
  198. line-height: 60px;
  199. color: #474747;
  200. margin: 0 auto;
  201. box-shadow: 0 2px 8px 0 rgba(0,0,0,0.2);
  202. background: url(@/assets/images/Photography/hui.png) 0px 0px no-repeat;
  203. background-size: 60px 60px;
  204. }
  205. .el-row {
  206. min-height: 100px;
  207. }
  208. .button:hover {
  209. background: url(@/assets/images/Photography/lan.png) 0px 0px no-repeat;
  210. background-size: 60px 60px;
  211. cursor: pointer;
  212. }
  213. .button.stop {
  214. background: #ff4c00;
  215. color: white;
  216. border-radius: 10px;
  217. width: 120px;
  218. height: 40px;
  219. line-height: 40px;
  220. font-size: 14px;
  221. margin: 0 auto;
  222. }
  223. .button.stop:hover {
  224. background: #e64500;
  225. }
  226. .button.disabled {
  227. opacity: 0.5;
  228. cursor: not-allowed;
  229. pointer-events: none;
  230. }
  231. .context-menu {
  232. position: fixed;
  233. background: white;
  234. border: 1px solid #e4e7ed;
  235. border-radius: 4px;
  236. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  237. z-index: 2000;
  238. min-width: 120px;
  239. max-width: 200px;
  240. }
  241. .menu-title {
  242. padding: 8px 12px;
  243. font-size: 12px;
  244. font-weight: 600;
  245. color: #606266;
  246. border-bottom: 1px solid #ebeef5;
  247. background-color: #f5f7fa;
  248. }
  249. .menu-items {
  250. max-height: 250px;
  251. overflow: auto;
  252. }
  253. .menu-item {
  254. padding: 8px 12px;
  255. font-size: 14px;
  256. color: #606266;
  257. cursor: pointer;
  258. transition: background-color 0.2s;
  259. &:hover {
  260. background-color: #f5f7fa;
  261. }
  262. &.active {
  263. color: #2957FF;
  264. font-weight: 600;
  265. }
  266. }
  267. .menu-overlay {
  268. position: fixed;
  269. top: 0;
  270. left: 0;
  271. right: 0;
  272. bottom: 0;
  273. z-index: 1999;
  274. }
  275. </style>