fxs пре 9 месеци
родитељ
комит
41d8d5b740

+ 9 - 0
auto-imports.d.ts

@@ -0,0 +1,9 @@
+/* eslint-disable */
+/* prettier-ignore */
+// @ts-nocheck
+// noinspection JSUnusedGlobalSymbols
+// Generated by unplugin-auto-import
+export {}
+declare global {
+
+}

+ 32 - 0
components.d.ts

@@ -0,0 +1,32 @@
+/* eslint-disable */
+// @ts-nocheck
+// Generated by unplugin-vue-components
+// Read more: https://github.com/vuejs/core/pull/3399
+export {}
+
+/* prettier-ignore */
+declare module 'vue' {
+  export interface GlobalComponents {
+    ElAffix: typeof import('element-plus/es')['ElAffix']
+    ElAvatar: typeof import('element-plus/es')['ElAvatar']
+    ElIcon: typeof import('element-plus/es')['ElIcon']
+    ElImage: typeof import('element-plus/es')['ElImage']
+    ElMenu: typeof import('element-plus/es')['ElMenu']
+    ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
+    ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup']
+    ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
+    HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
+    IconCommunity: typeof import('./src/components/icons/IconCommunity.vue')['default']
+    IconDocumentation: typeof import('./src/components/icons/IconDocumentation.vue')['default']
+    IconEcosystem: typeof import('./src/components/icons/IconEcosystem.vue')['default']
+    IconEpHistogram: typeof import('~icons/ep/histogram')['default']
+    IconEpPieChart: typeof import('~icons/ep/pie-chart')['default']
+    IconSupport: typeof import('./src/components/icons/IconSupport.vue')['default']
+    IconTooling: typeof import('./src/components/icons/IconTooling.vue')['default']
+    RouterLink: typeof import('vue-router')['RouterLink']
+    RouterView: typeof import('vue-router')['RouterView']
+    Table: typeof import('./src/components/Table.vue')['default']
+    TheWelcome: typeof import('./src/components/TheWelcome.vue')['default']
+    WelcomeItem: typeof import('./src/components/WelcomeItem.vue')['default']
+  }
+}

Разлика између датотеке није приказан због своје велике величине
+ 725 - 5
package-lock.json


+ 8 - 0
package.json

@@ -13,11 +13,16 @@
     "format": "prettier --write src/"
   },
   "dependencies": {
+    "@element-plus/icons-vue": "^2.3.1",
+    "axios": "^1.7.4",
+    "echarts": "^5.5.1",
+    "element-plus": "^2.8.0",
     "pinia": "^2.1.7",
     "vue": "^3.4.29",
     "vue-router": "^4.3.3"
   },
   "devDependencies": {
+    "@iconify-json/ep": "^1.1.16",
     "@rushstack/eslint-patch": "^1.8.0",
     "@tsconfig/node20": "^20.1.4",
     "@types/node": "^20.14.5",
@@ -30,6 +35,9 @@
     "npm-run-all2": "^6.2.0",
     "prettier": "^3.2.5",
     "typescript": "~5.4.0",
+    "unplugin-auto-import": "^0.18.2",
+    "unplugin-icons": "^0.19.2",
+    "unplugin-vue-components": "^0.27.4",
     "vite": "^5.3.1",
     "vue-tsc": "^2.0.21"
   }

+ 147 - 57
src/App.vue

@@ -1,85 +1,175 @@
 <script setup lang="ts">
-import { RouterLink, RouterView } from 'vue-router'
-import HelloWorld from './components/HelloWorld.vue'
+import { RouterView } from 'vue-router'
+import { ref } from 'vue'
+import { fi } from 'element-plus/es/locales.mjs'
+
+const isCollapse = ref(false)
+const menuList = [
+  {
+    title: '数据总览',
+    icon: 'PieChart',
+    children: [
+      {
+        pathName: 'OverView',
+        title: '工作台'
+      }
+    ]
+  },
+  {
+    title: '信息管理',
+    icon: 'Histogram',
+    children: [
+      {
+        pathName: 'GameManageView',
+        title: '游戏管理'
+      },
+      {
+        pathName: 'PlayerManageView',
+        title: '玩家管理'
+      }
+    ]
+  }
+]
+
+const changeCollapse = () => {
+  isCollapse.value = !isCollapse.value
+}
 </script>
 
 <template>
-  <header>
-    <img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />
-
-    <div class="wrapper">
-      <HelloWorld msg="You did it!" />
-
-      <nav>
-        <RouterLink to="/">Home</RouterLink>
-        <RouterLink to="/about">About</RouterLink>
-      </nav>
+  <div class="body">
+    <div class="sideBarBox">
+      <el-menu :router="true" :default-active="$route.name" class="sideBar" :collapse="isCollapse">
+        <el-menu-item index="/" class="logoBox">
+          <el-image :fit="'fill'" class="logoImg" src="/src/assets/logo.svg"></el-image>
+          <template #title><span class="logoText">淳皓科技</span></template>
+        </el-menu-item>
+        <el-sub-menu v-for="item in menuList" :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>
+        <div class="sideBarFold" @click="changeCollapse">
+          <el-icon :size="25"><Fold /></el-icon>
+        </div>
+      </el-menu>
     </div>
-  </header>
-
-  <RouterView />
+    <div class="navBarBox">
+      <div class="headPortraitBox">
+        <!-- <el-avatar :size="40" src="/src/assets/default/defaultHead.png" /> -->
+        <el-image class="headPortrait" src="/src/assets/default/defaultHead.png"></el-image>
+      </div>
+    </div>
+    <div class="content">
+      <RouterView />
+    </div>
+  </div>
 </template>
 
 <style scoped>
-header {
-  line-height: 1.5;
-  max-height: 100vh;
+.body {
+  width: 100%;
+  display: flex;
+  height: 100vh;
 }
 
-.logo {
-  display: block;
-  margin: 0 auto 2rem;
+/* 设置宽度后,content无法适应宽度,只能去间接的调整内部元素的宽度 */
+.sideBarBox {
+  position: relative;
+  /* width: 12%; */
+  z-index: 2;
+  height: 100vh;
+  top: 0;
 }
 
-nav {
-  width: 100%;
-  font-size: 12px;
-  text-align: center;
-  margin-top: 2rem;
+.sideBar {
+  /* width: 12vw; */
+  height: 100vh;
+  position: relative;
+  overflow: scroll;
 }
 
-nav a.router-link-exact-active {
-  color: var(--color-text);
+/* 设置弹出层的样式 */
+.el-popper > .logoText {
+  width: 100px;
+  font-size: 16px;
+  /* color: red; */
 }
 
-nav a.router-link-exact-active:hover {
-  background-color: transparent;
+/* 调整LOGO */
+.logoBox {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
 }
 
-nav a {
-  display: inline-block;
-  padding: 0 1rem;
-  border-left: 1px solid var(--color-border);
+.logoImg {
+  display: flex;
+  align-items: center;
+  width: 33px;
+  /* margin-right: 20px; */
+  /* height: 50px; */
 }
 
-nav a:first-of-type {
-  border: 0;
+.logoText {
+  width: 80%;
+  height: 100%;
+  margin-left: 15%;
+  display: flex;
+  font-size: 18px;
+  align-items: center;
+  /* background-color: lightcoral; */
 }
 
-@media (min-width: 1024px) {
-  header {
-    display: flex;
-    place-items: center;
-    padding-right: calc(var(--section-gap) / 2);
-  }
+/* 主要用来调整整个menu的宽度 */
+.menuTitle {
+  margin-right: 40px;
+}
 
-  .logo {
-    margin: 0 2rem 0 0;
-  }
+.sideBarFold {
+  width: 5%;
+  height: 3%;
+  position: absolute;
+  right: 40px;
+  bottom: 20px;
+}
 
-  header .wrapper {
-    display: flex;
-    place-items: flex-start;
-    flex-wrap: wrap;
-  }
+.navBarBox {
+  position: fixed;
+  width: 100vw;
+  z-index: 1;
+  height: 7vh;
+  top: 0;
+  background-color: white;
+  right: 0;
+  border-bottom: 1px solid gainsboro;
+}
 
-  nav {
-    text-align: left;
-    margin-left: -1rem;
-    font-size: 1rem;
+.headPortraitBox {
+  /* width: 5vw; */
+  /* height: 5vh; */
+  position: absolute;
+  right: 3%;
+  top: 50%;
+  transform: translateY(-50%);
+}
 
-    padding: 1rem 0;
-    margin-top: 1rem;
-  }
+.headPortrait {
+  cursor: pointer;
+  width: 50px;
+}
+
+.content {
+  /* flex-grow: 1; */
+  /* position: absolute; */
+
+  width: 100%;
+  height: 100%;
+  overflow: scroll;
+  background-color: lightcoral;
+  right: 0vw;
+  top: 0vh;
 }
 </style>

+ 22 - 83
src/assets/base.css

@@ -1,86 +1,25 @@
-/* color palette from <https://github.com/vuejs/theme> */
-:root {
-  --vt-c-white: #ffffff;
-  --vt-c-white-soft: #f8f8f8;
-  --vt-c-white-mute: #f2f2f2;
-
-  --vt-c-black: #181818;
-  --vt-c-black-soft: #222222;
-  --vt-c-black-mute: #282828;
-
-  --vt-c-indigo: #2c3e50;
-
-  --vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
-  --vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
-  --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
-  --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
-
-  --vt-c-text-light-1: var(--vt-c-indigo);
-  --vt-c-text-light-2: rgba(60, 60, 60, 0.66);
-  --vt-c-text-dark-1: var(--vt-c-white);
-  --vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
+::-webkit-scrollbar {
+  display: none;
 }
-
-/* semantic color variables for this project */
-:root {
-  --color-background: var(--vt-c-white);
-  --color-background-soft: var(--vt-c-white-soft);
-  --color-background-mute: var(--vt-c-white-mute);
-
-  --color-border: var(--vt-c-divider-light-2);
-  --color-border-hover: var(--vt-c-divider-light-1);
-
-  --color-heading: var(--vt-c-text-light-1);
-  --color-text: var(--vt-c-text-light-1);
-
-  --section-gap: 160px;
-}
-
-@media (prefers-color-scheme: dark) {
-  :root {
-    --color-background: var(--vt-c-black);
-    --color-background-soft: var(--vt-c-black-soft);
-    --color-background-mute: var(--vt-c-black-mute);
-
-    --color-border: var(--vt-c-divider-dark-2);
-    --color-border-hover: var(--vt-c-divider-dark-1);
-
-    --color-heading: var(--vt-c-text-dark-1);
-    --color-text: var(--vt-c-text-dark-2);
-  }
-}
-
-*,
-*::before,
-*::after {
-  box-sizing: border-box;
+html,
+body,
+ul,
+li,
+ol,
+dl,
+dd,
+dt,
+p,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+form,
+fieldset,
+legend,
+img {
   margin: 0;
-  font-weight: normal;
-}
-
-body {
-  min-height: 100vh;
-  color: var(--color-text);
-  background: var(--color-background);
-  transition:
-    color 0.5s,
-    background-color 0.5s;
-  line-height: 1.6;
-  font-family:
-    Inter,
-    -apple-system,
-    BlinkMacSystemFont,
-    'Segoe UI',
-    Roboto,
-    Oxygen,
-    Ubuntu,
-    Cantarell,
-    'Fira Sans',
-    'Droid Sans',
-    'Helvetica Neue',
-    sans-serif;
-  font-size: 15px;
-  text-rendering: optimizeLegibility;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
+  padding: 0;
 }

BIN
src/assets/default/defaultHead.png


+ 1 - 1
src/assets/logo.svg

@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1724143653276" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10671" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M1.276808 0h261.66407v261.66407H1.276808z" fill="#B7DCEE" p-id="10672"></path><path d="M410.685346 131.151137h261.66407v261.66407h-261.66407zM760.740815 241.241508H1022.404885v261.66407h-261.66407z" fill="#9BCFE8" p-id="10673"></path><path d="M760.740815 501.310065H1022.404885v261.66407h-261.66407z" fill="#2B99CE" p-id="10674"></path><path d="M760.740815 762.33593H1022.404885v261.66407h-261.66407z" fill="#1A79B4" p-id="10675"></path><path d="M499.076746 501.310065h261.664069v261.66407h-261.664069z" fill="#9BCFE8" p-id="10676"></path><path d="M499.076746 762.33593h261.664069v261.66407h-261.664069z" fill="#2B99CE" p-id="10677"></path><path d="M238.050881 762.33593h261.66407v261.66407h-261.66407zM110.728974 411.961359h261.66407v261.664069h-261.66407z" fill="#9BCFE8" p-id="10678"></path></svg>

+ 0 - 35
src/assets/main.css

@@ -1,35 +0,0 @@
-@import './base.css';
-
-#app {
-  max-width: 1280px;
-  margin: 0 auto;
-  padding: 2rem;
-  font-weight: normal;
-}
-
-a,
-.green {
-  text-decoration: none;
-  color: hsla(160, 100%, 37%, 1);
-  transition: 0.4s;
-  padding: 3px;
-}
-
-@media (hover: hover) {
-  a:hover {
-    background-color: hsla(160, 100%, 37%, 0.2);
-  }
-}
-
-@media (min-width: 1024px) {
-  body {
-    display: flex;
-    place-items: center;
-  }
-
-  #app {
-    display: grid;
-    grid-template-columns: 1fr 1fr;
-    padding: 0 2rem;
-  }
-}

+ 0 - 41
src/components/HelloWorld.vue

@@ -1,41 +0,0 @@
-<script setup lang="ts">
-defineProps<{
-  msg: string
-}>()
-</script>
-
-<template>
-  <div class="greetings">
-    <h1 class="green">{{ msg }}</h1>
-    <h3>
-      You’ve successfully created a project with
-      <a href="https://vitejs.dev/" target="_blank" rel="noopener">Vite</a> +
-      <a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>. What's next?
-    </h3>
-  </div>
-</template>
-
-<style scoped>
-h1 {
-  font-weight: 500;
-  font-size: 2.6rem;
-  position: relative;
-  top: -10px;
-}
-
-h3 {
-  font-size: 1.2rem;
-}
-
-.greetings h1,
-.greetings h3 {
-  text-align: center;
-}
-
-@media (min-width: 1024px) {
-  .greetings h1,
-  .greetings h3 {
-    text-align: left;
-  }
-}
-</style>

+ 17 - 0
src/components/Table.vue

@@ -0,0 +1,17 @@
+<script setup lang="ts">
+import { ref } from 'vue'
+</script>
+
+<template>
+  <div class="tableContent">
+    <div class="filterBox">
+      <!-- slot -->
+    </div>
+    <div class="tableBox">
+      <div class="tableTools"></div>
+      <div class="tableBody"></div>
+    </div>
+  </div>
+</template>
+
+<style scoped></style>

+ 0 - 88
src/components/TheWelcome.vue

@@ -1,88 +0,0 @@
-<script setup lang="ts">
-import WelcomeItem from './WelcomeItem.vue'
-import DocumentationIcon from './icons/IconDocumentation.vue'
-import ToolingIcon from './icons/IconTooling.vue'
-import EcosystemIcon from './icons/IconEcosystem.vue'
-import CommunityIcon from './icons/IconCommunity.vue'
-import SupportIcon from './icons/IconSupport.vue'
-</script>
-
-<template>
-  <WelcomeItem>
-    <template #icon>
-      <DocumentationIcon />
-    </template>
-    <template #heading>Documentation</template>
-
-    Vue’s
-    <a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
-    provides you with all information you need to get started.
-  </WelcomeItem>
-
-  <WelcomeItem>
-    <template #icon>
-      <ToolingIcon />
-    </template>
-    <template #heading>Tooling</template>
-
-    This project is served and bundled with
-    <a href="https://vitejs.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
-    recommended IDE setup is
-    <a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a> +
-    <a href="https://github.com/johnsoncodehk/volar" target="_blank" rel="noopener">Volar</a>. If
-    you need to test your components and web pages, check out
-    <a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a> and
-    <a href="https://on.cypress.io/component" target="_blank" rel="noopener"
-      >Cypress Component Testing</a
-    >.
-
-    <br />
-
-    More instructions are available in <code>README.md</code>.
-  </WelcomeItem>
-
-  <WelcomeItem>
-    <template #icon>
-      <EcosystemIcon />
-    </template>
-    <template #heading>Ecosystem</template>
-
-    Get official tools and libraries for your project:
-    <a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
-    <a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
-    <a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
-    <a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
-    you need more resources, we suggest paying
-    <a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
-    a visit.
-  </WelcomeItem>
-
-  <WelcomeItem>
-    <template #icon>
-      <CommunityIcon />
-    </template>
-    <template #heading>Community</template>
-
-    Got stuck? Ask your question on
-    <a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>, our official
-    Discord server, or
-    <a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
-      >StackOverflow</a
-    >. You should also subscribe to
-    <a href="https://news.vuejs.org" target="_blank" rel="noopener">our mailing list</a> and follow
-    the official
-    <a href="https://twitter.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
-    twitter account for latest news in the Vue world.
-  </WelcomeItem>
-
-  <WelcomeItem>
-    <template #icon>
-      <SupportIcon />
-    </template>
-    <template #heading>Support Vue</template>
-
-    As an independent project, Vue relies on community backing for its sustainability. You can help
-    us by
-    <a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
-  </WelcomeItem>
-</template>

+ 0 - 87
src/components/WelcomeItem.vue

@@ -1,87 +0,0 @@
-<template>
-  <div class="item">
-    <i>
-      <slot name="icon"></slot>
-    </i>
-    <div class="details">
-      <h3>
-        <slot name="heading"></slot>
-      </h3>
-      <slot></slot>
-    </div>
-  </div>
-</template>
-
-<style scoped>
-.item {
-  margin-top: 2rem;
-  display: flex;
-  position: relative;
-}
-
-.details {
-  flex: 1;
-  margin-left: 1rem;
-}
-
-i {
-  display: flex;
-  place-items: center;
-  place-content: center;
-  width: 32px;
-  height: 32px;
-
-  color: var(--color-text);
-}
-
-h3 {
-  font-size: 1.2rem;
-  font-weight: 500;
-  margin-bottom: 0.4rem;
-  color: var(--color-heading);
-}
-
-@media (min-width: 1024px) {
-  .item {
-    margin-top: 0;
-    padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
-  }
-
-  i {
-    top: calc(50% - 25px);
-    left: -26px;
-    position: absolute;
-    border: 1px solid var(--color-border);
-    background: var(--color-background);
-    border-radius: 8px;
-    width: 50px;
-    height: 50px;
-  }
-
-  .item:before {
-    content: ' ';
-    border-left: 1px solid var(--color-border);
-    position: absolute;
-    left: 0;
-    bottom: calc(50% + 25px);
-    height: calc(50% - 25px);
-  }
-
-  .item:after {
-    content: ' ';
-    border-left: 1px solid var(--color-border);
-    position: absolute;
-    left: 0;
-    top: calc(50% + 25px);
-    height: calc(50% - 25px);
-  }
-
-  .item:first-of-type:before {
-    display: none;
-  }
-
-  .item:last-of-type:after {
-    display: none;
-  }
-}
-</style>

+ 0 - 7
src/components/icons/IconCommunity.vue

@@ -1,7 +0,0 @@
-<template>
-  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
-    <path
-      d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
-    />
-  </svg>
-</template>

+ 0 - 7
src/components/icons/IconDocumentation.vue

@@ -1,7 +0,0 @@
-<template>
-  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
-    <path
-      d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
-    />
-  </svg>
-</template>

+ 0 - 7
src/components/icons/IconEcosystem.vue

@@ -1,7 +0,0 @@
-<template>
-  <svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
-    <path
-      d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
-    />
-  </svg>
-</template>

+ 0 - 7
src/components/icons/IconSupport.vue

@@ -1,7 +0,0 @@
-<template>
-  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
-    <path
-      d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
-    />
-  </svg>
-</template>

+ 0 - 19
src/components/icons/IconTooling.vue

@@ -1,19 +0,0 @@
-<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
-<template>
-  <svg
-    xmlns="http://www.w3.org/2000/svg"
-    xmlns:xlink="http://www.w3.org/1999/xlink"
-    aria-hidden="true"
-    role="img"
-    class="iconify iconify--mdi"
-    width="24"
-    height="24"
-    preserveAspectRatio="xMidYMid meet"
-    viewBox="0 0 24 24"
-  >
-    <path
-      d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
-      fill="currentColor"
-    ></path>
-  </svg>
-</template>

+ 50 - 0
src/hooks/useRequest.ts

@@ -0,0 +1,50 @@
+import { ElMessage } from 'element-plus'
+
+import type { AxiosResponse } from 'axios'
+import type { ResponseInfo } from '@/types/res'
+
+export function useRequest() {
+  const baseIp = 'http://server.ichunhao.cn'
+
+  const AllApi = {
+    getGameTable: `${baseIp}/user/getGidConfig`, // 获取游戏列表
+    getUserTable: `${baseIp}/user/userList`, // 获取用户列表
+    addGame: `${baseIp}/user/addGidConfig`, // 添加/修改 游戏配置
+    userLogin: `${baseIp}/user/login`, // 登录
+    addOption: `${baseIp}/user/addUserOption`, // 添加/修改 权限
+    addUserToBlack: `${baseIp}/user/addUserToBlackList`, // 封禁用户
+    deleteUserToBlack: `${baseIp}/user/deleteUserToBlackList`, // 解封用户
+    getInterfaceInfo: `${baseIp}/user/getInterfaceInfo`, // 拿到所有接口的信息
+    getInterfaceDataByDay: `${baseIp}/user/getInterfaceDataByDay`, //获取接口的请求频次 (按天)
+    gerRefreshToken: `${baseIp}/user/refreshToken`, // 刷新token
+    getOverViewData: `${baseIp}/user/overview` // 总览数据
+  }
+
+  const analysisResCode = (data: AxiosResponse, kind?: string): Promise<ResponseInfo> => {
+    return new Promise((resolve, reject) => {
+      let info = JSON.parse(JSON.stringify(data)) as ResponseInfo
+      let type: string = 'success'
+      let message: string = info.msg
+      let kindText = kind === 'login' ? '登录' : '请求'
+      switch (info.code) {
+        case 0:
+          {
+            type = 'success'
+            message = `${kindText}成功`
+            resolve(info)
+          }
+          break
+        default: {
+          type = 'error'
+          reject(info.msg)
+        }
+      }
+      ElMessage.success(message)
+    })
+  }
+
+  return {
+    AllApi,
+    analysisResCode
+  }
+}

+ 34 - 0
src/hooks/useTable.ts

@@ -0,0 +1,34 @@
+import axiosInstance from '../utils/axios/axiosInstance'
+import { useRequest } from './useRequest'
+import type { TablePaginationSetting } from '@/types/table'
+
+export function useTable(tableData: Array<any>, paginationSetting: TablePaginationSetting) {
+  const { AllApi, analysisResCode } = useRequest()
+
+  const getTableData = (url: string, option: any, isPagination: boolean = false) => {
+    return new Promise(async (reslove, reject) => {
+      try {
+        await axiosInstance.post(url, option).then((data) => {
+          analysisResCode(data)
+            .then((info) => {
+              let data = info.data
+              if (isPagination) {
+                tableData[paginationSetting.currentPage] = []
+              } else {
+                tableData.splice(0, tableData.length, ...data)
+              }
+              paginationSetting.total = data.count
+              reslove(true)
+            })
+            .catch((err) => {
+              console.log(err)
+            })
+        })
+      } catch {}
+    })
+  }
+
+  return {
+    getTableData
+  }
+}

+ 5 - 4
src/main.ts

@@ -1,13 +1,14 @@
-import './assets/main.css'
-
 import { createApp } from 'vue'
 import { createPinia } from 'pinia'
-
+import * as ElementPlusIconsVue from '@element-plus/icons-vue'
+import './assets/base.css'
 import App from './App.vue'
 import router from './router'
 
 const app = createApp(App)
-
+for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
+  app.component(key, component)
+}
 app.use(createPinia())
 app.use(router)
 

+ 39 - 0
src/router/home.ts

@@ -0,0 +1,39 @@
+import GameManageView from '../views/Home/GameManageView.vue'
+import OverView from '../views/Home/OverView.vue'
+import PlayerManageView from '../views/Home/PlayerManageView.vue'
+
+export default [
+  {
+    path: '/home',
+    children: [
+      {
+        path: '',
+        redirect: 'gameOverview'
+      },
+      {
+        path: 'overView',
+        name: 'OverView',
+        component: OverView,
+        meta: {
+          needKeepAlive: true
+        }
+      },
+      {
+        path: 'playerManageView/:gid?',
+        name: 'PlayerManageView',
+        component: PlayerManageView,
+        meta: {
+          needKeepAlive: false
+        }
+      },
+      {
+        path: 'gameManageView',
+        name: 'GameManageView',
+        component: GameManageView,
+        meta: {
+          needKeepAlive: true
+        }
+      }
+    ]
+  }
+]

+ 19 - 19
src/router/index.ts

@@ -1,23 +1,23 @@
-import { createRouter, createWebHistory } from 'vue-router'
-import HomeView from '../views/HomeView.vue'
+import { createRouter, createWebHashHistory } from 'vue-router'
+
+import HomeRoutes from './home'
+import LoginRoutes from './login'
+
+const routes = [
+  ...HomeRoutes,
+  ...LoginRoutes,
+  {
+    path: '/',
+    redirect: '/home/overView'
+  },
+  {
+    path: '/:pathMach(.*)',
+    redirect: '/'
+  }
+]
 
 const router = createRouter({
-  history: createWebHistory(import.meta.env.BASE_URL),
-  routes: [
-    {
-      path: '/',
-      name: 'home',
-      component: HomeView
-    },
-    {
-      path: '/about',
-      name: 'about',
-      // route level code-splitting
-      // this generates a separate chunk (About.[hash].js) for this route
-      // which is lazy-loaded when the route is visited.
-      component: () => import('../views/AboutView.vue')
-    }
-  ]
+  history: createWebHashHistory(),
+  routes
 })
-
 export default router

+ 8 - 0
src/router/login.ts

@@ -0,0 +1,8 @@
+import LoginView from '../views/Login/LoginView.vue'
+export default [
+  {
+    path: '/login',
+    name: 'Login',
+    component: LoginView
+  }
+]

+ 5 - 0
src/types/res.ts

@@ -0,0 +1,5 @@
+export interface ResponseInfo {
+  code: number
+  msg: string
+  data: any
+}

+ 8 - 0
src/types/table.ts

@@ -0,0 +1,8 @@
+export interface TablePaginationSetting {
+  limit: number // 每页展示个数
+  currentPage: number // 当前页码
+  total: number // 数据总数
+  pagesizeList: Array<number> // 页数大小列表
+  loading: boolean // 加载图标
+  hasLodingData: number // 已经加载的数据
+}

+ 58 - 0
src/utils/axios/axiosInstance.ts

@@ -0,0 +1,58 @@
+// 引入axios
+import axios from 'axios'
+import router from '../router'
+import { ElMessage } from 'element-plus'
+import { useReq } from '../hooks/useReq'
+
+const { AllGameTableAPI } = useReq()
+// import qs from "qs";
+// 创建axios实例
+const axiosInstance = axios.create()
+// 请求拦截器
+axiosInstance.interceptors.request.use(
+  function (config) {
+    // console.log(config);
+    if (config.url === AllGameTableAPI.gerRefreshToken) {
+      let refreshToken = localStorage.getItem('refreshToken')
+      if (refreshToken) {
+        config.headers.Authorization = refreshToken
+      }
+    } else if (config.url !== AllGameTableAPI.userLogin) {
+      let token = localStorage.getItem('token')
+
+      if (token) {
+        config.headers.Authorization = token
+      }
+    }
+
+    // 在发送请求之前做些什么
+    return config
+  },
+  function (error) {
+    // 对请求错误做些什么
+    return Promise.reject(error)
+  }
+)
+// 添加响应拦截器
+axiosInstance.interceptors.response.use(
+  function (response) {
+    // 对响应数据做点什么
+    if (response.data.code === -1) {
+      localStorage.removeItem('token')
+      localStorage.removeItem('refreshToken')
+      ElMessage({
+        type: 'warning',
+        message: '登录已过期,请重新登陆',
+        duration: 1500
+      })
+      router.push('/login')
+    }
+    return response.data
+  },
+  function (error) {
+    // 对响应错误做点什么
+    return Promise.reject(error)
+  }
+)
+// 导出实例
+export default axiosInstance

+ 52 - 0
src/utils/echarts/CoreEcharts.ts

@@ -0,0 +1,52 @@
+import * as echarts from 'echarts/core'
+import { BarChart, LineChart } from 'echarts/charts'
+import {
+  TitleComponent,
+  TooltipComponent,
+  GridComponent,
+  // 数据集组件
+  DatasetComponent,
+  // 内置数据转换器组件 (filter, sort)
+  TransformComponent
+} from 'echarts/components'
+import { LabelLayout, UniversalTransition } from 'echarts/features'
+import { CanvasRenderer } from 'echarts/renderers'
+import type {
+  // 系列类型的定义后缀都为 SeriesOption
+  BarSeriesOption,
+  LineSeriesOption
+} from 'echarts/charts'
+import type {
+  // 组件类型的定义后缀都为 ComponentOption
+  TitleComponentOption,
+  TooltipComponentOption,
+  GridComponentOption,
+  DatasetComponentOption
+} from 'echarts/components'
+import type { ComposeOption } from 'echarts/core'
+
+// 通过 ComposeOption 来组合出一个只有必须组件和图表的 Option 类型
+type ECOption = ComposeOption<
+  | BarSeriesOption
+  | LineSeriesOption
+  | TitleComponentOption
+  | TooltipComponentOption
+  | GridComponentOption
+  | DatasetComponentOption
+>
+
+// 注册必须的组件
+echarts.use([
+  TitleComponent,
+  TooltipComponent,
+  GridComponent,
+  DatasetComponent,
+  TransformComponent,
+  BarChart,
+  LineChart,
+  LabelLayout,
+  UniversalTransition,
+  CanvasRenderer
+])
+
+export default echarts

+ 0 - 0
src/views/AboutView.vue → src/views/Home/GameManageView.vue


+ 15 - 0
src/views/Home/OverView.vue

@@ -0,0 +1,15 @@
+<template>
+  <div class="about">
+    <h1>This is an about page</h1>
+  </div>
+</template>
+
+<style>
+@media (min-width: 1024px) {
+  .about {
+    min-height: 100vh;
+    display: flex;
+    align-items: center;
+  }
+}
+</style>

+ 15 - 0
src/views/Home/PlayerManageView.vue

@@ -0,0 +1,15 @@
+<template>
+  <div class="about">
+    <h1>This is an about page</h1>
+  </div>
+</template>
+
+<style>
+@media (min-width: 1024px) {
+  .about {
+    min-height: 100vh;
+    display: flex;
+    align-items: center;
+  }
+}
+</style>

+ 0 - 9
src/views/HomeView.vue

@@ -1,9 +0,0 @@
-<script setup lang="ts">
-import TheWelcome from '../components/TheWelcome.vue'
-</script>
-
-<template>
-  <main>
-    <TheWelcome />
-  </main>
-</template>

+ 15 - 0
src/views/Login/LoginView.vue

@@ -0,0 +1,15 @@
+<template>
+  <div class="about">
+    <h1>This is an about page</h1>
+  </div>
+</template>
+
+<style>
+@media (min-width: 1024px) {
+  .about {
+    min-height: 100vh;
+    display: flex;
+    align-items: center;
+  }
+}
+</style>

+ 28 - 2
vite.config.ts

@@ -1,12 +1,38 @@
-import { fileURLToPath, URL } from 'node:url'
-
 import { defineConfig } from 'vite'
 import vue from '@vitejs/plugin-vue'
 
+import { fileURLToPath, URL } from 'node:url'
+import AutoImport from 'unplugin-auto-import/vite'
+import Components from 'unplugin-vue-components/vite'
+import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
+
+import Icons from 'unplugin-icons/vite'
+import IconsResolver from 'unplugin-icons/resolver'
+
 // https://vitejs.dev/config/
 export default defineConfig({
   plugins: [
     vue(),
+    AutoImport({
+      resolvers: [
+        ElementPlusResolver(),
+        IconsResolver({
+          enabledCollections: ['ep']
+        })
+      ]
+    }),
+    Components({
+      resolvers: [
+        ElementPlusResolver(),
+        IconsResolver({
+          prefix: 'icon',
+          enabledCollections: ['ep']
+        })
+      ]
+    }),
+    Icons({
+      autoInstall: true
+    })
   ],
   resolve: {
     alias: {

Неке датотеке нису приказане због велике количине промена