index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. <template>
  2. <div class="gesture">
  3. <Header :showTool="true" @confirmExit="getLogout" :key="key"></Header>
  4. <div class="menu" v-if="projectList.length" :key="projectList.length">
  5. <swiper
  6. :slides-per-view="5"
  7. :space-between="0"
  8. :loop="true"
  9. :observe-parents="true"
  10. :observer="true"
  11. :centered-slides="true"
  12. :modules="[Navigation]"
  13. @swiper="onSwiper"
  14. >
  15. <swiper-slide v-for="(item, index) in projectList" :key="index" @click="getOption(item)">
  16. <div class="li">
  17. <div>
  18. <div class="pic"><img :src="'static/images/train/' + item.key + '.png'" /></div>
  19. <div class="name">
  20. {{ item.name }}
  21. </div>
  22. </div>
  23. </div>
  24. </swiper-slide>
  25. </swiper>
  26. </div>
  27. <div class="erweima">
  28. <img :src="erweima" />
  29. <span>扫码遥控</span>
  30. </div>
  31. <OptionWindow ref="optionWindowRef" :projectList="projectList" />
  32. </div>
  33. </template>
  34. <script setup name="Gesture" lang="ts">
  35. import { useWebSocket } from '@/utils/handWs';
  36. import { Swiper, SwiperSlide } from 'swiper/vue';
  37. import { Navigation } from 'swiper/modules';
  38. import QRCode from 'qrcode';
  39. import 'swiper/css';
  40. import 'swiper/scss/navigation';
  41. const { handWs, startDevice, startHand, stateHand } = useWebSocket();
  42. const router = useRouter();
  43. const route = useRoute();
  44. const { proxy } = getCurrentInstance() as any;
  45. const optionWindowRef = ref();
  46. const data = reactive<any>({
  47. mySwiper: {},
  48. projectList: [],
  49. timerManager: {},
  50. device_info: {},
  51. erweima: '',
  52. sid: '',
  53. key: 0
  54. });
  55. const { mySwiper, projectList, timerManager, device_info, erweima, sid, key } = toRefs(data);
  56. /**
  57. * 清空定时任务
  58. */
  59. const getClearTimer = (data?: any) => {
  60. if (data) {
  61. //清除指定
  62. clearInterval(timerManager.value[data]);
  63. timerManager.value[data] = null;
  64. } else {
  65. for (let key in timerManager.value) {
  66. if (timerManager.value.hasOwnProperty(key)) {
  67. clearInterval(timerManager.value[key]);
  68. timerManager.value[key] = null;
  69. }
  70. }
  71. }
  72. };
  73. /**
  74. * 初始化项目
  75. */
  76. const getInitExam = () => {
  77. getExam();
  78. //定时刷新
  79. timerManager.value.exam = setInterval(() => {
  80. getExam();
  81. }, 5000);
  82. };
  83. /**
  84. * 获取项目
  85. */
  86. const getExam = async () => {
  87. let myList = device_info.value?.project_list || [];
  88. let examList = myList.map((item: any) => {
  89. return item.exam_name;
  90. });
  91. await proxy?.$http.train.projectList().then((res: any) => {
  92. projectList.value = proxy?.$utils.getProject(res.exams).filter((item: any) => {
  93. //只显示能开的
  94. return item.area.length > 0 && examList.includes(item.key);
  95. //return item.area.length > 0;
  96. });
  97. // console.log("projectList.value", projectList.value)
  98. });
  99. };
  100. /**
  101. * 获取实例
  102. */
  103. const onSwiper = ($ev: any) => {
  104. console.log('1111111', $ev);
  105. mySwiper.value = $ev;
  106. slidePrev();
  107. };
  108. /**
  109. * 切换上一页
  110. */
  111. const slidePrev = () => {
  112. mySwiper.value.slidePrev();
  113. };
  114. /**
  115. * 切换下一页
  116. */
  117. const slideNext = () => {
  118. mySwiper.value.slideNext();
  119. };
  120. /**
  121. * 启动切换
  122. */
  123. const slideChange = () => {
  124. // if (projectList.value.length <= 3) {
  125. // slidePrev()
  126. // } else {
  127. // slideNext();
  128. // }
  129. slidePrev();
  130. };
  131. /**
  132. * 进入项目
  133. */
  134. const getOption = (data: any) => {
  135. confirm(data);
  136. };
  137. /**
  138. * 确定并进入
  139. */
  140. const confirm = (myProject?: any) => {
  141. let project = myProject || projectList.value[mySwiper.value.realIndex];
  142. console.log('projectList.value', projectList.value);
  143. console.log('mySwiper.value', mySwiper.value);
  144. console.log('mySwiper.value.realIndex', mySwiper.value.realIndex);
  145. console.log('project', project);
  146. if (project == undefined) {
  147. proxy?.$modal.msgError('获取不到项目信息');
  148. return false;
  149. }
  150. let obj = device_info.value.project_list.find((item: any) => {
  151. return item.exam_name == project.key;
  152. });
  153. if (obj == undefined) {
  154. proxy?.$modal.msgError('该项目没有配置参数');
  155. return false;
  156. }
  157. let data = {
  158. gesture: obj.gesture ? true : false,
  159. demo: obj?.demo || 0,
  160. area: obj?.area_test_id || '',
  161. ctrl: obj?.area_ctrl_id || '',
  162. time: obj?.test_time || '',
  163. music: obj?.music_info?.url || '',
  164. handcontroller: device_info.value.handcontroller_id
  165. };
  166. optionWindowRef.value.getGesture(project, data);
  167. };
  168. /**
  169. * 退出
  170. */
  171. const getLogout = async () => {
  172. if (import.meta.env.DEV) {
  173. proxy?.$modal.msgSuccess('测试环境免密退出');
  174. await proxy?.$http.common.logout({}).then((res: any) => {});
  175. proxy?.$modal?.closeLoading();
  176. //清空缓存
  177. localStorage.clear();
  178. //跳转
  179. router.push({ path: '/login/qrcode' });
  180. } else {
  181. let myInfo: any = localStorage.getItem('userInfo');
  182. let userInfo = JSON.parse(myInfo);
  183. proxy?.$modal
  184. .prompt(`【${userInfo.login_name}】,请输入密码`, 'password')
  185. .then((e: any) => {
  186. // console.log("e", e)
  187. if (e.action == 'confirm' && e.value) {
  188. let params = {
  189. password: e.value
  190. };
  191. proxy?.$http.common.checkPassword(params).then(async (res: any) => {
  192. if (res.status === 200 || res.status === 1) {
  193. await proxy?.$http.common.logout({}).then((res: any) => {});
  194. proxy?.$modal?.closeLoading();
  195. //清空缓存
  196. localStorage.clear();
  197. //跳转
  198. router.push({ path: '/login/qrcode' });
  199. } else {
  200. proxy?.$modal.msgError(res.message);
  201. }
  202. });
  203. }
  204. })
  205. .finally(() => {});
  206. }
  207. };
  208. /**
  209. * 提示语
  210. */
  211. const getTips = () => {
  212. let myTime = 10000;
  213. let num = 0;
  214. timerManager.value.tips = setInterval(() => {
  215. if (projectList.value.length) {
  216. // if (num % 2 == 0) {
  217. // proxy?.$modal.msgWarning({
  218. // message: `手向左滑切换项目`,
  219. // duration: 5000
  220. // })
  221. // } else {
  222. // proxy?.$modal.msgWarning({
  223. // message: `举左手进入测试`,
  224. // duration: 5000
  225. // })
  226. // }
  227. proxy?.$modal.msgWarning({
  228. message: `举左手进入测试`,
  229. duration: 5000
  230. });
  231. num++;
  232. }
  233. }, myTime);
  234. };
  235. /**
  236. * 获取个人信息
  237. */
  238. const getUserInfo = () => {
  239. let params = {};
  240. proxy?.$http.common.getUserInfo(params).then((res: any) => {
  241. //保存信息
  242. if (res.data.length) {
  243. let myData = res.data[0];
  244. let info = JSON.stringify(myData);
  245. localStorage.setItem('userInfo', info);
  246. //修改收藏夹图标
  247. proxy?.$utils.setFavicon(myData?.logo_url);
  248. key.value = key.value + 1; //更新头部LOGO
  249. }
  250. });
  251. };
  252. /**
  253. * 获取设备项目
  254. */
  255. const getDevice = async () => {
  256. let deviceid = localStorage.getItem('deviceid') || '';
  257. if (deviceid) {
  258. startDevice({ deviceid: deviceid });
  259. } else {
  260. proxy?.$modal.msgError(`缺少设备信息请重新登录!`);
  261. await proxy?.$http.common.logout({}).then((res: any) => {});
  262. proxy?.$modal?.closeLoading();
  263. //清空缓存
  264. localStorage.clear();
  265. //跳转
  266. router.push({ path: '/login/qrcode' });
  267. }
  268. };
  269. /**
  270. * 获取二维码
  271. */
  272. const getErweima = () => {
  273. let deviceid = localStorage.getItem('deviceid') || '';
  274. QRCode.toDataURL(`${location.origin}/#/login/mobile?sid=${sid}&deviceid=${deviceid}`).then((res: any) => {
  275. erweima.value = res;
  276. });
  277. };
  278. onBeforeMount(() => {
  279. //加载设备WS
  280. handWs((e: any) => {
  281. if (router.currentRoute.value.path != '/gesture') {
  282. return false;
  283. }
  284. // console.log("eeeee", e)
  285. if (e?.wksid) {
  286. //获取设备项目
  287. getDevice();
  288. }
  289. //接收设备信息
  290. if (e?.device_info) {
  291. device_info.value = e.device_info;
  292. let handcontroller_id = device_info.value.handcontroller_id;
  293. stateHand(handcontroller_id);
  294. getInitExam();
  295. }
  296. //获取手势状态
  297. if (e?.cmd == 'get_handcontroller_state' && e?.state == 0) {
  298. let handcontroller_id = device_info.value.handcontroller_id;
  299. startHand(handcontroller_id);
  300. }
  301. //左滑动
  302. if (e?.data?.result == 'next_item') {
  303. // proxy?.$modal.msgSuccess('手势指令:左滑动');
  304. if (projectList.value.length == 0) {
  305. return false;
  306. }
  307. slideChange();
  308. }
  309. //举左手
  310. if (e?.data?.result == 'left_hand') {
  311. proxy?.$modal.msgSuccess('手势指令:举左手');
  312. confirm();
  313. }
  314. //退出
  315. // if (e?.data?.result == "exit") {
  316. // proxy?.$modal.msgSuccess('手势指令:交叉手');
  317. // }
  318. //刷新
  319. if (e?.data?.result == 'refresh') {
  320. window.location.reload();
  321. }
  322. });
  323. });
  324. onMounted(() => {
  325. getUserInfo();
  326. //登录码
  327. getErweima();
  328. //提示语
  329. // getTips();
  330. });
  331. onBeforeUnmount(() => {
  332. getClearTimer();
  333. ElMessage.closeAll();
  334. });
  335. </script>
  336. <style lang="scss" scoped>
  337. $topPadding: 5.19rem;
  338. $waiPadding: 6.51rem;
  339. .menu {
  340. width: calc(100% - ($waiPadding * 2));
  341. height: 100vh;
  342. margin: 0 auto;
  343. display: flex;
  344. align-items: center;
  345. .li {
  346. // width: calc((100% / 6) - 1rem + (1rem/6));
  347. // margin-right: 1rem;
  348. // margin-bottom: 1rem;
  349. width: 100%;
  350. height: 100%;
  351. padding: 3vh 0;
  352. border-radius: 1.6rem;
  353. box-sizing: border-box;
  354. box-shadow: inset 0px 1px 0px 2px rgba(255, 255, 255, 0.9046), inset 0px 3px 6px 0px rgba(0, 0, 0, 0.0851);
  355. display: flex;
  356. justify-content: center;
  357. align-items: center;
  358. background: radial-gradient(96% 96% at 2% 32%, #ffffff 0%, #fcfdfd 54%, #e1e4e7 100%);
  359. cursor: pointer;
  360. .name {
  361. width: 100%;
  362. font-size: 2.48rem;
  363. color: #1a293a;
  364. padding: 0.5rem 0;
  365. text-align: center;
  366. }
  367. .pic {
  368. width: 11.36vw;
  369. height: 11.36vw;
  370. border-radius: 50%;
  371. background: radial-gradient(78% 78% at 53% 50%, #07121a 0%, #2a4256 49%, #5180a9 100%);
  372. box-shadow: 0px 0px 2px 2px #ffffff;
  373. margin-bottom: 2vh;
  374. overflow: hidden;
  375. display: flex;
  376. align-items: center;
  377. justify-content: center;
  378. flex-shrink: 0;
  379. img {
  380. max-width: 88%;
  381. max-height: 88%;
  382. transition: all 1s;
  383. }
  384. }
  385. &:hover {
  386. img {
  387. transform: translateY(-0.5vw);
  388. }
  389. }
  390. }
  391. .swiper {
  392. width: 100%;
  393. }
  394. .swiper-slide {
  395. transform: scale(0.8);
  396. transition: all 0.3s ease-in-out;
  397. border-radius: 1.6rem;
  398. opacity: 0.6;
  399. overflow: hidden;
  400. }
  401. .swiper-slide-active {
  402. opacity: 1;
  403. transform: scale(1);
  404. .li {
  405. background: radial-gradient(167% 126% at 97% 6%, #35ffc6 0%, #00ffe8 100%);
  406. }
  407. }
  408. }
  409. .erweima {
  410. position: absolute;
  411. right: 3rem;
  412. bottom: 3rem;
  413. text-align: center;
  414. img {
  415. width: 6.625rem;
  416. }
  417. span {
  418. display: block;
  419. color: #ffffff;
  420. font-size: 1rem;
  421. padding-top: 3px;
  422. }
  423. }
  424. </style>