yangzj 2 سال پیش
والد
کامیت
ef817907a5

+ 2 - 0
.env.dev

@@ -0,0 +1,2 @@
+# 请求基础api
+VUE_APP_BASE_API = '/api'

+ 2 - 0
.env.prod

@@ -0,0 +1,2 @@
+# 请求基础api
+VUE_APP_BASE_API = '/api'

+ 1 - 0
.gitignore

@@ -1,6 +1,7 @@
 .DS_Store
 node_modules
 /dist
+.history
 
 
 # local env files

+ 3 - 0
package.json

@@ -8,7 +8,10 @@
     "lint": "vue-cli-service lint"
   },
   "dependencies": {
+    "axios": "^0.27.2",
     "core-js": "^3.8.3",
+    "element-ui": "^2.15.9",
+    "js-cookie": "^3.0.1",
     "register-service-worker": "^1.7.2",
     "vue": "^2.6.14",
     "vue-router": "^3.5.1",

+ 1 - 1
public/index.html

@@ -3,7 +3,7 @@
   <head>
     <meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
     <link rel="icon" href="<%= BASE_URL %>favicon.ico">
     <title><%= htmlWebpackPlugin.options.title %></title>
   </head>

+ 0 - 23
src/App.vue

@@ -1,32 +1,9 @@
 <template>
   <div id="app">
-    <nav>
-      <router-link to="/">Home</router-link> |
-      <router-link to="/about">About</router-link>
-    </nav>
     <router-view/>
   </div>
 </template>
 
 <style lang="scss">
-#app {
-  font-family: Avenir, Helvetica, Arial, sans-serif;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-  text-align: center;
-  color: #2c3e50;
-}
 
-nav {
-  padding: 30px;
-
-  a {
-    font-weight: bold;
-    color: #2c3e50;
-
-    &.router-link-exact-active {
-      color: #42b983;
-    }
-  }
-}
 </style>

+ 47 - 0
src/api/Home/index.js

@@ -0,0 +1,47 @@
+/**
+ * @Description: 首页api
+ * @Author: 空白格
+ * @Date: 2022-08-10 14:10:36
+ * @LastEditors: 空白格
+ * @LastEditTime: 2022-08-10 17:36:05
+ * @FilePath: \veterans_client_web\src\api\Home\index.js
+ * @Copyright: Copyright (c) 2016~2022 by 空白格, All Rights Reserved.
+ */
+import request from '@/utils/request'
+
+// 获取轮播图片
+export function getBannerList(params) {
+  return request({
+    url: '/app/sysadv/list',
+    method: 'get',
+    headers: {
+      noLoginFlag: true
+    },
+    params
+  })
+}
+
+// 获取新闻内容
+export function getNewsList(params) {
+  return request({
+    url: '/app/sec/article/door/list',
+    method: 'get',
+    headers: {
+      noLoginFlag: true
+    },
+    params
+  })
+}
+
+// 获取公告内容
+export function getNoticeList(params) {
+  return request({
+    url: '/app/notice/queryNewest',
+    method: 'get',
+    headers: {
+      noLoginFlag: true
+    },
+    params
+  })
+}
+

+ 28 - 0
src/api/Login/index.js

@@ -0,0 +1,28 @@
+/**
+ * @Description: 登录接口
+ * @Author: 空白格
+ * @Date: 2022-08-10 14:58:23
+ * @LastEditors: 空白格
+ * @LastEditTime: 2022-08-10 15:06:53
+ * @FilePath: \veterans_client_web\src\api\Login\index.js
+ * @Copyright: Copyright (c) 2016~2022 by 空白格, All Rights Reserved.
+ */
+import request from '@/utils/request'
+
+// 验证码验证登录
+export function loginAuthCode(data) {
+  return request({
+    url: '/auth/verifyCode',
+    method: 'post',
+    data
+  })
+}
+
+// 获取验证码
+export function getAuthCode(data) {
+  return request({
+    url: '/auth/sendSmsCode',
+    method: 'post',
+    data
+  })
+}

BIN
src/assets/images/default-news.jpg


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 35 - 0
src/assets/images/home-menu-icon/home-menu-icon-1.svg


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 30 - 0
src/assets/images/home-menu-icon/home-menu-icon-2.svg


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 35 - 0
src/assets/images/home-menu-icon/home-menu-icon-3.svg


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 36 - 0
src/assets/images/home-menu-icon/home-menu-icon-4.svg


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 36 - 0
src/assets/images/home-menu-icon/home-menu-icon-5.svg


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 37 - 0
src/assets/images/home-menu-icon/home-menu-icon-6.svg


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 35 - 0
src/assets/images/home-menu-icon/home-menu-icon-7.svg


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 27 - 0
src/assets/images/home-menu-icon/home-menu-icon-8.svg


+ 1 - 0
src/assets/styles/index.scss

@@ -0,0 +1 @@
+@import './reset.scss';

+ 138 - 0
src/assets/styles/reset.scss

@@ -0,0 +1,138 @@
+html,
+body,
+div,
+span,
+applet,
+object,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+p,
+blockquote,
+pre,
+a,
+abbr,
+acronym,
+address,
+big,
+cite,
+code,
+del,
+dfn,
+em,
+img,
+ins,
+kbd,
+q,
+s,
+samp,
+small,
+strike,
+strong,
+sub,
+sup,
+tt,
+var,
+b,
+u,
+i,
+center,
+dl,
+dt,
+dd,
+ol,
+ul,
+li,
+fieldset,
+form,
+label,
+legend,
+table,
+caption,
+tbody,
+tfoot,
+thead,
+tr,
+th,
+td,
+article,
+aside,
+canvas,
+details,
+embed,
+figure,
+figcaption,
+footer,
+header,
+hgroup,
+menu,
+nav,
+output,
+ruby,
+section,
+summary,
+time,
+mark,
+audio,
+video {
+  margin: 0;
+  padding: 0;
+  border: 0;
+  font-size: 100%;
+  font-family: PingFangSC;
+  font-weight: normal;
+  vertical-align: baseline;
+}
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+menu,
+nav,
+section {
+  display: block;
+}
+ol,
+ul,
+li {
+  list-style: none;
+}
+blockquote,
+q {
+  quotes: none;
+}
+blockquote:before,
+blockquote:after,
+q:before,
+q:after {
+  content: '';
+  content: none;
+}
+table {
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+th,
+td {
+  vertical-align: middle;
+}
+a {
+  outline: none;
+  color: #16418a;
+  text-decoration: none;
+}
+a:focus {
+  outline: none;
+}
+input:focus,
+select:focus,
+textarea:focus {
+  outline: -webkit-focus-ring-color auto 0;
+}

+ 0 - 61
src/components/HelloWorld.vue

@@ -1,61 +0,0 @@
-<template>
-  <div class="hello">
-    <h1>{{ msg }}</h1>
-    <p>
-      For a guide and recipes on how to configure / customize this project,<br>
-      check out the
-      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
-    </p>
-    <h3>Installed CLI Plugins</h3>
-    <ul>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa" target="_blank" rel="noopener">pwa</a></li>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex" target="_blank" rel="noopener">vuex</a></li>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
-    </ul>
-    <h3>Essential Links</h3>
-    <ul>
-      <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
-      <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
-      <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
-      <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
-      <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
-    </ul>
-    <h3>Ecosystem</h3>
-    <ul>
-      <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
-      <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
-      <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
-      <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
-      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
-    </ul>
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'HelloWorld',
-  props: {
-    msg: String
-  }
-}
-</script>
-
-<!-- Add "scoped" attribute to limit CSS to this component only -->
-<style scoped lang="scss">
-h3 {
-  margin: 40px 0 0;
-}
-ul {
-  list-style-type: none;
-  padding: 0;
-}
-li {
-  display: inline-block;
-  margin: 0 10px;
-}
-a {
-  color: #42b983;
-}
-</style>

+ 132 - 0
src/layout/index.vue

@@ -0,0 +1,132 @@
+<!--
+ * @Description: 共有头部
+ * @Author: 空白格
+ * @Date: 2022-08-10 11:30:36
+ * @LastEditors: 空白格
+ * @LastEditTime: 2022-08-10 15:36:48
+ * @FilePath: \veterans_client_web\src\layout\index.vue
+ * @Copyright: Copyright (c) 2016~2022 by 空白格, All Rights Reserved.
+-->
+<template>
+  <el-container>
+    <el-header class="header" height="60px">
+      <div class="header-box">
+        <div class="header-box-left">贵州退役军人教育培训</div>
+        <div class="header-box-right">
+          <div class="header-box-right-search">
+            <el-input
+              placeholder="请输入搜索内容"
+              size="small"
+              v-model="searchValue"
+            >
+              <i slot="prefix" class="el-input__icon el-icon-search"></i>
+            </el-input>
+          </div>
+          <div class="header-box-right-user" v-if="userInfo.userName">
+            下午好,{{ userInfo.userName }}
+          </div>
+          <div class="header-box-right-user" v-else>
+            下午好,请<router-link class="link" to="/login">登录</router-link>
+          </div>
+        </div>
+      </div>
+    </el-header>
+    <el-main class="main">
+      <router-view />
+    </el-main>
+    <el-footer class="footer" height="100px">
+      <div class="footer-link">
+        <router-link class="link" to="">关于我们</router-link> |
+        <router-link class="link" to="">加入收藏</router-link> |
+        <router-link class="link" to="">隐私声明</router-link> |
+        <router-link class="link" to="">网站地图</router-link> |
+        <router-link class="link" to="">联系我们</router-link> |
+        <router-link class="link" to="">网站年报</router-link>
+      </div>
+      <div class="footer-organizer">
+        主办单位:贵州省退役军人事务厅、黔CP备19001516号-1
+        网站标识码:5200000143
+      </div>
+    </el-footer>
+  </el-container>
+</template>
+
+<script>
+import { mapState } from "vuex";
+export default {
+  name: "Layout",
+  data() {
+    return {
+      searchValue: "",
+    };
+  },
+  computed: {
+    ...mapState({
+      userInfo: (state) => state.user.userInfo,
+    }),
+  },
+  created() {
+    console.log(this.userInfo);
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.header {
+  background-color: #3d5d4c;
+  height: 60px;
+  &-box {
+    width: 70%;
+    min-width: 600px;
+    height: 60px;
+    margin: 0 auto;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    &-left {
+      color: #fff;
+      font-size: 20px;
+    }
+    &-right {
+      display: flex;
+      align-items: center;
+      &-search {
+        ::v-deep .el-input__inner {
+          border-radius: 100px !important;
+        }
+      }
+      &-user {
+        color: #fff;
+        margin-left: 30px;
+        .link {
+          color: #fff;
+        }
+      }
+    }
+  }
+}
+.main {
+  min-height: calc(100vh - 160px);
+  background-color: #f2f2f2;
+  padding: 0;
+}
+.footer {
+  background-color: #3d5d4c;
+  opacity: 0.7;
+  height: 100px;
+  text-align: center;
+  color: #fff;
+  font-size: 12px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  &-link {
+    line-height: 30px;
+    .link {
+      color: #fff;
+      margin: 0 5px;
+    }
+  }
+}
+</style>

+ 5 - 0
src/main.js

@@ -3,6 +3,11 @@ import App from './App.vue'
 import './registerServiceWorker'
 import router from './router'
 import store from './store'
+import '@/assets/styles/index.scss'
+import ElementUI from 'element-ui'
+import 'element-ui/lib/theme-chalk/index.css'
+
+Vue.use(ElementUI)
 
 Vue.config.productionTip = false
 

+ 16 - 9
src/router/index.js

@@ -1,26 +1,33 @@
 import Vue from 'vue'
 import VueRouter from 'vue-router'
-import HomeView from '../views/HomeView.vue'
+import Layout from '@/layout'
 
 Vue.use(VueRouter)
 
 const routes = [
   {
     path: '/',
-    name: 'home',
-    component: HomeView
+    component: Layout,
+    children: [
+      {
+        path: '',
+        name: 'Index',
+        component: () => import('@/views/Home/HomeIndex.vue'),
+        meta: {
+          title: '首页'
+        }
+      }
+    ]
   },
   {
-    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(/* webpackChunkName: "about" */ '../views/AboutView.vue')
+    path: '/login',
+    name: 'Login',
+    component: () => import('@/views/Login/LoginIndex.vue')
   }
 ]
 
 const router = new VueRouter({
+  mode: 'history',
   routes
 })
 

+ 4 - 0
src/store/getters.js

@@ -0,0 +1,4 @@
+const getters = {
+  userInfo: (state) => state.user.userInfo
+};
+export default getters;

+ 5 - 9
src/store/index.js

@@ -1,17 +1,13 @@
 import Vue from 'vue'
 import Vuex from 'vuex'
+import getters from './getters'
+import user from './modules/user'
 
 Vue.use(Vuex)
 
 export default new Vuex.Store({
-  state: {
-  },
-  getters: {
-  },
-  mutations: {
-  },
-  actions: {
-  },
   modules: {
-  }
+    user
+  },
+  getters
 })

+ 60 - 0
src/store/modules/user.js

@@ -0,0 +1,60 @@
+/**
+ * @Description: 用户模块
+ * @Author: 空白格
+ * @Date: 2022-08-10 13:40:53
+ * @LastEditors: 空白格
+ * @LastEditTime: 2022-08-10 15:19:32
+ * @FilePath: \veterans_client_web\src\store\modules\user.js
+ * @Copyright: Copyright (c) 2016~2022 by 空白格, All Rights Reserved.
+ */
+import { getToken } from "@/utils/auth"
+import { loginAuthCode, getAuthCode } from "@/api/Login";
+const user = {
+  state: {
+    token: getToken(),
+    isLogin: false,
+    userInfo: {
+      userName: 'xxx'
+    }
+  },
+  mutations: {
+    SET_TOKEN: (state, token) => {
+      state.token = token;
+    },
+    SET_LOGIN_FLAG: (state, flag) => {
+      state.isLogin = flag;
+    }
+  },
+  actions: {
+    // 登录验证验证码
+    Login({ commit, state }, userInfo) {
+      return new Promise((resolve, reject) => {
+        loginAuthCode({
+          accessToken: state.user.token,
+					userId: userInfo.userId,
+					code: userInfo.code
+        })
+          .then(res => {
+            commit('SET_LOGIN_FLAG', true)
+            resolve()
+          })
+          .catch((error) => {
+            reject(error)
+          })
+      })
+    },
+    GetLoginCode({ commit }) {
+      return new Promise((resolve, reject) => {
+        getAuthCode()
+          .then(res => {
+            commit('SET_TOKEN', res.accessToken)
+            resolve(res)
+          })
+          .catch((error) => {
+            reject(error)
+          })
+      })
+    }
+  }
+}
+export default user

+ 29 - 0
src/utils/auth.js

@@ -0,0 +1,29 @@
+import Cookies from 'js-cookie';
+
+const TokenKey = 'Vetervas-Client-Web-Token';
+
+const ExpiresInKey = 'Vetervas-Client-Web-Expires-In';
+
+export function getToken(keyValue) {
+  return Cookies.get(keyValue || TokenKey);
+}
+
+export function setToken(token, keyValue) {
+  return Cookies.set(keyValue || TokenKey, token);
+}
+
+export function removeToken(keyValue) {
+  return Cookies.remove(keyValue || TokenKey);
+}
+
+export function getExpiresIn(keyValue) {
+  return Cookies.get(keyValue || ExpiresInKey) || -1;
+}
+
+export function setExpiresIn(time, keyValue) {
+  return Cookies.set(keyValue || ExpiresInKey, time);
+}
+
+export function removeExpiresIn(keyValue) {
+  return Cookies.remove(keyValue || ExpiresInKey);
+}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
src/utils/jsonlint.js


+ 97 - 0
src/utils/request.js

@@ -0,0 +1,97 @@
+import axios from 'axios';
+import { Notification, MessageBox, Message, Loading } from 'element-ui';
+import { getToken } from '@/utils/auth';
+import { tansParams } from '@/utils/utils'
+
+axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';
+
+// 创建axios实例
+const service = axios.create({
+  // axios中请求配置有baseURL选项,表示请求URL公共部分
+  baseURL: '/api',
+  // 超时
+  timeout: 60000
+});
+
+// request拦截器
+service.interceptors.request.use(
+  (config) => {
+    // 不需要token验证标识
+    if (config.headers.noLoginFlag) {
+      config.headers['noLoginFlag'] = true;
+    }
+    // 是否需要设置 token
+    const isToken = (config.headers || {}).isToken === false;
+
+    // 让每个请求携带自定义token 请根据实际情况自行修改
+    if (getToken() && !isToken) {
+      config.headers['Authorization'] = `Bearer ${getToken()}`;
+    }
+    // url拼接时间戳参数
+    config.url = `${config.url}?_t=${new Date().getTime()}`;
+    // get请求映射params参数
+    if (config.method === 'get' && config.params) {
+      let url = config.url + '&' + tansParams(config.params);
+      url = url.slice(0, -1);
+      config.params = {};
+      config.url = url;
+    }
+    return config;
+  },
+  (error) => {
+    Promise.reject(error);
+  }
+);
+
+// 响应拦截器
+service.interceptors.response.use(
+  (res) => {
+    // 未设置状态码则默认成功状态
+    const code = res.data.code || 200;
+    // 鉴权校验
+    if (code === 400) {
+      MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
+        confirmButtonText: '重新登录',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+
+        })
+        .catch(() => {
+          return Promise.reject('登录状态已过期,请重新登录。');
+        });
+    } else if (code === 500) {
+      Message({
+        message: msg,
+        type: 'error'
+      });
+      return Promise.reject(new Error(msg));
+    } else if (code !== 200) {
+      Notification.error({
+        title: res?.data?.msg
+      });
+      return Promise.reject('error');
+    } else {
+      return res.data;
+    }
+  },
+  (error) => {
+    let { message } = error;
+    if (message == 'Network Error') {
+      message = '后端接口连接异常';
+    } else if (message.includes('timeout')) {
+      message = '系统接口请求超时';
+    } else if (message.includes('Request failed with status code')) {
+      message = '系统接口' + message.substr(message.length - 3) + '异常';
+    }
+    Message({
+      message: message,
+      type: 'error',
+      duration: 5 * 1000
+    });
+    return Promise.reject(error);
+  }
+);
+
+export default service;

+ 89 - 0
src/utils/utils.js

@@ -0,0 +1,89 @@
+/**
+ * @Description:
+ * @Author: 空白格
+ * @Date: 2022-08-10 15:31:30
+ * @LastEditors: 空白格
+ * @LastEditTime: 2022-08-10 15:31:30
+ * @FilePath: \veterans_client_web\src\utils\utils.js
+ * @Copyright: Copyright (c) 2016~2022 by 空白格, All Rights Reserved.
+ */
+/**
+ * 参数处理
+ * @param {*} params  参数
+ */
+export function tansParams(params) {
+  let result = ''
+  for (const propName of Object.keys(params)) {
+    const value = params[propName]
+    var part = encodeURIComponent(propName) + '='
+    if (value !== null && value !== '' && typeof value !== 'undefined') {
+      if (typeof value === 'object') {
+        for (const key of Object.keys(value)) {
+          if (
+            value[key] !== null &&
+            value[key] !== '' &&
+            typeof value[key] !== 'undefined'
+          ) {
+            let params = propName + '[' + key + ']'
+            var subPart = encodeURIComponent(params) + '='
+            result += subPart + encodeURIComponent(value[key]) + '&'
+          }
+        }
+      } else {
+        result += part + encodeURIComponent(value) + '&'
+      }
+    }
+  }
+  return result
+}
+
+/**
+ * 日期格式化
+ * @param {*} time
+ * @param {*} pattern
+ * @returns
+ */
+export function parseTime(time, pattern) {
+  if (arguments.length === 0 || !time) {
+    return null
+  }
+  const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
+  let date
+  if (typeof time === 'object') {
+    date = time
+  } else {
+    if (typeof time === 'string' && /^[0-9]+$/.test(time)) {
+      time = parseInt(time)
+    } else if (typeof time === 'string') {
+      time = time
+        .replace(new RegExp(/-/gm), '/')
+        .replace('T', ' ')
+        .replace(new RegExp(/\.[\d]{3}/gm), '')
+    }
+    if (typeof time === 'number' && time.toString().length === 10) {
+      time = time * 1000
+    }
+    date = new Date(time)
+  }
+  const formatObj = {
+    y: date.getFullYear(),
+    m: date.getMonth() + 1,
+    d: date.getDate(),
+    h: date.getHours(),
+    i: date.getMinutes(),
+    s: date.getSeconds(),
+    a: date.getDay()
+  }
+  const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+    let value = formatObj[key]
+    // Note: getDay() returns 0 on Sunday
+    if (key === 'a') {
+      return ['日', '一', '二', '三', '四', '五', '六'][value]
+    }
+    if (result.length > 0 && value < 10) {
+      value = '0' + value
+    }
+    return value || 0
+  })
+  return time_str
+}

+ 0 - 5
src/views/AboutView.vue

@@ -1,5 +0,0 @@
-<template>
-  <div class="about">
-    <h1>This is an about page</h1>
-  </div>
-</template>

+ 349 - 0
src/views/Home/HomeIndex.vue

@@ -0,0 +1,349 @@
+<!--
+ * @Description: 首页
+ * @Author: 空白格
+ * @Date: 2022-08-10 11:26:40
+ * @LastEditors: 空白格
+ * @LastEditTime: 2022-08-10 17:38:49
+ * @FilePath: \veterans_client_web\src\views\Home\HomeIndex.vue
+ * @Copyright: Copyright (c) 2016~2022 by 空白格, All Rights Reserved.
+-->
+<template>
+  <div class="home">
+    <!-- 轮播图 -->
+    <div class="home-carousel">
+      <el-carousel :interval="2000" arrow="always" height="500px">
+        <el-carousel-item v-for="(item, index) in bannerList" :key="index">
+          <el-image class="image" :src="item.bannerUrl" fit="fill">
+            <div slot="placeholder" class="image-slot">
+              加载图片中<span class="dot">...</span>
+            </div>
+          </el-image>
+        </el-carousel-item>
+      </el-carousel>
+    </div>
+    <div class="home-main">
+      <div class="home-main-box">
+        <!-- 菜单部分 -->
+        <el-row :gutter="30" class="home-main-menu">
+          <el-col
+            :xs="12"
+            :sm="8"
+            :md="6"
+            :lg="3"
+            :xl="3"
+            v-for="(menu, index) in menuList"
+            :key="index"
+          >
+            <div class="home-main-menu-icon">
+              <el-image class="image" :src="menu.icon"></el-image>
+            </div>
+            <div class="home-main-menu-name">{{ menu.name }}</div>
+          </el-col>
+        </el-row>
+        <!-- 新闻部分 -->
+        <el-row :gutter="30" class="home-main-news">
+          <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
+            <div class="home-main-news-left">
+              <el-carousel :interval="100000" arrow="never" height="400px">
+                <el-carousel-item
+                  v-for="(item, index) in newsList"
+                  :key="index"
+                >
+                  <el-image
+                    class="image"
+                    :src="
+                      item.artImage ||
+                      require('@/assets/images/default-news.jpg')
+                    "
+                    fit="fill"
+                  >
+                    <div slot="placeholder" class="image-slot">
+                      加载图片中<span class="dot">...</span>
+                    </div>
+                    <div slot="error" class="image-slot">
+                      <el-image
+                        class="image"
+                        :src="require('@/assets/images/default-news.jpg')"
+                        fit="fill"
+                      ></el-image>
+                    </div>
+                  </el-image>
+                  <div class="title">
+                    {{ item.artTitle || "" }}
+                  </div>
+                </el-carousel-item>
+              </el-carousel>
+            </div>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
+            <div class="home-main-news-right">
+              <el-tabs v-model="activeName" @tab-click="handleClick">
+                <el-tab-pane label="新闻动态" name="first">
+                  <ul class="news-infomation">
+                    <li
+                      class="news-infomation-item"
+                      v-for="(item, index) in newsList"
+                      :key="index"
+                    >
+                      <div class="title">{{ item.artTitle }}</div>
+                      <div class="date">
+                        {{ parseTime(item.createTime, "{y}-{m}-{d}") }}
+                      </div>
+                    </li>
+                  </ul>
+                </el-tab-pane>
+                <el-tab-pane label="通知公告" name="second">
+                  <ul class="news-infomation">
+                    <li
+                      class="news-infomation-item"
+                      v-for="(item, index) in noticeList"
+                      :key="index"
+                    >
+                      <div class="title">{{ item.content }}</div>
+                      <div class="date">
+                        {{ parseTime(item.releasTime, "{y}-{m}-{d}") }}
+                      </div>
+                    </li>
+                  </ul>
+                </el-tab-pane>
+              </el-tabs>
+            </div>
+          </el-col>
+        </el-row>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { parseTime } from "@/utils/utils";
+import { getBannerList, getNewsList, getNoticeList } from "@/api/Home";
+export default {
+  name: "HomeIndex",
+  data() {
+    return {
+      bannerList: [],
+      menuList: [
+        {
+          name: "政策咨询",
+          icon: require("@/assets/images/home-menu-icon/home-menu-icon-1.svg"),
+        },
+        {
+          name: "招聘就业",
+          icon: require("@/assets/images/home-menu-icon/home-menu-icon-2.svg"),
+        },
+        {
+          name: "合作企业",
+          icon: require("@/assets/images/home-menu-icon/home-menu-icon-3.svg"),
+        },
+        {
+          name: "合作院校",
+          icon: require("@/assets/images/home-menu-icon/home-menu-icon-4.svg"),
+        },
+        {
+          name: "技能培训",
+          icon: require("@/assets/images/home-menu-icon/home-menu-icon-5.svg"),
+        },
+        {
+          name: "适应性培训",
+          icon: require("@/assets/images/home-menu-icon/home-menu-icon-6.svg"),
+        },
+        {
+          name: "学历提升",
+          icon: require("@/assets/images/home-menu-icon/home-menu-icon-7.svg"),
+        },
+        {
+          name: "创业指引",
+          icon: require("@/assets/images/home-menu-icon/home-menu-icon-8.svg"),
+        },
+      ],
+      newsList: [],
+      noticeList: [],
+      activeName: "first",
+      parseTime: parseTime,
+    };
+  },
+  created() {
+    this.initData();
+  },
+  methods: {
+    initData() {
+      this.getBanner();
+      this.getNews();
+      this.getNotice();
+    },
+    /**
+     * 获取轮播图
+     * @date 2022-08-10
+     * @returns {any}
+     */
+    getBanner() {
+      getBannerList({ type: 0 }).then((res) => {
+        this.bannerList = res.data;
+      });
+    },
+    /**
+     * 获取新闻
+     * @date 2022-08-10
+     * @returns {any}
+     */
+    getNews() {
+      getNewsList({
+        artCategoryId: 2,
+        pageNum: 1,
+        pageSize: 5,
+      }).then((res) => {
+        this.newsList = res.rows;
+      });
+    },
+    /**
+     * 获取公告
+     * @date 2022-08-10
+     * @returns {any}
+     */
+    getNotice() {
+      getNoticeList().then((res) => {
+        this.noticeList = res.data;
+      });
+    }
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.home {
+  &-carousel {
+    .image {
+      width: 100%;
+      height: 100%;
+    }
+    .image-slot {
+      line-height: 500px;
+      text-align: center;
+    }
+    ::v-deep .el-carousel__indicators {
+      // 指示器
+      bottom: 6%;
+    }
+    ::v-deep .el-carousel__button {
+      // 指示器按钮
+      width: 10px;
+      height: 10px;
+      border: none;
+      border-radius: 50%;
+      background-color: #fff;
+    }
+    ::v-deep .is-active .el-carousel__button {
+      // 指示器激活按钮
+      width: 20px;
+      border-radius: 10px;
+    }
+  }
+  &-main {
+    width: 70%;
+    margin: 0 auto;
+    min-width: 600px;
+    position: relative;
+    &-box {
+      width: 100%;
+      position: absolute;
+      top: -30px;
+      z-index: 1000;
+    }
+    &-menu {
+      width: 100%;
+      background-color: #fff;
+      padding: 30px 30px 0;
+      border-radius: 5px;
+      &-icon {
+        text-align: center;
+        .image {
+          width: 98px;
+          height: 98px;
+        }
+      }
+      &-name {
+        text-align: center;
+        margin-top: 20px;
+        margin-bottom: 30px;
+      }
+    }
+    &-news {
+      width: 100%;
+      background-color: #fff;
+      padding: 30px;
+      border-radius: 5px;
+      margin-top: 30px;
+      &-left {
+        .image {
+          width: 100%;
+          height: 100%;
+          border-radius: 5px;
+        }
+        .title {
+          width: calc(100% - 40px);
+          height: 40px;
+          line-height: 40px;
+          padding: 0 20px;
+          background-color: rgba($color: #000000, $alpha: 0.3);
+          color: #fff;
+          white-space: nowrap;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          word-break: break-all;
+          position: absolute;
+          bottom: 0;
+        }
+        ::v-deep .el-carousel__indicators {
+          // 指示器
+          left: auto;
+          right: -20px;
+        }
+        ::v-deep .el-carousel__button {
+          // 指示器按钮
+          width: 10px;
+          height: 10px;
+          border: none;
+          border-radius: 50%;
+          background-color: #fff;
+        }
+        ::v-deep .is-active .el-carousel__button {
+          // 指示器激活按钮
+          width: 20px;
+          border-radius: 10px;
+          background-color: #f00;
+        }
+      }
+      &-right {
+        .news-infomation {
+          &-item {
+            display: flex;
+            justify-content: space-between;
+            margin-bottom: 10px;
+            font-size: 14px;
+            cursor: pointer;
+            &:hover {
+              text-decoration: underline;
+            }
+            .title {
+              width: 80%;
+              white-space: nowrap;
+              overflow: hidden;
+              text-overflow: ellipsis;
+              word-break: break-all;
+            }
+            .date {
+              width: 20%;
+              white-space: nowrap;
+              overflow: hidden;
+              text-overflow: ellipsis;
+              word-break: break-all;
+              text-align: right;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 0 - 18
src/views/HomeView.vue

@@ -1,18 +0,0 @@
-<template>
-  <div class="home">
-    <img alt="Vue logo" src="../assets/logo.png">
-    <HelloWorld msg="Welcome to Your Vue.js App"/>
-  </div>
-</template>
-
-<script>
-// @ is an alias to /src
-import HelloWorld from '@/components/HelloWorld.vue'
-
-export default {
-  name: 'HomeView',
-  components: {
-    HelloWorld
-  }
-}
-</script>

+ 12 - 0
src/views/Login/LoginIndex.vue

@@ -0,0 +1,12 @@
+<!--
+ * @Description: 登录页
+ * @Author: 空白格
+ * @Date: 2022-08-10 11:45:16
+ * @LastEditors: 空白格
+ * @LastEditTime: 2022-08-10 11:45:16
+ * @FilePath: \veterans_client_web\src\views\Login\LoginIndex.vue
+ * @Copyright: Copyright (c) 2016~2022 by 空白格, All Rights Reserved.
+-->
+<template>
+  <div>登录页</div>
+</template>

+ 16 - 1
vue.config.js

@@ -1,5 +1,20 @@
 const { defineConfig } = require('@vue/cli-service')
+let port = 9010
 module.exports = defineConfig({
   transpileDependencies: true,
-  lintOnSave: false
+  lintOnSave: false,
+  devServer: {
+    host: '0.0.0.0',
+    port,
+    proxy: {
+      // 开发模式请求基础api反代理
+      '/api': {
+        target: `https://wx.hw.hongweisoft.com/veterans`,
+        changeOrigin: true,
+        pathRewrite: {
+          '^/api': ''
+        }
+      }
+    }
+  }
 })

+ 99 - 3
yarn.lock

@@ -1986,6 +1986,13 @@ astral-regex@^2.0.0:
   resolved "https://registry.npmmirror.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
   integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
 
+async-validator@~1.8.1:
+  version "1.8.5"
+  resolved "https://registry.npmmirror.com/async-validator/-/async-validator-1.8.5.tgz#dc3e08ec1fd0dddb67e60842f02c0cd1cec6d7f0"
+  integrity sha512-tXBM+1m056MAX0E8TL2iCjg8WvSyXu0Zc8LNtYqrVeyoL3+esHRZ4SieE9fKQyyU09uONjnMEjrNBMqT0mbvmA==
+  dependencies:
+    babel-runtime "6.x"
+
 async@^2.6.4:
   version "2.6.4"
   resolved "https://registry.npmmirror.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221"
@@ -1998,6 +2005,11 @@ async@^3.2.3:
   resolved "https://registry.npmmirror.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c"
   integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==
 
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+  integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
+
 at-least-node@^1.0.0:
   version "1.0.0"
   resolved "https://registry.npmmirror.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
@@ -2015,6 +2027,19 @@ autoprefixer@^10.2.4:
     picocolors "^1.0.0"
     postcss-value-parser "^4.2.0"
 
+axios@^0.27.2:
+  version "0.27.2"
+  resolved "https://registry.npmmirror.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
+  integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
+  dependencies:
+    follow-redirects "^1.14.9"
+    form-data "^4.0.0"
+
+babel-helper-vue-jsx-merge-props@^2.0.0:
+  version "2.0.3"
+  resolved "https://registry.npmmirror.com/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz#22aebd3b33902328e513293a8e4992b384f9f1b6"
+  integrity sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg==
+
 babel-loader@^8.2.2:
   version "8.2.5"
   resolved "https://registry.npmmirror.com/babel-loader/-/babel-loader-8.2.5.tgz#d45f585e654d5a5d90f5350a779d7647c5ed512e"
@@ -2056,6 +2081,14 @@ babel-plugin-polyfill-regenerator@^0.4.0:
   dependencies:
     "@babel/helper-define-polyfill-provider" "^0.3.2"
 
+babel-runtime@6.x:
+  version "6.26.0"
+  resolved "https://registry.npmmirror.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
+  integrity sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.11.0"
+
 balanced-match@^1.0.0:
   version "1.0.2"
   resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
@@ -2393,6 +2426,13 @@ colorette@^2.0.10:
   resolved "https://registry.npmmirror.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798"
   integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==
 
+combined-stream@^1.0.8:
+  version "1.0.8"
+  resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+  integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+  dependencies:
+    delayed-stream "~1.0.0"
+
 commander@^2.20.0:
   version "2.20.3"
   resolved "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
@@ -2504,6 +2544,11 @@ core-js-compat@^3.21.0, core-js-compat@^3.22.1, core-js-compat@^3.8.3:
     browserslist "^4.21.3"
     semver "7.0.0"
 
+core-js@^2.4.0:
+  version "2.6.12"
+  resolved "https://registry.npmmirror.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
+  integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
+
 core-js@^3.8.3:
   version "3.24.1"
   resolved "https://registry.npmmirror.com/core-js/-/core-js-3.24.1.tgz#cf7724d41724154010a6576b7b57d94c5d66e64f"
@@ -2711,7 +2756,7 @@ deep-is@^0.1.3:
   resolved "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
   integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
 
-deepmerge@^1.5.2:
+deepmerge@^1.2.0, deepmerge@^1.5.2:
   version "1.5.2"
   resolved "https://registry.npmmirror.com/deepmerge/-/deepmerge-1.5.2.tgz#10499d868844cdad4fee0842df8c7f6f0c95a753"
   integrity sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==
@@ -2748,6 +2793,11 @@ define-properties@^1.1.3, define-properties@^1.1.4:
     has-property-descriptors "^1.0.0"
     object-keys "^1.1.1"
 
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+  integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
+
 depd@2.0.0:
   version "2.0.0"
   resolved "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
@@ -2883,6 +2933,18 @@ electron-to-chromium@^1.4.202:
   resolved "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.213.tgz#a0d0f535e4fbddc25196c91ff2964b5660932297"
   integrity sha512-+3DbGHGOCHTVB/Ms63bGqbyC1b8y7Fk86+7ltssB8NQrZtSCvZG6eooSl9U2Q0yw++fL2DpHKOdTU0NVEkFObg==
 
+element-ui@^2.15.9:
+  version "2.15.9"
+  resolved "https://registry.npmmirror.com/element-ui/-/element-ui-2.15.9.tgz#b03548e007b7ab7496c49a282db92a0fffd7efc7"
+  integrity sha512-dx45nQLt4Hn87/Z9eRr3ex6KFZbxlFAwEU3QoW3wA5EsYftvHTyL9Pq7VnXXD7hu1Eiaup2jcs6kp+/VSFmXuA==
+  dependencies:
+    async-validator "~1.8.1"
+    babel-helper-vue-jsx-merge-props "^2.0.0"
+    deepmerge "^1.2.0"
+    normalize-wheel "^1.0.1"
+    resize-observer-polyfill "^1.5.0"
+    throttle-debounce "^1.0.1"
+
 emoji-regex@^8.0.0:
   version "8.0.0"
   resolved "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
@@ -3492,11 +3554,20 @@ flatted@^3.1.0:
   resolved "https://registry.npmmirror.com/flatted/-/flatted-3.2.6.tgz#022e9218c637f9f3fc9c35ab9c9193f05add60b2"
   integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==
 
-follow-redirects@^1.0.0:
+follow-redirects@^1.0.0, follow-redirects@^1.14.9:
   version "1.15.1"
   resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5"
   integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==
 
+form-data@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
+  integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.8"
+    mime-types "^2.1.12"
+
 forwarded@0.2.0:
   version "0.2.0"
   resolved "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
@@ -4218,6 +4289,11 @@ joi@^17.4.0:
     "@sideway/formula" "^3.0.0"
     "@sideway/pinpoint" "^2.0.0"
 
+js-cookie@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.npmmirror.com/js-cookie/-/js-cookie-3.0.1.tgz#9e39b4c6c2f56563708d7d31f6f5f21873a92414"
+  integrity sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==
+
 js-message@1.0.7:
   version "1.0.7"
   resolved "https://registry.npmmirror.com/js-message/-/js-message-1.0.7.tgz#fbddd053c7a47021871bb8b2c95397cc17c20e47"
@@ -4553,7 +4629,7 @@ mime-db@1.52.0, "mime-db@>= 1.43.0 < 2":
   resolved "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
   integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
 
-mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34:
+mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34:
   version "2.1.35"
   resolved "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
   integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
@@ -4742,6 +4818,11 @@ normalize-url@^6.0.1:
   resolved "https://registry.npmmirror.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
   integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
 
+normalize-wheel@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.npmmirror.com/normalize-wheel/-/normalize-wheel-1.0.1.tgz#aec886affdb045070d856447df62ecf86146ec45"
+  integrity sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA==
+
 npm-run-path@^2.0.0:
   version "2.0.2"
   resolved "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
@@ -5479,6 +5560,11 @@ regenerate@^1.4.2:
   resolved "https://registry.npmmirror.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a"
   integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
 
+regenerator-runtime@^0.11.0:
+  version "0.11.1"
+  resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
+  integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
+
 regenerator-runtime@^0.13.4:
   version "0.13.9"
   resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
@@ -5565,6 +5651,11 @@ requires-port@^1.0.0:
   resolved "https://registry.npmmirror.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
   integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==
 
+resize-observer-polyfill@^1.5.0:
+  version "1.5.1"
+  resolved "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
+  integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
+
 resolve-from@^4.0.0:
   version "4.0.0"
   resolved "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
@@ -6249,6 +6340,11 @@ thread-loader@^3.0.0:
     neo-async "^2.6.2"
     schema-utils "^3.0.0"
 
+throttle-debounce@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.npmmirror.com/throttle-debounce/-/throttle-debounce-1.1.0.tgz#51853da37be68a155cb6e827b3514a3c422e89cd"
+  integrity sha512-XH8UiPCQcWNuk2LYePibW/4qL97+ZQ1AN3FNXwZRBNPPowo/NRU5fAlDCSNBJIYCKbioZfuYtMhG4quqoJhVzg==
+
 thunky@^1.0.2:
   version "1.1.0"
   resolved "https://registry.npmmirror.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d"