index.vue 10 KB

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