Ver código fonte

feat(time): added time compoennt close #285

Vben 4 anos atrás
pai
commit
a89eeef6f3

+ 2 - 1
.env.development

@@ -7,7 +7,8 @@ VITE_USE_MOCK = true
 VITE_PUBLIC_PATH = /
 
 # Cross-domain proxy, you can configure multiple
-VITE_PROXY=[["/basic-api","http://localhost:3000"],["/upload","http://localhost:3001/upload"]]
+# Please note that no line breaks
+VITE_PROXY = [["/basic-api","http://localhost:3000"],["/upload","http://localhost:3001/upload"]]
 # VITE_PROXY=[["/api","https://vvbin.cn/test"]]
 
 # Delete console

+ 3 - 10
.vscode/settings.json

@@ -6,18 +6,18 @@
   //============= Editor ======================
   //===========================================
   "explorer.openEditors.visible": 0,
+  "editor.tabSize": 2,
+  "editor.renderControlCharacters": true,
+  "window.zoomLevel": -1,
   "editor.minimap.renderCharacters": false,
   "editor.minimap.maxColumn": 300,
   "editor.minimap.showSlider": "always",
-  "editor.smoothScrolling": true,
   "editor.cursorBlinking": "phase",
   "editor.cursorSmoothCaretAnimation": true,
   "editor.detectIndentation": false,
   "editor.defaultFormatter": "esbenp.prettier-vscode",
   "diffEditor.ignoreTrimWhitespace": false,
   "javascript.format.insertSpaceBeforeFunctionParenthesis": true,
-  "editor.formatOnPaste": true,
-  "editor.formatOnSave": true,
   "editor.suggestSelection": "first",
   "editor.trimAutoWhitespace": true,
   "editor.quickSuggestions": {
@@ -39,7 +39,6 @@
   "emmet.syntaxProfiles": {
     "vue-html": "html",
     "vue": "html",
-    "javascript": "javascriptreact",
     "xml": {
       "attr_quotes": "single"
     }
@@ -80,7 +79,6 @@
   "files.exclude": {
     "**/bower_components": true,
     "**/.idea": true,
-    "**/yarn.lock": true,
     "**/tmp": true,
     "**/.git": true,
     "**/.svn": true,
@@ -89,7 +87,6 @@
     "**/.DS_Store": true
   },
   "files.watcherExclude": {
-    // 文件监视排除
     "**/.git/objects/**": true,
     "**/.git/subtree-cache/**": true,
     "**/.vscode/**": true,
@@ -99,10 +96,6 @@
     "**/dist/**": true,
     "**/yarn.lock": true
   },
-  "files.associations": {
-    "*.vue": "vue",
-    "*.wxss": "css"
-  },
   "stylelint.enable": true,
   "stylelint.packageManager": "yarn",
   // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

+ 1 - 0
CHANGELOG.zh_CN.md

@@ -3,6 +3,7 @@
 ### ✨ Features
 
 - 图标选择器新增 svg 模式
+- 新增时间组件
 
 ### ✨ Refactor
 

+ 2 - 3
build/vite/optimizer.ts

@@ -1,5 +1,5 @@
 // TODO
-import type { GetManualChunk, GetManualChunkApi } from 'rollup';
+import type { GetManualChunk } from 'rollup';
 
 //
 const vendorLibs: { match: string[]; output: string }[] = [
@@ -10,8 +10,7 @@ const vendorLibs: { match: string[]; output: string }[] = [
 ];
 
 // @ts-ignore
-export const configManualChunk: GetManualChunk = (id: string, api: GetManualChunkApi) => {
-  console.log(api);
+export const configManualChunk: GetManualChunk = (id: string) => {
   if (/[\\/]node_modules[\\/]/.test(id)) {
     const matchItem = vendorLibs.find((item) => {
       const reg = new RegExp(`[\\/]node_modules[\\/]_?(${item.match.join('|')})(.*)`, 'ig');

+ 2 - 2
package.json

@@ -49,7 +49,7 @@
     "vditor": "^3.8.2",
     "vue": "^3.0.7",
     "vue-i18n": "^9.0.0",
-    "vue-router": "^4.0.4",
+    "vue-router": "^4.0.5",
     "vue-types": "^3.0.2",
     "vuex": "^4.0.0",
     "vuex-module-decorators": "^1.0.1",
@@ -118,7 +118,7 @@
     "vite-plugin-style-import": "^0.8.1",
     "vite-plugin-svg-icons": "^0.3.4",
     "vite-plugin-theme": "^0.4.8",
-    "vite-plugin-windicss": "0.7.2",
+    "vite-plugin-windicss": "0.8.2",
     "vue-eslint-parser": "^7.6.0",
     "yargs": "^16.2.0"
   },

+ 1 - 0
src/components/Time/index.ts

@@ -0,0 +1 @@
+export { default as Time } from './src/index.vue';

+ 109 - 0
src/components/Time/src/index.vue

@@ -0,0 +1,109 @@
+<template>
+  <span>{{ date }}</span>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, watch } from 'vue';
+
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useIntervalFn } from '@vueuse/core';
+
+  import { formatToDateTime, formatToDate, dateUtil } from '/@/utils/dateUtil';
+  import { isNumber, isObject, isString } from '/@/utils/is';
+  import { propTypes } from '/@/utils/propTypes';
+
+  const ONE_SECONDS = 1000;
+  const ONE_MINUTES = ONE_SECONDS * 60;
+  const ONE_HOUR = ONE_MINUTES * 60;
+  const ONE_DAY = ONE_HOUR * 24;
+  export default defineComponent({
+    name: 'Time',
+    props: {
+      value: propTypes.oneOfType([propTypes.number, propTypes.instanceOf(Date), propTypes.string])
+        .isRequired,
+      step: propTypes.number.def(60),
+      mode: propTypes.oneOf(['date', 'datetime', 'relative']).def('relative'),
+    },
+    setup(props) {
+      const date = ref('');
+
+      const { t } = useI18n();
+
+      useIntervalFn(setTime, props.step * ONE_SECONDS);
+
+      watch(
+        () => props.value,
+        () => {
+          setTime();
+        },
+        { immediate: true }
+      );
+
+      function getTime() {
+        const { value } = props;
+        let time: number = 0;
+        if (isNumber(value)) {
+          const timestamp = value.toString().length > 10 ? value : value * 1000;
+          time = new Date(timestamp).getTime();
+        } else if (isString(value)) {
+          time = new Date(value).getTime();
+        } else if (isObject(value)) {
+          time = value.getTime();
+        }
+        return time;
+      }
+
+      function setTime() {
+        const { mode, value } = props;
+        const time = getTime();
+        if (mode === 'relative') {
+          date.value = getRelativeTime(time);
+        } else {
+          if (mode === 'datetime') {
+            date.value = formatToDateTime(value);
+          } else if (mode === 'date') {
+            date.value = formatToDate(value);
+          }
+        }
+      }
+
+      function getRelativeTime(timeStamp: number) {
+        const currentTime = new Date().getTime();
+
+        // Determine whether the incoming timestamp is earlier than the current timestamp
+        const isBefore = dateUtil(timeStamp).isBefore(currentTime);
+
+        let diff = currentTime - timeStamp;
+        if (!isBefore) {
+          diff = -diff;
+        }
+
+        let resStr = '';
+        let dirStr = isBefore ? t('component.time.before') : t('component.time.after');
+
+        if (diff < ONE_SECONDS) {
+          resStr = t('component.time.just');
+          // Less than or equal to 59 seconds
+        } else if (diff < ONE_MINUTES) {
+          resStr = parseInt(diff / ONE_SECONDS) + t('component.time.seconds') + dirStr;
+          // More than 59 seconds, less than or equal to 59 minutes and 59 seconds
+        } else if (diff >= ONE_MINUTES && diff < ONE_HOUR) {
+          resStr = Math.floor(diff / ONE_MINUTES) + t('component.time.minutes') + dirStr;
+          // More than 59 minutes and 59 seconds, less than or equal to 23 hours, 59 minutes and 59 seconds
+        } else if (diff >= ONE_HOUR && diff < ONE_DAY) {
+          resStr = Math.floor(diff / ONE_HOUR) + t('component.time.hours') + dirStr;
+          // More than 23 hours, 59 minutes and 59 seconds, less than or equal to 29 days, 59 minutes and 59 seconds
+        } else if (diff >= ONE_DAY && diff < 2623860000) {
+          resStr = Math.floor(diff / ONE_DAY) + t('component.time.days') + dirStr;
+          // More than 29 days, 59 minutes, 59 seconds, less than 364 days, 23 hours, 59 minutes, 59 seconds, and the incoming timestamp is earlier than the current
+        } else if (diff >= 2623860000 && diff <= 31567860000 && isBefore) {
+          resStr = dateUtil(timeStamp).format('MM-DD-HH-mm');
+        } else {
+          resStr = dateUtil(timeStamp).format('YYYY');
+        }
+        return resStr;
+      }
+
+      return { date };
+    },
+  });
+</script>

+ 16 - 13
src/hooks/core/useContext.ts

@@ -4,7 +4,7 @@ import {
   inject,
   reactive,
   readonly as defineReadonly,
-  defineComponent,
+  // defineComponent,
   UnwrapRef,
 } from 'vue';
 
@@ -29,18 +29,21 @@ export function createContext<T>(
   const provideData = readonly ? defineReadonly(state) : state;
   !createProvider && provide(key, native ? context : provideData);
 
-  const Provider = createProvider
-    ? defineComponent({
-        name: 'Provider',
-        inheritAttrs: false,
-        setup(_, { slots }) {
-          provide(key, provideData);
-          return () => slots.default?.();
-        },
-      })
-    : null;
-
-  return { Provider, state };
+  // const Provider = createProvider
+  //   ? defineComponent({
+  //       name: 'Provider',
+  //       inheritAttrs: false,
+  //       setup(_, { slots }) {
+  //         provide(key, provideData);
+  //         return () => slots.default?.();
+  //       },
+  //     })
+  //   : null;
+
+  return {
+    // Provider,
+    state,
+  };
 }
 
 export function useContext<T>(key: InjectionKey<T>, native?: boolean): T;

+ 4 - 13
src/layouts/default/content/index.vue

@@ -1,30 +1,21 @@
 <template>
-  <div :class="[prefixCls, getLayoutContentMode]">
-    <transition name="fade">
-      <Loading
-        v-if="getOpenPageLoading"
-        :loading="getPageLoading"
-        background="rgba(240, 242, 245, 0.6)"
-        absolute
-        :class="`${prefixCls}-loading`"
-      />
-    </transition>
+  <div :class="[prefixCls, getLayoutContentMode]" v-loading="getOpenPageLoading && getPageLoading">
     <PageLayout />
   </div>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
 
+  import PageLayout from '/@/layouts/page/index.vue';
+
   import { useDesign } from '/@/hooks/web/useDesign';
   import { useRootSetting } from '/@/hooks/setting/useRootSetting';
   import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
-  import PageLayout from '/@/layouts/page/index.vue';
   import { useContentViewHeight } from './useContentViewHeight';
-  import { Loading } from '/@/components/Loading';
 
   export default defineComponent({
     name: 'LayoutContent',
-    components: { PageLayout, Loading },
+    components: { PageLayout },
     setup() {
       const { prefixCls } = useDesign('layout-content');
       const { getOpenPageLoading } = useTransitionSetting();

+ 2 - 0
src/layouts/default/footer/index.vue

@@ -2,7 +2,9 @@
   <Footer :class="prefixCls" v-if="getShowLayoutFooter">
     <div :class="`${prefixCls}__links`">
       <a @click="openWindow(SITE_URL)">{{ t('layout.footer.onlinePreview') }}</a>
+
       <GithubFilled @click="openWindow(GITHUB_URL)" :class="`${prefixCls}__github`" />
+
       <a @click="openWindow(DOC_URL)">{{ t('layout.footer.onlineDocument') }}</a>
     </div>
     <div>Copyright &copy;2020 Vben Admin</div>

+ 7 - 8
src/layouts/default/index.vue

@@ -2,13 +2,9 @@
   <Layout :class="prefixCls">
     <LayoutFeatures />
     <LayoutHeader fixed v-if="getShowFullHeaderRef" />
-    <Layout
-      :class="{
-        'ant-layout-has-sider': getIsMixSidebar,
-      }"
-    >
+    <Layout :class="layoutClass">
       <LayoutSideBar v-if="getShowSidebar || getIsMobile" />
-      <Layout :class="`${prefixCls}__main`">
+      <Layout :class="`${prefixCls}-main`">
         <LayoutMultipleHeader />
         <LayoutContent />
         <LayoutFooter />
@@ -18,7 +14,7 @@
 </template>
 
 <script lang="ts">
-  import { defineComponent } from 'vue';
+  import { defineComponent, computed, unref } from 'vue';
   import { Layout } from 'ant-design-vue';
   import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
 
@@ -53,12 +49,15 @@
 
       const { getShowSidebar, getIsMixSidebar } = useMenuSetting();
 
+      const layoutClass = computed(() => ({ 'ant-layout-has-sider': unref(getIsMixSidebar) }));
+
       return {
         getShowFullHeaderRef,
         getShowSidebar,
         prefixCls,
         getIsMobile,
         getIsMixSidebar,
+        layoutClass,
       };
     },
   });
@@ -77,7 +76,7 @@
       min-height: 100%;
     }
 
-    &__main {
+    &-main {
       margin-left: 1px;
     }
   }

+ 1 - 1
src/layouts/default/trigger/HeaderTrigger.vue

@@ -11,7 +11,7 @@
   import { propTypes } from '/@/utils/propTypes';
 
   export default defineComponent({
-    name: 'SiderTrigger',
+    name: 'HeaderTrigger',
     components: { MenuUnfoldOutlined, MenuFoldOutlined },
     props: {
       theme: propTypes.oneOf(['light', 'dark']),

+ 9 - 0
src/locales/lang/en/component/time.ts

@@ -0,0 +1,9 @@
+export default {
+  before: ' ago',
+  after: ' after',
+  just: 'just now',
+  seconds: ' seconds',
+  minutes: ' minutes',
+  hours: ' hours',
+  days: ' days',
+};

+ 2 - 0
src/locales/lang/en/routes/demo/comp.ts

@@ -32,4 +32,6 @@ export default {
   upload: 'Upload',
 
   loading: 'Loading',
+
+  time: 'Time',
 };

+ 9 - 0
src/locales/lang/zh_CN/component/time.ts

@@ -0,0 +1,9 @@
+export default {
+  before: '前',
+  after: '后',
+  just: '刚刚',
+  seconds: '秒',
+  minutes: '分钟',
+  hours: '小时',
+  days: '天',
+};

+ 2 - 0
src/locales/lang/zh_CN/routes/demo/comp.ts

@@ -31,4 +31,6 @@ export default {
   upload: '上传组件',
 
   loading: 'Loading',
+
+  time: '时间组件',
 };

+ 0 - 1
src/router/index.ts

@@ -2,7 +2,6 @@ import type { RouteRecordRaw } from 'vue-router';
 import type { App } from 'vue';
 
 import { createRouter, createWebHashHistory } from 'vue-router';
-
 import { basicRoutes, LoginRoute } from './routes';
 import { REDIRECT_NAME } from './constant';
 

+ 7 - 0
src/router/menus/modules/demo/comp.ts

@@ -122,6 +122,13 @@ const menu: MenuModule = {
         name: t('routes.demo.comp.countTo'),
       },
       {
+        path: 'timestamp',
+        name: t('routes.demo.comp.time'),
+        tag: {
+          content: 'new',
+        },
+      },
+      {
         path: 'transition',
         name: t('routes.demo.comp.transition'),
       },

+ 8 - 0
src/router/routes/modules/demo/comp.ts

@@ -233,6 +233,14 @@ const comp: AppRouteModule = {
       },
     },
     {
+      path: 'timestamp',
+      name: 'TimeDemo',
+      component: () => import('/@/views/demo/comp/time/index.vue'),
+      meta: {
+        title: t('routes.demo.comp.time'),
+      },
+    },
+    {
       path: 'countTo',
       name: 'CountTo',
       component: () => import('/@/views/demo/comp/count-to/index.vue'),

+ 3 - 0
src/utils/dateUtil.ts

@@ -1,3 +1,6 @@
+/**
+ * Independent time operation tool to facilitate subsequent switch to dayjs
+ */
 import moment from 'moment';
 
 const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm';

+ 44 - 0
src/views/demo/comp/time/index.vue

@@ -0,0 +1,44 @@
+<template>
+  <PageWrapper title="时间组件示例">
+    <CollapseContainer title="基础示例">
+      <Time :value="time1" />
+      <br />
+      <Time :value="time2" />
+    </CollapseContainer>
+
+    <CollapseContainer title="定时更新" class="my-4">
+      <Time :value="now" :step="1" />
+      <br />
+      <Time :value="now" :step="5" />
+    </CollapseContainer>
+
+    <CollapseContainer title="定时更新">
+      <Time :value="now" mode="date" />
+      <br />
+      <Time :value="now" mode="datetime" />
+      <br />
+      <Time :value="now" />
+    </CollapseContainer>
+  </PageWrapper>
+</template>
+<script lang="ts">
+  import { defineComponent, reactive, toRefs } from 'vue';
+  import { PageWrapper } from '/@/components/Page';
+  import { Time } from '/@/components/Time';
+  import { CollapseContainer } from '/@/components/Container/index';
+
+  export default defineComponent({
+    components: { PageWrapper, Time, CollapseContainer },
+    setup() {
+      const now = new Date().getTime();
+      const state = reactive({
+        time1: now - 60 * 3 * 1000,
+        time2: now - 86400 * 3 * 1000,
+      });
+      return {
+        ...toRefs(state),
+        now,
+      };
+    },
+  });
+</script>

+ 79 - 23
yarn.lock

@@ -1790,16 +1790,15 @@
   dependencies:
     vue-demi latest
 
-"@windicss/plugin-utils@0.7.2":
-  version "0.7.2"
-  resolved "https://registry.npmjs.org/@windicss/plugin-utils/-/plugin-utils-0.7.2.tgz#c43c89a2f51110eb6f49da565dc235fb2af30269"
-  integrity sha512-4znRERKhhStIOFy1/eB0rJXnXs+NyumBREjh0GZVMoHVmUB9up08tNUpbbq3tlJC96t27VsD4vdfv00T+It/IA==
+"@windicss/plugin-utils@0.8.2":
+  version "0.8.2"
+  resolved "https://registry.npmjs.org/@windicss/plugin-utils/-/plugin-utils-0.8.2.tgz#032b21a79ff5af5031bf29bc3faeb0efcce73afb"
+  integrity sha512-jBv9w3VrUF5BjkP/WjY5Brf6CzJYeFMwcZFfOYiSPGuK+4+a/UmYX8B0/bISp5GnY9plVYr5aibTY9PTbt597Q==
   dependencies:
-    esbuild "^0.8.57"
-    esbuild-register "^2.2.0"
     fast-glob "^3.2.5"
     micromatch "^4.0.2"
-    windicss "^2.3.0"
+    sucrase "^3.17.1"
+    windicss "^2.4.0"
 
 "@zxcvbn-ts/core@^0.3.0":
   version "0.3.0"
@@ -1944,6 +1943,11 @@ ant-design-vue@2.0.1:
     vue-types "^3.0.0"
     warning "^4.0.0"
 
+any-promise@^1.0.0:
+  version "1.3.0"
+  resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
+  integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
+
 anymatch@~3.1.1:
   version "3.1.1"
   resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
@@ -2745,7 +2749,7 @@ commander@^2.16.0, commander@^2.20.0, commander@^2.20.3, commander@^2.8.1:
   resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
   integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
 
-commander@^4.1.1:
+commander@^4.0.0, commander@^4.1.1:
   version "4.1.1"
   resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
   integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
@@ -4741,7 +4745,7 @@ glob@7.1.4:
     once "^1.3.0"
     path-is-absolute "^1.0.0"
 
-glob@^7.0.0, glob@^7.1.3, glob@^7.1.6:
+glob@7.1.6, glob@^7.0.0, glob@^7.1.3, glob@^7.1.6:
   version "7.1.6"
   resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
   integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
@@ -6588,6 +6592,15 @@ mute-stream@0.0.8:
   resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
   integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
 
+mz@^2.7.0:
+  version "2.7.0"
+  resolved "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
+  integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
+  dependencies:
+    any-promise "^1.0.0"
+    object-assign "^4.0.1"
+    thenify-all "^1.0.0"
+
 nanoid@^3.0.1, nanoid@^3.1.20:
   version "3.1.20"
   resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788"
@@ -6652,6 +6665,11 @@ node-fetch@2.6.1:
   resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
   integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
 
+node-modules-regexp@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40"
+  integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=
+
 node-releases@^1.1.69:
   version "1.1.70"
   resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.70.tgz#66e0ed0273aa65666d7fe78febe7634875426a08"
@@ -7267,6 +7285,13 @@ pinkie@^2.0.0:
   resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
   integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
 
+pirates@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87"
+  integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==
+  dependencies:
+    node-modules-regexp "^1.0.0"
+
 please-upgrade-node@^3.2.0:
   version "3.2.0"
   resolved "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942"
@@ -8799,6 +8824,18 @@ stylus-lookup@^3.0.1:
     commander "^2.8.1"
     debug "^4.1.0"
 
+sucrase@^3.17.1:
+  version "3.17.1"
+  resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.17.1.tgz#b5e35ca7d99db2cc82b3e942934c3746b41ff8e2"
+  integrity sha512-04cNLFAhS4NBG2Z/MTkLY6HdoBsqErv3wCncymFlfFtnpMthurlWYML2RlID4M2BbiJSu1eZdQnE8Lcz4PCe2g==
+  dependencies:
+    commander "^4.0.0"
+    glob "7.1.6"
+    lines-and-columns "^1.1.6"
+    mz "^2.7.0"
+    pirates "^4.0.1"
+    ts-interface-checker "^0.1.9"
+
 sugarss@^2.0.0:
   version "2.0.0"
   resolved "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz#ddd76e0124b297d40bf3cca31c8b22ecb43bc61d"
@@ -9053,6 +9090,20 @@ text-table@^0.2.0:
   resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
   integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
 
+thenify-all@^1.0.0:
+  version "1.6.0"
+  resolved "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"
+  integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=
+  dependencies:
+    thenify ">= 3.1.0 < 4"
+
+"thenify@>= 3.1.0 < 4":
+  version "3.3.1"
+  resolved "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f"
+  integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==
+  dependencies:
+    any-promise "^1.0.0"
+
 through2@^2.0.0, through2@^2.0.2:
   version "2.0.5"
   resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
@@ -9171,6 +9222,11 @@ trough@^1.0.0:
   resolved "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406"
   integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==
 
+ts-interface-checker@^0.1.9:
+  version "0.1.13"
+  resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699"
+  integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==
+
 ts-node@^9.1.1:
   version "9.1.1"
   resolved "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d"
@@ -9626,13 +9682,13 @@ vite-plugin-theme@^0.4.8:
     es-module-lexer "^0.3.26"
     tinycolor2 "^1.4.2"
 
-vite-plugin-windicss@0.7.2:
-  version "0.7.2"
-  resolved "https://registry.npmjs.org/vite-plugin-windicss/-/vite-plugin-windicss-0.7.2.tgz#1647ee3765edb0f993b81206f35310a63b25c1f9"
-  integrity sha512-U6N8ljy7meqLkq8aENb3VXKr93Vzp1pU5zwhJr7HmGi+42Wv4i8r7+7BW6WRS4Ght4SAMzFuzIGq9RLPzoZ2Jg==
+vite-plugin-windicss@0.8.2:
+  version "0.8.2"
+  resolved "https://registry.npmjs.org/vite-plugin-windicss/-/vite-plugin-windicss-0.8.2.tgz#cb7a4e03ed218007425be60e54cd4f21cca836d1"
+  integrity sha512-eeHmCAbmeKg1k0r5moPEQrVPFebfsCCGkKUSb8MYWkglLfpcBZfCHyTTdpn/PONy/JcvWrdpbND2/tsy30it3g==
   dependencies:
-    "@windicss/plugin-utils" "0.7.2"
-    windicss "^2.3.0"
+    "@windicss/plugin-utils" "0.8.2"
+    windicss "^2.4.0"
 
 vite@^2.0.5:
   version "2.0.5"
@@ -9672,10 +9728,10 @@ vue-i18n@^9.0.0:
     "@intlify/shared" "9.0.0"
     "@vue/devtools-api" "^6.0.0-beta.5"
 
-vue-router@^4.0.4:
-  version "4.0.4"
-  resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.0.4.tgz#ad9b4b7bbdad622407b4ff189b1646f48c1e9053"
-  integrity sha512-uN6PDEaYdU9aRO7mU+Dkr1uaY49hV3fucEDG/Vre/Qj8ct3RoJS16vcPrvKVzn69zDDjBV5b9Xw7fZA9r6b/Iw==
+vue-router@^4.0.5:
+  version "4.0.5"
+  resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.0.5.tgz#dd0a4134bc950c37aef64b973e9ee1008428d8fa"
+  integrity sha512-AQq+pllb6FCc7rS6vh4PPcce3XA1jgK3hKNkQ4hXHwoVN7jOeAOMKCnX7XAX3etV9rmN7iNW8iIwgPk95ckBjw==
 
 vue-types@^3.0.0:
   version "3.0.1"
@@ -9771,10 +9827,10 @@ which@^2.0.1:
   dependencies:
     isexe "^2.0.0"
 
-windicss@^2.3.0:
-  version "2.3.0"
-  resolved "https://registry.npmjs.org/windicss/-/windicss-2.3.0.tgz#76f10017169df195d95042b7101d2e2586e8ebd1"
-  integrity sha512-OR/ULZmcVhtEJDIFnkz4S4v4efpZ8DuvDtzBwXNgbtiPQIxN0Zhpo59q0rfF0i3tfwjKw2KCQXNxL5E98bMuVA==
+windicss@^2.4.0:
+  version "2.4.0"
+  resolved "https://registry.npmjs.org/windicss/-/windicss-2.4.0.tgz#9aa0108399d5d3925d5ad5860e76c80299de0cab"
+  integrity sha512-EcGkGnZpuoH0r/hNuj4GLheb9Lg3P+s5KOHUZU63zkl6yoMQNAwTvNXai7OjylbXLFDEWii7SAJbwQIFxE56qQ==
 
 wmf@~1.0.1:
   version "1.0.2"