|
@@ -2,20 +2,466 @@
|
|
* @Author: fxs bjnsfxs@163.com
|
|
* @Author: fxs bjnsfxs@163.com
|
|
* @Date: 2024-08-20 14:06:49
|
|
* @Date: 2024-08-20 14:06:49
|
|
* @LastEditors: fxs bjnsfxs@163.com
|
|
* @LastEditors: fxs bjnsfxs@163.com
|
|
- * @LastEditTime: 2024-08-29 09:43:18
|
|
|
|
|
|
+ * @LastEditTime: 2024-09-03 18:22:47
|
|
* @FilePath: \Game-Backstage-Management-System\src\App.vue
|
|
* @FilePath: \Game-Backstage-Management-System\src\App.vue
|
|
* @Description:
|
|
* @Description:
|
|
*
|
|
*
|
|
-->
|
|
-->
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
import { zhCn } from 'element-plus/es/locales.mjs'
|
|
import { zhCn } from 'element-plus/es/locales.mjs'
|
|
|
|
+import { RouterView } from 'vue-router'
|
|
|
|
+import { onMounted, reactive, ref, nextTick } from 'vue'
|
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
|
+import { getAllGameInfo } from '@/utils/table/table'
|
|
|
|
+import router from '@/router'
|
|
|
|
+import type { DropDownInfo } from '@/types/dataAnalysis'
|
|
|
|
+import DropDownSelection from '@/components/dataAnalysis/DropDownSelection.vue'
|
|
|
|
+import { useCommonStore } from '@/stores/useCommon'
|
|
|
|
+import { initLoadResouce } from '@/utils/resource'
|
|
|
|
+
|
|
|
|
+const { selectInfo } = useCommonStore()
|
|
|
|
+const isCollapse = ref(false)
|
|
|
|
+const navBarSelect = ref<string>('Home')
|
|
|
|
+const siderBarOpened = ref<Array<string>>(['数据总览'])
|
|
|
|
+const siderBar = ref()
|
|
|
|
+const menuList = reactive<Array<any>>([])
|
|
|
|
+const defaultActive = ref<string>('0')
|
|
|
|
+const navBarMenuList = [
|
|
|
|
+ {
|
|
|
|
+ name: 'Home',
|
|
|
|
+ title: '应用分析'
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ {
|
|
|
|
+ name: 'AppManage',
|
|
|
|
+ title: '应用管理'
|
|
|
|
+ }
|
|
|
|
+]
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * @description: 侧边栏折叠改变
|
|
|
|
+ * @return {*}
|
|
|
|
+ */
|
|
|
|
+const changeCollapse = () => {
|
|
|
|
+ isCollapse.value = !isCollapse.value
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 登出
|
|
|
|
+const logOut = () => {
|
|
|
|
+ ElMessage({
|
|
|
|
+ type: 'success',
|
|
|
|
+ message: '退出成功',
|
|
|
|
+ duration: 1000
|
|
|
|
+ })
|
|
|
|
+ localStorage.removeItem('token')
|
|
|
|
+ localStorage.removeItem('refreshToken')
|
|
|
|
+ router.push('/login')
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 游戏下拉选择框需要的数据
|
|
|
|
+const gameSelectInfo = reactive<DropDownInfo>({
|
|
|
|
+ defaultSelect: '1001',
|
|
|
|
+ title: '请选择游戏',
|
|
|
|
+ optionsList: []
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+// 游戏信息是否加载成功
|
|
|
|
+const gameinfoLoad = ref(false)
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * @description: 更新整个页面的游戏选择
|
|
|
|
+ * @param {*} gid 游戏id
|
|
|
|
+ * @return {*}
|
|
|
|
+ */
|
|
|
|
+const changeGame = (gid: any) => {
|
|
|
|
+ selectInfo.gid = gid
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * @description: 头部导航栏改变
|
|
|
|
+ * @param {*} val 对应的name
|
|
|
|
+ * @return {*}
|
|
|
|
+ */
|
|
|
|
+const changeNavBar = (val: string) => {
|
|
|
|
+ navBarSelect.value = val
|
|
|
|
+
|
|
|
|
+ router.push(`/${val}`)
|
|
|
|
+ createdMenuList()
|
|
|
|
+
|
|
|
|
+ let title = navBarMenuList.find((item) => item.name === val)?.title
|
|
|
|
+ if (title) {
|
|
|
|
+ siderBarOpened.value.splice(0, 1, title)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * @description: 获取所有游戏列表
|
|
|
|
+ * @return {*}
|
|
|
|
+ */
|
|
|
|
+getAllGameInfo().then((data) => {
|
|
|
|
+ if (data) {
|
|
|
|
+ data.map((item) => {
|
|
|
|
+ gameSelectInfo.optionsList.push({
|
|
|
|
+ value: item.gid,
|
|
|
|
+ label: item.gameName
|
|
|
|
+ })
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ gameinfoLoad.value = true
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+// 资源的加载路径
|
|
|
|
+const resourceInfo: Record<string, string> = {
|
|
|
|
+ logo: `/img/logo.svg`,
|
|
|
|
+ defaultHead: `/img/default/defaultHead.png`
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 使用blob的资源路径信息
|
|
|
|
+const blobUrlInfo = reactive<Record<string, string>>({})
|
|
|
|
+
|
|
|
|
+const basePath = ref<string | undefined>()
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * @description: 创建侧边栏menu
|
|
|
|
+ * @param {*} let
|
|
|
|
+ * @return {*}
|
|
|
|
+ */
|
|
|
|
+const createdMenuList = () => {
|
|
|
|
+ let routes = router.options.routes
|
|
|
|
+ let activeMenu = routes.find((item) => {
|
|
|
|
+ return item.name === navBarSelect.value
|
|
|
|
+ })
|
|
|
|
+ basePath.value = activeMenu?.path
|
|
|
|
+ menuList.splice(0, menuList.length, ...(activeMenu?.children as Array<any>))
|
|
|
|
+ defaultActive.value = '0' // 仍有问题
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+onMounted(() => {
|
|
|
|
+ // 去加载所有需要的资源
|
|
|
|
+ initLoadResouce(resourceInfo).then((data) => {
|
|
|
|
+ Object.assign(blobUrlInfo, data)
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ createdMenuList()
|
|
|
|
+})
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<template>
|
|
<template>
|
|
- <div>测试</div>
|
|
|
|
<el-config-provider :locale="zhCn">
|
|
<el-config-provider :locale="zhCn">
|
|
- <RouterView />
|
|
|
|
|
|
+ <div class="body">
|
|
|
|
+ <div class="navBarBox">
|
|
|
|
+ <div class="logoBox">
|
|
|
|
+ <el-image :fit="'fill'" class="logoImg" :src="blobUrlInfo.logo"></el-image>
|
|
|
|
+ <span>淳皓科技</span>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="gameSelect">
|
|
|
|
+ <el-icon class="gameIcon" :size="20">
|
|
|
|
+ <icon-icon-park-game-three></icon-icon-park-game-three>
|
|
|
|
+ </el-icon>
|
|
|
|
+ <DropDownSelection
|
|
|
|
+ :default-select="gameSelectInfo.defaultSelect"
|
|
|
|
+ :title="gameSelectInfo.title"
|
|
|
|
+ :options-list="gameSelectInfo.optionsList"
|
|
|
|
+ :size="'default'"
|
|
|
|
+ @change-select="changeGame"
|
|
|
|
+ ></DropDownSelection>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="navBarMenu">
|
|
|
|
+ <el-menu
|
|
|
|
+ :default-active="navBarSelect"
|
|
|
|
+ class="el-menu-demo"
|
|
|
|
+ mode="horizontal"
|
|
|
|
+ @select="changeNavBar"
|
|
|
|
+ >
|
|
|
|
+ <el-menu-item
|
|
|
|
+ v-for="item in navBarMenuList"
|
|
|
|
+ class="navBarMenuItem"
|
|
|
|
+ :index="item.name"
|
|
|
|
+ >{{ item.title }}</el-menu-item
|
|
|
|
+ >
|
|
|
|
+ </el-menu>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="headPortraitBox">
|
|
|
|
+ <el-popover popper-class="headPopper" placement="bottom-end" trigger="click">
|
|
|
|
+ <template #reference>
|
|
|
|
+ <el-image class="headPortrait" :src="blobUrlInfo.defaultHead"></el-image>
|
|
|
|
+ </template>
|
|
|
|
+ <div class="userTools">
|
|
|
|
+ <span class="userToolsItem" @click="logOut">
|
|
|
|
+ <icon-material-symbols-light-logout></icon-material-symbols-light-logout>
|
|
|
|
+ <span> 退出登录</span>
|
|
|
|
+ </span>
|
|
|
|
+ </div>
|
|
|
|
+ </el-popover>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ <div class="sideBarBox">
|
|
|
|
+ <el-menu
|
|
|
|
+ :default-active="defaultActive"
|
|
|
|
+ class="sideBar"
|
|
|
|
+ :collapse="isCollapse"
|
|
|
|
+ ref="siderBar"
|
|
|
|
+ >
|
|
|
|
+ <template v-for="(item, index) in menuList">
|
|
|
|
+ <el-sub-menu :index="`${index}`" v-if="item.children && item.showChild">
|
|
|
|
+ <template #title>
|
|
|
|
+ <el-icon><component :is="item.icon"></component></el-icon>
|
|
|
|
+ <span>{{ item.cnName }}</span>
|
|
|
|
+ </template>
|
|
|
|
+ <!-- :to="{ name: val.name }" -->
|
|
|
|
+ <router-link
|
|
|
|
+ style="text-decoration: none"
|
|
|
|
+ v-for="(val, subIndex) in item.children"
|
|
|
|
+ :to="{ path: basePath + '/' + item.path + '/' + val.path }"
|
|
|
|
+ :key="index"
|
|
|
|
+ >
|
|
|
|
+ <el-menu-item :index="index + '-' + subIndex">{{ val.cnName }}</el-menu-item>
|
|
|
|
+ </router-link>
|
|
|
|
+ </el-sub-menu>
|
|
|
|
+
|
|
|
|
+ <router-link
|
|
|
|
+ style="text-decoration: none"
|
|
|
|
+ v-else
|
|
|
|
+ :to="{ path: basePath + '/' + item.path }"
|
|
|
|
+ :key="index"
|
|
|
|
+ >
|
|
|
|
+ <el-menu-item :index="`${index}`">
|
|
|
|
+ <template #title>
|
|
|
|
+ <el-icon><component :is="item.icon" /></el-icon>
|
|
|
|
+ <span class="menuTitle">{{ item.cnName }}</span>
|
|
|
|
+ </template>
|
|
|
|
+ </el-menu-item>
|
|
|
|
+ </router-link>
|
|
|
|
+ </template>
|
|
|
|
+ <div class="sideBarFold" @click="changeCollapse">
|
|
|
|
+ <el-icon :size="25"><Fold /></el-icon>
|
|
|
|
+ </div>
|
|
|
|
+ </el-menu>
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ <!-- <div class="sideBarBox">
|
|
|
|
+ <el-menu
|
|
|
|
+ :router="true"
|
|
|
|
+ :default-active="$route.name"
|
|
|
|
+ class="sideBar"
|
|
|
|
+ :collapse="isCollapse"
|
|
|
|
+ ref="siderBar"
|
|
|
|
+ >
|
|
|
|
+ <template v-for="item in menuInfo[navBarSelect]">
|
|
|
|
+ <el-sub-menu v-if="item.children" :index="item.title">
|
|
|
|
+ <template #title>
|
|
|
|
+ <el-icon><component :is="item.icon" /></el-icon>
|
|
|
|
+ <span class="menuTitle">{{ item.title }}</span>
|
|
|
|
+ </template>
|
|
|
|
+ <el-menu-item v-for="v in item.children" :index="v.pathName">{{
|
|
|
|
+ v.title
|
|
|
|
+ }}</el-menu-item>
|
|
|
|
+ </el-sub-menu>
|
|
|
|
+ <el-menu-item v-else :index="item.pathName">
|
|
|
|
+ <template #title>
|
|
|
|
+ <el-icon><component :is="item.icon" /></el-icon>
|
|
|
|
+ <span class="menuTitle">{{ item.title }}</span>
|
|
|
|
+ </template>
|
|
|
|
+ </el-menu-item>
|
|
|
|
+ </template>
|
|
|
|
+ <div class="sideBarFold" @click="changeCollapse">
|
|
|
|
+ <el-icon :size="25"><Fold /></el-icon>
|
|
|
|
+ </div>
|
|
|
|
+ </el-menu>
|
|
|
|
+ </div> -->
|
|
|
|
+ <div class="content">
|
|
|
|
+ <router-view v-slot="{ Component, route }">
|
|
|
|
+ <keep-alive>
|
|
|
|
+ <component
|
|
|
|
+ :is="Component"
|
|
|
|
+ :key="route.path"
|
|
|
|
+ v-if="route.meta.needKeepAlive == true"
|
|
|
|
+ ></component>
|
|
|
|
+ </keep-alive>
|
|
|
|
+ <component
|
|
|
|
+ :is="Component"
|
|
|
|
+ :key="route.path"
|
|
|
|
+ v-if="route.meta.needKeepAlive == false"
|
|
|
|
+ ></component>
|
|
|
|
+ </router-view>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
</el-config-provider>
|
|
</el-config-provider>
|
|
</template>
|
|
</template>
|
|
|
|
|
|
-<style scoped></style>
|
|
|
|
|
|
+<style scoped>
|
|
|
|
+.body {
|
|
|
|
+ width: 100%;
|
|
|
|
+ display: flex;
|
|
|
|
+ height: 100vh;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 设置宽度后,content无法适应宽度,只能去间接的调整内部元素的宽度 */
|
|
|
|
+.sideBarBox {
|
|
|
|
+ position: relative;
|
|
|
|
+ /* width: 12%; */
|
|
|
|
+ z-index: 1;
|
|
|
|
+ height: 93vh;
|
|
|
|
+ margin-top: 7vh;
|
|
|
|
+ top: 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.sideBar {
|
|
|
|
+ /* width: 12vw; */
|
|
|
|
+ height: 93vh;
|
|
|
|
+ position: relative;
|
|
|
|
+ overflow: scroll;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 设置弹出层的样式 */
|
|
|
|
+.el-popper > .logoText {
|
|
|
|
+ width: 100px;
|
|
|
|
+ font-size: 16px;
|
|
|
|
+ /* color: red; */
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.logoImg {
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ width: 33px;
|
|
|
|
+ /* margin-right: 20px; */
|
|
|
|
+ /* height: 50px; */
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.logoText {
|
|
|
|
+ width: 80%;
|
|
|
|
+ height: 100%;
|
|
|
|
+ margin-left: 15%;
|
|
|
|
+ display: flex;
|
|
|
|
+ font-size: 18px;
|
|
|
|
+ align-items: center;
|
|
|
|
+ /* background-color: lightcoral; */
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 主要用来调整整个menu的宽度 */
|
|
|
|
+.menuTitle {
|
|
|
|
+ margin-right: 40px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.sideBarFold {
|
|
|
|
+ width: 5%;
|
|
|
|
+ height: 3%;
|
|
|
|
+ position: absolute;
|
|
|
|
+ right: 40px;
|
|
|
|
+ bottom: 20px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.navBarBox {
|
|
|
|
+ position: fixed;
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ width: 100vw;
|
|
|
|
+ z-index: 2;
|
|
|
|
+ height: 7vh;
|
|
|
|
+ top: 0;
|
|
|
|
+ background-color: white;
|
|
|
|
+ right: 0;
|
|
|
|
+ border-bottom: 1px solid gainsboro;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 调整LOGO */
|
|
|
|
+.logoBox {
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
+ left: 30px;
|
|
|
|
+ position: relative;
|
|
|
|
+
|
|
|
|
+ display: flex;
|
|
|
|
+ justify-content: space-between;
|
|
|
|
+ align-items: center;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.gameSelect {
|
|
|
|
+ position: relative;
|
|
|
|
+
|
|
|
|
+ height: 80%;
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ left: 5%;
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.gameIcon {
|
|
|
|
+ /* box-sizing: border-box; */
|
|
|
|
+ /* padding-right: 12px; */
|
|
|
|
+ margin-right: 12px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.navBarMenu {
|
|
|
|
+ width: 60%;
|
|
|
|
+ position: relative;
|
|
|
|
+ left: 6%;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.headPortraitBox {
|
|
|
|
+ position: absolute;
|
|
|
|
+ right: 3%;
|
|
|
|
+ top: 50%;
|
|
|
|
+ transform: translateY(-50%);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.userTools {
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 100%;
|
|
|
|
+ display: flex;
|
|
|
|
+ flex-direction: column;
|
|
|
|
+ justify-content: space-around;
|
|
|
|
+ align-items: center;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.userToolsItem {
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 4vh;
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ justify-content: center;
|
|
|
|
+ /* padding: 10px; */
|
|
|
|
+ margin: 2%;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.userToolsItem > span {
|
|
|
|
+ margin-left: 10%;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.userToolsItem:hover {
|
|
|
|
+ background-color: #f2f3f5;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.headPortrait {
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ width: 50px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.content {
|
|
|
|
+ /* flex-grow: 1; */
|
|
|
|
+ /* position: absolute; */
|
|
|
|
+
|
|
|
|
+ width: 100%;
|
|
|
|
+ /* height: 93%; */
|
|
|
|
+ margin-top: 7vh;
|
|
|
|
+ overflow: scroll;
|
|
|
|
+ background-color: #f2f3f5;
|
|
|
|
+ right: 0vw;
|
|
|
|
+ top: 0vh;
|
|
|
|
+}
|
|
|
|
+</style>
|
|
|
|
+
|
|
|
|
+<!-- 为了让popper-class生效,需要的单独写一份 -->
|
|
|
|
+<style>
|
|
|
|
+.headPopper {
|
|
|
|
+ padding: 0px !important;
|
|
|
|
+ border: 1px solid #e5e6eb;
|
|
|
|
+
|
|
|
|
+ background-color: white;
|
|
|
|
+}
|
|
|
|
+.el-menu--horizontal.el-menu {
|
|
|
|
+ border-bottom: none;
|
|
|
|
+}
|
|
|
|
+</style>
|