App.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. <!--
  2. * @Author: fxs bjnsfxs@163.com
  3. * @Date: 2024-08-20 14:06:49
  4. * @LastEditors: fxs bjnsfxs@163.com
  5. * @LastEditTime: 2024-09-03 18:22:47
  6. * @FilePath: \Game-Backstage-Management-System\src\App.vue
  7. * @Description:
  8. *
  9. -->
  10. <script setup lang="ts">
  11. import { zhCn } from 'element-plus/es/locales.mjs'
  12. import { RouterView } from 'vue-router'
  13. import { onMounted, reactive, ref, nextTick } from 'vue'
  14. import { ElMessage } from 'element-plus'
  15. import { getAllGameInfo } from '@/utils/table/table'
  16. import router from '@/router'
  17. import type { DropDownInfo } from '@/types/dataAnalysis'
  18. import DropDownSelection from '@/components/dataAnalysis/DropDownSelection.vue'
  19. import { useCommonStore } from '@/stores/useCommon'
  20. import { initLoadResouce } from '@/utils/resource'
  21. const { selectInfo } = useCommonStore()
  22. const isCollapse = ref(false)
  23. const navBarSelect = ref<string>('Home')
  24. const siderBarOpened = ref<Array<string>>(['数据总览'])
  25. const siderBar = ref()
  26. const menuList = reactive<Array<any>>([])
  27. const defaultActive = ref<string>('0')
  28. const navBarMenuList = [
  29. {
  30. name: 'Home',
  31. title: '应用分析'
  32. },
  33. {
  34. name: 'AppManage',
  35. title: '应用管理'
  36. }
  37. ]
  38. /**
  39. * @description: 侧边栏折叠改变
  40. * @return {*}
  41. */
  42. const changeCollapse = () => {
  43. isCollapse.value = !isCollapse.value
  44. }
  45. // 登出
  46. const logOut = () => {
  47. ElMessage({
  48. type: 'success',
  49. message: '退出成功',
  50. duration: 1000
  51. })
  52. localStorage.removeItem('token')
  53. localStorage.removeItem('refreshToken')
  54. router.push('/login')
  55. }
  56. // 游戏下拉选择框需要的数据
  57. const gameSelectInfo = reactive<DropDownInfo>({
  58. defaultSelect: '1001',
  59. title: '请选择游戏',
  60. optionsList: []
  61. })
  62. // 游戏信息是否加载成功
  63. const gameinfoLoad = ref(false)
  64. /**
  65. * @description: 更新整个页面的游戏选择
  66. * @param {*} gid 游戏id
  67. * @return {*}
  68. */
  69. const changeGame = (gid: any) => {
  70. selectInfo.gid = gid
  71. }
  72. /**
  73. * @description: 头部导航栏改变
  74. * @param {*} val 对应的name
  75. * @return {*}
  76. */
  77. const changeNavBar = (val: string) => {
  78. navBarSelect.value = val
  79. router.push(`/${val}`)
  80. createdMenuList()
  81. let title = navBarMenuList.find((item) => item.name === val)?.title
  82. if (title) {
  83. siderBarOpened.value.splice(0, 1, title)
  84. }
  85. }
  86. /**
  87. * @description: 获取所有游戏列表
  88. * @return {*}
  89. */
  90. getAllGameInfo().then((data) => {
  91. if (data) {
  92. data.map((item) => {
  93. gameSelectInfo.optionsList.push({
  94. value: item.gid,
  95. label: item.gameName
  96. })
  97. })
  98. }
  99. gameinfoLoad.value = true
  100. })
  101. // 资源的加载路径
  102. const resourceInfo: Record<string, string> = {
  103. logo: `/img/logo.svg`,
  104. defaultHead: `/img/default/defaultHead.png`
  105. }
  106. // 使用blob的资源路径信息
  107. const blobUrlInfo = reactive<Record<string, string>>({})
  108. const basePath = ref<string | undefined>()
  109. /**
  110. * @description: 创建侧边栏menu
  111. * @param {*} let
  112. * @return {*}
  113. */
  114. const createdMenuList = () => {
  115. let routes = router.options.routes
  116. let activeMenu = routes.find((item) => {
  117. return item.name === navBarSelect.value
  118. })
  119. basePath.value = activeMenu?.path
  120. menuList.splice(0, menuList.length, ...(activeMenu?.children as Array<any>))
  121. defaultActive.value = '0' // 仍有问题
  122. }
  123. onMounted(() => {
  124. // 去加载所有需要的资源
  125. initLoadResouce(resourceInfo).then((data) => {
  126. Object.assign(blobUrlInfo, data)
  127. })
  128. createdMenuList()
  129. })
  130. </script>
  131. <template>
  132. <el-config-provider :locale="zhCn">
  133. <div class="body">
  134. <div class="navBarBox">
  135. <div class="logoBox">
  136. <el-image :fit="'fill'" class="logoImg" :src="blobUrlInfo.logo"></el-image>
  137. <span>淳皓科技</span>
  138. </div>
  139. <div class="gameSelect">
  140. <el-icon class="gameIcon" :size="20">
  141. <icon-icon-park-game-three></icon-icon-park-game-three>
  142. </el-icon>
  143. <DropDownSelection
  144. :default-select="gameSelectInfo.defaultSelect"
  145. :title="gameSelectInfo.title"
  146. :options-list="gameSelectInfo.optionsList"
  147. :size="'default'"
  148. @change-select="changeGame"
  149. ></DropDownSelection>
  150. </div>
  151. <div class="navBarMenu">
  152. <el-menu
  153. :default-active="navBarSelect"
  154. class="el-menu-demo"
  155. mode="horizontal"
  156. @select="changeNavBar"
  157. >
  158. <el-menu-item
  159. v-for="item in navBarMenuList"
  160. class="navBarMenuItem"
  161. :index="item.name"
  162. >{{ item.title }}</el-menu-item
  163. >
  164. </el-menu>
  165. </div>
  166. <div class="headPortraitBox">
  167. <el-popover popper-class="headPopper" placement="bottom-end" trigger="click">
  168. <template #reference>
  169. <el-image class="headPortrait" :src="blobUrlInfo.defaultHead"></el-image>
  170. </template>
  171. <div class="userTools">
  172. <span class="userToolsItem" @click="logOut">
  173. <icon-material-symbols-light-logout></icon-material-symbols-light-logout>
  174. <span> 退出登录</span>
  175. </span>
  176. </div>
  177. </el-popover>
  178. </div>
  179. </div>
  180. <div class="sideBarBox">
  181. <el-menu
  182. :default-active="defaultActive"
  183. class="sideBar"
  184. :collapse="isCollapse"
  185. ref="siderBar"
  186. >
  187. <template v-for="(item, index) in menuList">
  188. <el-sub-menu :index="`${index}`" v-if="item.children && item.showChild">
  189. <template #title>
  190. <el-icon><component :is="item.icon"></component></el-icon>
  191. <span>{{ item.cnName }}</span>
  192. </template>
  193. <!-- :to="{ name: val.name }" -->
  194. <router-link
  195. style="text-decoration: none"
  196. v-for="(val, subIndex) in item.children"
  197. :to="{ path: basePath + '/' + item.path + '/' + val.path }"
  198. :key="index"
  199. >
  200. <el-menu-item :index="index + '-' + subIndex">{{ val.cnName }}</el-menu-item>
  201. </router-link>
  202. </el-sub-menu>
  203. <router-link
  204. style="text-decoration: none"
  205. v-else
  206. :to="{ path: basePath + '/' + item.path }"
  207. :key="index"
  208. >
  209. <el-menu-item :index="`${index}`">
  210. <template #title>
  211. <el-icon><component :is="item.icon" /></el-icon>
  212. <span class="menuTitle">{{ item.cnName }}</span>
  213. </template>
  214. </el-menu-item>
  215. </router-link>
  216. </template>
  217. <div class="sideBarFold" @click="changeCollapse">
  218. <el-icon :size="25"><Fold /></el-icon>
  219. </div>
  220. </el-menu>
  221. </div>
  222. <!-- <div class="sideBarBox">
  223. <el-menu
  224. :router="true"
  225. :default-active="$route.name"
  226. class="sideBar"
  227. :collapse="isCollapse"
  228. ref="siderBar"
  229. >
  230. <template v-for="item in menuInfo[navBarSelect]">
  231. <el-sub-menu v-if="item.children" :index="item.title">
  232. <template #title>
  233. <el-icon><component :is="item.icon" /></el-icon>
  234. <span class="menuTitle">{{ item.title }}</span>
  235. </template>
  236. <el-menu-item v-for="v in item.children" :index="v.pathName">{{
  237. v.title
  238. }}</el-menu-item>
  239. </el-sub-menu>
  240. <el-menu-item v-else :index="item.pathName">
  241. <template #title>
  242. <el-icon><component :is="item.icon" /></el-icon>
  243. <span class="menuTitle">{{ item.title }}</span>
  244. </template>
  245. </el-menu-item>
  246. </template>
  247. <div class="sideBarFold" @click="changeCollapse">
  248. <el-icon :size="25"><Fold /></el-icon>
  249. </div>
  250. </el-menu>
  251. </div> -->
  252. <div class="content">
  253. <router-view v-slot="{ Component, route }">
  254. <keep-alive>
  255. <component
  256. :is="Component"
  257. :key="route.path"
  258. v-if="route.meta.needKeepAlive == true"
  259. ></component>
  260. </keep-alive>
  261. <component
  262. :is="Component"
  263. :key="route.path"
  264. v-if="route.meta.needKeepAlive == false"
  265. ></component>
  266. </router-view>
  267. </div>
  268. </div>
  269. </el-config-provider>
  270. </template>
  271. <style scoped>
  272. .body {
  273. width: 100%;
  274. display: flex;
  275. height: 100vh;
  276. }
  277. /* 设置宽度后,content无法适应宽度,只能去间接的调整内部元素的宽度 */
  278. .sideBarBox {
  279. position: relative;
  280. /* width: 12%; */
  281. z-index: 1;
  282. height: 93vh;
  283. margin-top: 7vh;
  284. top: 0;
  285. }
  286. .sideBar {
  287. /* width: 12vw; */
  288. height: 93vh;
  289. position: relative;
  290. overflow: scroll;
  291. }
  292. /* 设置弹出层的样式 */
  293. .el-popper > .logoText {
  294. width: 100px;
  295. font-size: 16px;
  296. /* color: red; */
  297. }
  298. .logoImg {
  299. display: flex;
  300. align-items: center;
  301. width: 33px;
  302. /* margin-right: 20px; */
  303. /* height: 50px; */
  304. }
  305. .logoText {
  306. width: 80%;
  307. height: 100%;
  308. margin-left: 15%;
  309. display: flex;
  310. font-size: 18px;
  311. align-items: center;
  312. /* background-color: lightcoral; */
  313. }
  314. /* 主要用来调整整个menu的宽度 */
  315. .menuTitle {
  316. margin-right: 40px;
  317. }
  318. .sideBarFold {
  319. width: 5%;
  320. height: 3%;
  321. position: absolute;
  322. right: 40px;
  323. bottom: 20px;
  324. }
  325. .navBarBox {
  326. position: fixed;
  327. display: flex;
  328. align-items: center;
  329. width: 100vw;
  330. z-index: 2;
  331. height: 7vh;
  332. top: 0;
  333. background-color: white;
  334. right: 0;
  335. border-bottom: 1px solid gainsboro;
  336. }
  337. /* 调整LOGO */
  338. .logoBox {
  339. box-sizing: border-box;
  340. left: 30px;
  341. position: relative;
  342. display: flex;
  343. justify-content: space-between;
  344. align-items: center;
  345. }
  346. .gameSelect {
  347. position: relative;
  348. height: 80%;
  349. display: flex;
  350. align-items: center;
  351. left: 5%;
  352. display: flex;
  353. align-items: center;
  354. }
  355. .gameIcon {
  356. /* box-sizing: border-box; */
  357. /* padding-right: 12px; */
  358. margin-right: 12px;
  359. }
  360. .navBarMenu {
  361. width: 60%;
  362. position: relative;
  363. left: 6%;
  364. }
  365. .headPortraitBox {
  366. position: absolute;
  367. right: 3%;
  368. top: 50%;
  369. transform: translateY(-50%);
  370. }
  371. .userTools {
  372. width: 100%;
  373. height: 100%;
  374. display: flex;
  375. flex-direction: column;
  376. justify-content: space-around;
  377. align-items: center;
  378. }
  379. .userToolsItem {
  380. cursor: pointer;
  381. width: 100%;
  382. height: 4vh;
  383. display: flex;
  384. align-items: center;
  385. justify-content: center;
  386. /* padding: 10px; */
  387. margin: 2%;
  388. }
  389. .userToolsItem > span {
  390. margin-left: 10%;
  391. }
  392. .userToolsItem:hover {
  393. background-color: #f2f3f5;
  394. }
  395. .headPortrait {
  396. cursor: pointer;
  397. width: 50px;
  398. }
  399. .content {
  400. /* flex-grow: 1; */
  401. /* position: absolute; */
  402. width: 100%;
  403. /* height: 93%; */
  404. margin-top: 7vh;
  405. overflow: scroll;
  406. background-color: #f2f3f5;
  407. right: 0vw;
  408. top: 0vh;
  409. }
  410. </style>
  411. <!-- 为了让popper-class生效,需要的单独写一份 -->
  412. <style>
  413. .headPopper {
  414. padding: 0px !important;
  415. border: 1px solid #e5e6eb;
  416. background-color: white;
  417. }
  418. .el-menu--horizontal.el-menu {
  419. border-bottom: none;
  420. }
  421. </style>