index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. <template>
  2. <div class="game">
  3. <Header @confirmExit="getExit" :showTool="false" closeClass="close2"></Header>
  4. <div class="menu" v-if="projectList.length" :class="projectList.length <= 12 ? 'menu1' : 'menu2'"
  5. :key="projectList.length">
  6. <swiper :slides-per-view="6" :modules="[Grid]" :grid="{
  7. fill: projectList.length <= 12 ? 'row' : 'column',
  8. rows: 2,
  9. }" :space-between="20" :slides-per-group="12">
  10. <swiper-slide v-for="(item, index) in projectList" :key="item.project_uid" @click="getJump(item)">
  11. <div class="li">
  12. <div>
  13. <div class="pic"><img :src="'static/images/game/' + item.exam_name + '.png'" /></div>
  14. <div class="name">
  15. {{ item.exam_name_cn }}
  16. </div>
  17. </div>
  18. </div>
  19. </swiper-slide>
  20. </swiper>
  21. </div>
  22. <Transition :enter-active-class="proxy?.animate.rankingWindow.enter"
  23. :leave-active-class="proxy?.animate.rankingWindow.leave">
  24. <div class="gameWindow" v-if="start">
  25. <!---人体姿态识别-->
  26. <div class="columns" v-if="currentGame == 'bodyposecontroller'">
  27. <template v-if="currentGameArea.length == 2">
  28. <div class="item left">
  29. <HumanBody ref="humanBodyLeftRef" type="left" :currentGameArea="currentGameArea[0]"
  30. :areaStateList="areaStateList"></HumanBody>
  31. </div>
  32. <div class="item right">
  33. <HumanBody ref="humanBodyRightRef" type="right" :currentGameArea="currentGameArea[1]"
  34. :areaStateList="areaStateList"></HumanBody>
  35. </div>
  36. </template>
  37. <template v-else>
  38. <HumanBody ref="humanBodyLeftRef" type="left" :currentGameArea="currentGameArea[0]"
  39. :areaStateList="areaStateList"></HumanBody>
  40. </template>
  41. </div>
  42. <!---篮球投篮-->
  43. <div class="columns" v-if="currentGame == 'game_basketball'">
  44. <div class="item left">
  45. <Basketball ref="basketballLeftRef" type="left" @confirmExit="getExitGame"
  46. :currentGameArea="currentGameArea[0]" :areaStateList="areaStateList"></Basketball>
  47. </div>
  48. <div class="item right">
  49. <Basketball ref="basketballRightRef" type="right" @confirmExit="getExitGame"
  50. :currentGameArea="currentGameArea[1]" :areaStateList="areaStateList"></Basketball>
  51. </div>
  52. </div>
  53. <!---足球带球-->
  54. <div class="columns" v-if="currentGame == 'game_football'">
  55. <div class="item left">
  56. <Football ref="footballLeftRef" type="left" @confirmExit="getExitGame" :currentGameArea="currentGameArea[0]"
  57. :areaStateList="areaStateList">
  58. </Football>
  59. </div>
  60. <div class="item right">
  61. <Football ref="footballRightRef" type="right" @confirmExit="getExitGame"
  62. :currentGameArea="currentGameArea[1]" :areaStateList="areaStateList">
  63. </Football>
  64. </div>
  65. </div>
  66. <!---切水果-->
  67. <div class="columns" v-if="currentGame == 'game_fruit'">
  68. <Fruit ref="fruitRef" @confirmExit="getExitGame" :currentGameArea="currentGameArea[0]"
  69. :areaStateList="areaStateList">
  70. </Fruit>
  71. </div>
  72. </div>
  73. </Transition>
  74. <div class="continueGame" v-if="resumeGame">举手继续游戏</div>
  75. <div class="resumeGame" v-if="resumeGame" @click="getResumeGame">继续游戏</div>
  76. <div class="close close1" v-if="start" @click="getExitGame"></div>
  77. <ActionConfirmWindow ref="actionConfirmRef" @confirmExit="getExitGame({ type: 1 })" @confirmStart="getStartGame"
  78. @setMusic="setMusic">
  79. </ActionConfirmWindow>
  80. <div class="time" v-if="timerNum > 0">
  81. <div>{{ timerNum }}</div>
  82. </div>
  83. <div class="close close2" @click="getExit"></div>
  84. </div>
  85. </template>
  86. <script setup name="GameIndex" lang="ts">
  87. import useAppStore from '@/store/modules/app';
  88. import { clearInterval, clearTimeout, setInterval, setTimeout } from 'worker-timers';
  89. import { initSpeech, speckText, playMusic, controlMusic, speckCancel, chineseNumber } from '@/utils/speech';
  90. import { Swiper, SwiperSlide } from 'swiper/vue';
  91. import { Grid } from 'swiper/modules';
  92. import 'swiper/css';
  93. import 'swiper/css/grid';
  94. import { useWebSocket } from '@/utils/bodyposeWs';
  95. import HumanBody from "./components/humanBody.vue";
  96. import Basketball from "./components/basketball.vue";
  97. import Football from "./components/football.vue";
  98. import Fruit from "./components/fruit.vue";
  99. const router = useRouter();
  100. const { proxy } = getCurrentInstance() as any;
  101. const humanBodyLeftRef = ref();
  102. const humanBodyRightRef = ref();
  103. const basketballLeftRef = ref();
  104. const basketballRightRef = ref();
  105. const footballLeftRef = ref();
  106. const footballRightRef = ref();
  107. const fruitRef = ref();
  108. const actionConfirmRef = ref();
  109. const { bodyposeWs, startDevice, checkBodypose, openBodypose, terminateBodypose, suspendBodypose, resumeBodypose, getBodyposeState, closeWS } = useWebSocket();
  110. const data = reactive<any>({
  111. projectList: [],//项目列表
  112. wsState: false,//WS状态
  113. bodyposeState: false,//姿态识别窗口状态
  114. deviceInfo: {},//设备信息
  115. currentGame: "",//当前游戏
  116. currentGameArea: [],//当前游戏区
  117. start: false,//是否开始游戏
  118. areaStateList: [],//各游戏就绪状态
  119. resumeGame: false,//游戏结束显示继续游戏
  120. timer: null,
  121. timerNum: null,
  122. music: { id: null, list: [] }
  123. });
  124. const { projectList, wsState, bodyposeState, deviceInfo, currentGame, currentGameArea, start, areaStateList, resumeGame, timer, timerNum, music } = toRefs(data);
  125. /**
  126. * 监听数据变化
  127. */
  128. watch(
  129. () => areaStateList.value,
  130. (newData, oldData) => {
  131. console.log("areaStateList.value", areaStateList.value)
  132. //如果当前都是结束了就再重新弹窗
  133. let state = newData.every((item: any) => {
  134. return item.gameover;
  135. })
  136. if (state) {
  137. speckCancel();
  138. // start.value = false;
  139. // actionConfirmRef.value.getOpen(currentGame.value, currentGameArea.value);
  140. resumeGame.value = true;
  141. speckText("举手继续游戏");
  142. }
  143. },
  144. { deep: true }
  145. );
  146. /**
  147. * 初始化
  148. */
  149. const getInit = async () => {
  150. console.log("触发姿态识别")
  151. let deviceid = localStorage.getItem('deviceid') || '';
  152. if (!deviceid) {
  153. proxy?.$modal.msgError(`请重新登录绑定设备号后使用`);
  154. getExit();
  155. return false;
  156. }
  157. bodyposeState.value = true;
  158. if (wsState.value) {
  159. proxy?.$modal.msgWarning(`操作过快,请稍后重试`);
  160. setTimeout(() => {
  161. bodyposeState.value = false;
  162. }, 1000)
  163. return false;
  164. }
  165. bodyposeWs((e: any) => {
  166. if (e?.wksid) {
  167. wsState.value = true;
  168. //获取设备信息
  169. startDevice({ deviceid: deviceid });
  170. console.log("获取设备信息")
  171. }
  172. if (e?.type == 'fe_device_init_result') {
  173. //接收设备信息并发送请求
  174. if (e?.device_info) {
  175. deviceInfo.value = e.device_info;
  176. let list = deviceInfo.value.project_list.filter((item: any) => {
  177. return ['bodyposecontroller', 'game_basketball', 'game_football', 'game_fruit'].includes(item.exam_name)
  178. })
  179. projectList.value = list;
  180. } else {
  181. proxy?.$modal.msgError(`设备信息缺失,请重新登录绑定设备号后使用`);
  182. }
  183. }
  184. if (e?.cmd == 'check_bodyposecontroller_available') {
  185. let area = e.ctrl_name.replace('bodyposecontroller_', '');
  186. if (e?.code == 0) {
  187. getBodyposeState(area);
  188. }
  189. }
  190. if (e?.cmd == 'get_bodyposecontroller_state') {
  191. let area = e.ctrl_name.replace('bodyposecontroller_', '');
  192. //state说明: 0:关闭,3:空闲,36:工作中
  193. if ([3, 36].includes(e.state)) {
  194. terminateBodypose(area);
  195. } else {
  196. openBodypose(area);
  197. }
  198. }
  199. if (e?.type == 'bodyposecontroller_result') {
  200. //可信度低于0.1不要
  201. let arr = e.data.result.keypoints;
  202. let result = [];
  203. for (let i = 0; i < arr.length; i += 3) {
  204. result.push(arr[i + 2]);
  205. }
  206. // console.log("result", result)
  207. let ok = result.every((item) => {
  208. return item >= 0.1
  209. })
  210. if (!ok) {
  211. return false;
  212. }
  213. //传给预备窗口
  214. if (!start.value) {
  215. actionConfirmRef.value.getInit(e);
  216. return false;
  217. }
  218. if (!currentGame.value) {
  219. return false;
  220. }
  221. //举手继续游戏
  222. if (resumeGame.value) {
  223. let myArr = e.data.result.keypoints;
  224. let result = [];
  225. for (let i = 0; i < myArr.length; i += 3) {
  226. result.push(myArr.slice(i, i + 2));
  227. }
  228. let leftA = result[6][1];//右肩Y
  229. let rightA = result[5][1];//左肩Y
  230. let leftB = result[8][1];//右肘Y
  231. let rightB = result[7][1];//左肘Y
  232. let bizi = result[0][1];//鼻子Y
  233. if (leftB < leftA || rightB < rightA || leftB < bizi || rightB < bizi) {
  234. getResumeGame();
  235. }
  236. }
  237. let area = e.ctrl_name.replace('bodyposecontroller_', '');
  238. //传给游戏窗口
  239. if (currentGame.value == 'bodyposecontroller') {
  240. if (currentGameArea.value.length == 2) {
  241. if (area == currentGameArea.value[0]) {
  242. humanBodyLeftRef.value.getInit(e);
  243. }
  244. if (area == currentGameArea.value[1]) {
  245. humanBodyRightRef.value.getInit(e);
  246. }
  247. } else {
  248. if (area == currentGameArea.value[0]) {
  249. humanBodyLeftRef.value.getInit(e);
  250. }
  251. }
  252. }
  253. if (currentGame.value == 'game_basketball') {
  254. if (area == currentGameArea.value[0]) {
  255. basketballLeftRef.value.getInit(e);
  256. }
  257. if (area == currentGameArea.value[1]) {
  258. basketballRightRef.value.getInit(e);
  259. }
  260. }
  261. if (currentGame.value == 'game_football') {
  262. if (area == currentGameArea.value[0]) {
  263. footballLeftRef.value.getInit(e);
  264. }
  265. if (area == currentGameArea.value[1]) {
  266. footballRightRef.value.getInit(e);
  267. }
  268. }
  269. if (currentGame.value == 'game_fruit') {
  270. fruitRef.value.getInit(e);
  271. }
  272. }
  273. if (e?.cmd == 'terminate_bodyposecontroller') {
  274. }
  275. if (e?.type == 'disconnect') {
  276. getExit();
  277. }
  278. });
  279. };
  280. //打开窗口
  281. const getJump = (data: any) => {
  282. console.log("222", data)
  283. if (data.exam_name == 'test') {
  284. router.push({ path: '/game/test' });
  285. } else {
  286. //相同项目切换音乐保留上一次记录
  287. if (music.value.id) {
  288. actionConfirmRef.value.setMusic(music.value.id);
  289. } else {
  290. music.value.id = data.music_id;
  291. actionConfirmRef.value.setMusic(music.value.id);
  292. }
  293. currentGame.value = data.exam_name;
  294. currentGameArea.value = data.area_test_id?.split(",") || [];
  295. actionConfirmRef.value.getOpen(currentGame.value, currentGameArea.value);
  296. currentGameArea.value.forEach((item: any) => {
  297. checkBodypose(item);
  298. })
  299. }
  300. };
  301. /**
  302. * 退出
  303. */
  304. const getExit = () => {
  305. speckCancel();
  306. // router.go(-1);
  307. router.push({ path: '/home' });
  308. };
  309. /**
  310. * 退出游戏
  311. */
  312. const getExitGame = (data: any) => {
  313. if (data.type == 1) {
  314. //浮窗退出
  315. console.log("currentGameArea.value", currentGameArea.value)
  316. currentGameArea.value.forEach((item: any) => {
  317. terminateBodypose(item);
  318. })
  319. currentGame.value = "";
  320. start.value = false;
  321. resumeGame.value = false;
  322. timerNum.value = 0;
  323. clearInterval(timer.value);
  324. timer.value = null;
  325. speckCancel();
  326. } else if (data.type == 2) {
  327. //游戏结束显示下一场
  328. let myIndex = areaStateList.value.findIndex((item: any) => {
  329. return item.area == data.area;
  330. })
  331. if (myIndex != undefined) {
  332. areaStateList.value[myIndex].gameover = true;
  333. }
  334. } else {
  335. //游戏中退出
  336. proxy?.$modal.confirm("确定退出吗?").then(() => {
  337. currentGameArea.value.forEach((item: any) => {
  338. terminateBodypose(item);
  339. })
  340. currentGame.value = "";
  341. start.value = false;
  342. resumeGame.value = false;
  343. timerNum.value = 0;
  344. clearInterval(timer.value);
  345. timer.value = null;
  346. speckCancel();
  347. }).finally(() => {
  348. });
  349. }
  350. };
  351. /**
  352. * 开始游戏
  353. */
  354. const getStartGame = (data: any) => {
  355. areaStateList.value = data;
  356. start.value = true;
  357. resumeGame.value = false;
  358. getPlayMusic();
  359. };
  360. /**
  361. * 继续游戏
  362. */
  363. const getResumeGame = () => {
  364. if (timer.value) {
  365. clearInterval(timer.value);
  366. timer.value = null;
  367. }
  368. resumeGame.value = false;
  369. timerNum.value = 5;
  370. speckText(timerNum.value);
  371. timer.value = setInterval(() => {
  372. timerNum.value--;
  373. speckText(timerNum.value);
  374. if (timerNum.value == 0) {
  375. areaStateList.value.forEach((item: any, index: number) => {
  376. areaStateList.value[index].gameover = false;
  377. })
  378. clearInterval(timer.value);
  379. timer.value = null;
  380. if (currentGame.value == 'game_basketball') {
  381. basketballLeftRef.value.getResumeGame();
  382. basketballRightRef.value.getResumeGame();
  383. }
  384. if (currentGame.value == 'game_football') {
  385. footballLeftRef.value.getResumeGame();
  386. footballRightRef.value.getResumeGame();
  387. }
  388. if (currentGame.value == 'game_fruit') {
  389. fruitRef.value.getResumeGame();
  390. }
  391. getPlayMusic();
  392. }
  393. }, 1000)
  394. };
  395. /**
  396. * 播放音乐
  397. */
  398. const getPlayMusic = async () => {
  399. if (music.value.id) {
  400. let obj = music.value.list.find((item: any) => {
  401. return item.id == music.value.id;
  402. });
  403. if (obj != undefined) {
  404. playMusic(obj.url, true);
  405. }
  406. }
  407. };
  408. /**
  409. * 获取音乐
  410. */
  411. const getMusic = async () => {
  412. const list: any = useAppStore().getMusic();
  413. if (list.length) {
  414. music.value.list = list;
  415. } else {
  416. await proxy?.$http.train.musicList().then((res: any) => {
  417. if (res.data.length > 0) {
  418. let myList: any = res.data;
  419. music.value.list = myList;
  420. useAppStore().setMusic(myList);
  421. }
  422. });
  423. }
  424. };
  425. /**
  426. * 弹窗设置的音乐返回上层
  427. */
  428. const setMusic = async (data: any) => {
  429. //console.log("data",data)
  430. music.value.id = data;
  431. };
  432. onBeforeMount(async () => {
  433. //初始化语音
  434. initSpeech();
  435. //初始化WS
  436. getInit();
  437. //音乐
  438. getMusic();
  439. });
  440. onMounted(() => {
  441. });
  442. onBeforeUnmount(() => {
  443. speckCancel();
  444. closeWS();
  445. });
  446. </script>
  447. <style lang="scss" scoped>
  448. $topPadding: 5.19rem;
  449. $waiPadding: 6.51rem;
  450. .menu {
  451. width: calc(100% - ($waiPadding * 2));
  452. height: 72vh;
  453. padding-top: 10rem;
  454. margin: 0 auto;
  455. display: flex;
  456. .li {
  457. // width: calc((100% / 6) - 1rem + (1rem/6));
  458. // margin-right: 1rem;
  459. // margin-bottom: 1rem;
  460. width: 100%;
  461. height: calc((72vh / 2) - 20px);
  462. padding: 2.2vh 0;
  463. border-radius: 1.6rem;
  464. box-sizing: border-box;
  465. box-shadow: inset 0px 1px 0px 2px rgba(255, 255, 255, 0.9046), inset 0px 3px 6px 0px rgba(0, 0, 0, 0.0851);
  466. display: flex;
  467. justify-content: center;
  468. align-items: center;
  469. cursor: pointer;
  470. .pic {
  471. width: 11.36vw;
  472. height: 11.36vw;
  473. border-radius: 50%;
  474. background: radial-gradient(78% 78% at 53% 50%, #07121a 0%, #2a4256 49%, #5180a9 100%);
  475. box-shadow: 0px 0px 2px 2px #ffffff;
  476. margin-bottom: 2.5vh;
  477. overflow: hidden;
  478. display: flex;
  479. align-items: center;
  480. justify-content: center;
  481. flex-shrink: 0;
  482. img {
  483. max-width: 88%;
  484. max-height: 88%;
  485. transition: all 1s;
  486. }
  487. }
  488. .name {
  489. width: 100%;
  490. font-size: 2.1rem;
  491. color: #1a293a;
  492. text-align: center;
  493. }
  494. &:hover {
  495. img {
  496. transform: translateY(-0.5vw);
  497. }
  498. }
  499. }
  500. .swiper-slide {
  501. border-radius: 1.6rem;
  502. overflow: hidden;
  503. }
  504. }
  505. .menu1 {
  506. align-items: center;
  507. .swiper-slide {
  508. margin-bottom: 20px;
  509. .li {
  510. background: radial-gradient(96% 96% at 2% 32%, #ffffff 0%, #fcfdfd 54%, #e1e4e7 100%);
  511. }
  512. &:nth-child(2),
  513. &:nth-child(4),
  514. &:nth-child(6),
  515. &:nth-child(7),
  516. &:nth-child(9),
  517. &:nth-child(11) {
  518. .li {
  519. background: radial-gradient(167% 126% at 97% 6%, #35ffc6 0%, #00ffe8 100%);
  520. }
  521. }
  522. }
  523. }
  524. .menu2 {
  525. display: flex;
  526. .swiper-slide {
  527. &:nth-child(1),
  528. &:nth-child(4),
  529. &:nth-child(5),
  530. &:nth-child(8),
  531. &:nth-child(9),
  532. &:nth-child(12),
  533. &:nth-child(13),
  534. &:nth-child(16),
  535. &:nth-child(17),
  536. &:nth-child(20),
  537. &:nth-child(21),
  538. &:nth-child(24),
  539. &:nth-child(25),
  540. &:nth-child(28),
  541. &:nth-child(29),
  542. &:nth-child(32),
  543. &:nth-child(33),
  544. &:nth-child(36),
  545. &:nth-child(37),
  546. &:nth-child(40),
  547. &:nth-child(41),
  548. &:nth-child(44) {
  549. .li {
  550. background: radial-gradient(96% 96% at 2% 32%, #ffffff 0%, #fcfdfd 54%, #e1e4e7 100%);
  551. }
  552. }
  553. &:nth-child(2),
  554. &:nth-child(3),
  555. &:nth-child(6),
  556. &:nth-child(7),
  557. &:nth-child(10),
  558. &:nth-child(11),
  559. &:nth-child(14),
  560. &:nth-child(15),
  561. &:nth-child(18),
  562. &:nth-child(19),
  563. &:nth-child(22),
  564. &:nth-child(23),
  565. &:nth-child(26),
  566. &:nth-child(27),
  567. &:nth-child(30),
  568. &:nth-child(31),
  569. &:nth-child(34),
  570. &:nth-child(35),
  571. &:nth-child(38),
  572. &:nth-child(39),
  573. &:nth-child(42),
  574. &:nth-child(43) {
  575. .li {
  576. background: radial-gradient(167% 126% at 97% 6%, #35ffc6 0%, #00ffe8 100%);
  577. }
  578. }
  579. }
  580. }
  581. .gameWindow {
  582. width: 100vw;
  583. height: 100vh;
  584. position: absolute;
  585. z-index: 990;
  586. left: 0;
  587. top: 0;
  588. display: flex;
  589. .columns {
  590. display: flex;
  591. flex-wrap: wrap;
  592. width: 100%;
  593. .item {
  594. flex: 1;
  595. display: flex;
  596. box-sizing: border-box;
  597. width: 50%;
  598. }
  599. .left {
  600. border-right: 10px solid #07121a;
  601. }
  602. .right {
  603. border-left: 10px solid #07121a;
  604. }
  605. }
  606. }
  607. .close1 {
  608. z-index: 991;
  609. position: fixed;
  610. bottom: 35px;
  611. left: 50%;
  612. margin-left: -1.6rem;
  613. }
  614. .resumeGame {
  615. width: 10rem;
  616. height: 3.2rem;
  617. line-height: 3.2rem;
  618. font-size: 1.8rem;
  619. color: #1a293a;
  620. text-align: center;
  621. z-index: 991;
  622. position: fixed;
  623. bottom: calc(35px + 3.2rem + 25px);
  624. left: 50%;
  625. margin-left: -5rem;
  626. cursor: pointer;
  627. border-radius: 8px;
  628. background: radial-gradient(159% 126% at 5% 93%, #8effa9 0%, #07ffe7 100%);
  629. box-shadow: 1px 1px 1px 1px rgba(0, 0, 0, 0.1874), inset 0px 1px 0px 1px rgba(255, 255, 255, 0.3);
  630. &:hover {
  631. background: #8effa9;
  632. }
  633. }
  634. .continueGame {
  635. z-index: 991;
  636. position: fixed;
  637. width: 100%;
  638. left: 0;
  639. text-align: center;
  640. font-size: 3.5em;
  641. top: 40%;
  642. color: #ffffff;
  643. }
  644. .time {
  645. position: absolute;
  646. left: 0;
  647. top: 0;
  648. width: 100%;
  649. height: 100%;
  650. background: rgba(0, 0, 0, 0.5);
  651. color: #ffffff;
  652. font-size: 7rem;
  653. display: flex;
  654. align-items: center;
  655. justify-content: center;
  656. z-index: 998;
  657. }
  658. ::v-deep(.menu) {
  659. .swiper-horizontal {
  660. width: 100%;
  661. }
  662. }
  663. .close2 {
  664. position: absolute;
  665. // right: calc($waiPadding - 3.2rem);
  666. left: auto;
  667. right: calc($waiPadding - 3.2rem);
  668. top: auto;
  669. bottom: calc($topPadding / 2 - 3.2rem / 4);
  670. }
  671. @media screen and (max-width: 1450px) {
  672. .menu {
  673. .li {
  674. .name {
  675. font-size: 1.6rem;
  676. }
  677. .pic {
  678. width: 10vw;
  679. height: 10vw;
  680. }
  681. }
  682. }
  683. }
  684. </style>