Browse Source

feat: multi-language component

vben 4 years ago
parent
commit
dc09de1e05
40 changed files with 457 additions and 153 deletions
  1. 2 0
      CHANGELOG.zh_CN.md
  2. 3 3
      package.json
  3. 6 3
      src/components/Drawer/src/BasicDrawer.tsx
  4. 6 2
      src/components/Drawer/src/props.ts
  5. 14 4
      src/components/Excel/src/ExportExcelModel.vue
  6. 1 1
      src/components/Excel/src/ImportExcel.vue
  7. 6 3
      src/components/Form/src/FormAction.tsx
  8. 6 3
      src/components/Form/src/helper.ts
  9. 5 3
      src/components/Menu/src/SearchInput.vue
  10. 2 0
      src/components/Menu/src/types.ts
  11. 6 2
      src/components/Modal/src/props.ts
  12. 13 9
      src/components/Table/src/components/TableSetting.vue
  13. 3 1
      src/components/Table/src/hooks/useColumns.ts
  14. 4 1
      src/components/Table/src/hooks/usePagination.tsx
  15. 1 1
      src/components/Tinymce/src/lineHeight.ts
  16. 5 2
      src/components/Upload/src/BasicUpload.vue
  17. 20 11
      src/components/Upload/src/UploadModal.vue
  18. 6 1
      src/components/Upload/src/UploadPreviewModal.vue
  19. 19 16
      src/components/Upload/src/data.tsx
  20. 5 4
      src/components/Upload/src/useUpload.ts
  21. 7 3
      src/components/Verify/src/ImgRotate.tsx
  22. 0 44
      src/components/Verify/src/VerifyModal.vue
  23. 4 2
      src/components/Verify/src/props.ts
  24. 5 0
      src/locales/lang/en/component/drawer.ts
  25. 5 0
      src/locales/lang/en/component/excel.ts
  26. 9 0
      src/locales/lang/en/component/form.ts
  27. 3 0
      src/locales/lang/en/component/menu.ts
  28. 4 0
      src/locales/lang/en/component/modal.ts
  29. 15 0
      src/locales/lang/en/component/table.ts
  30. 32 0
      src/locales/lang/en/component/upload.ts
  31. 9 0
      src/locales/lang/en/component/verify.ts
  32. 5 0
      src/locales/lang/zh_CN/component/drawer.ts
  33. 5 0
      src/locales/lang/zh_CN/component/excel.ts
  34. 9 0
      src/locales/lang/zh_CN/component/form.ts
  35. 3 0
      src/locales/lang/zh_CN/component/menu.ts
  36. 5 0
      src/locales/lang/zh_CN/component/modal.ts
  37. 15 0
      src/locales/lang/zh_CN/component/table.ts
  38. 32 0
      src/locales/lang/zh_CN/component/upload.ts
  39. 9 0
      src/locales/lang/zh_CN/component/verify.ts
  40. 148 34
      yarn.lock

+ 2 - 0
CHANGELOG.zh_CN.md

@@ -14,6 +14,8 @@
 ### 🎫 Chores
 
 - 更新 antdv 到`2.0.0-rc.2`
+- 更新 vue 到`3.0.3`
+- 更新 vite 到`1.0.0.rc10`
 - 暂时删除 `@vueuse/core`.等稳定后在集成。目前不太稳定。
 
 ## 2.0.0-rc.11 (2020-11-18)

+ 3 - 3
package.json

@@ -35,7 +35,7 @@
     "qrcode": "^1.4.4",
     "sortablejs": "^1.12.0",
     "vditor": "^3.6.6",
-    "vue": "^3.0.2",
+    "vue": "^3.0.3",
     "vue-i18n": "^9.0.0-beta.8",
     "vue-router": "^4.0.0-rc.5",
     "vuex": "^4.0.0-rc.1",
@@ -63,7 +63,7 @@
     "@types/zxcvbn": "^4.4.0",
     "@typescript-eslint/eslint-plugin": "^4.8.2",
     "@typescript-eslint/parser": "^4.8.2",
-    "@vue/compiler-sfc": "^3.0.2",
+    "@vue/compiler-sfc": "^3.0.3",
     "@vuedx/typecheck": "^0.2.4-0",
     "@vuedx/typescript-plugin-vue": "^0.2.4-0",
     "autoprefixer": "^9.8.6",
@@ -96,7 +96,7 @@
     "tasksfile": "^5.1.1",
     "ts-node": "^9.0.0",
     "typescript": "^4.1.2",
-    "vite": "^1.0.0-rc.9",
+    "vite": "^1.0.0-rc.10",
     "vite-plugin-html": "^1.0.0-beta.2",
     "vite-plugin-mock": "^1.0.6",
     "vite-plugin-purge-icons": "^0.4.5",

+ 6 - 3
src/components/Drawer/src/BasicDrawer.tsx

@@ -1,3 +1,5 @@
+import './index.less';
+
 import type { DrawerInstance, DrawerProps } from './types';
 
 import { defineComponent, ref, computed, watchEffect, watch, unref, nextTick, toRaw } from 'vue';
@@ -13,8 +15,7 @@ import { getSlot } from '/@/utils/helper/tsxHelper';
 import { isFunction, isNumber } from '/@/utils/is';
 import { buildUUID } from '/@/utils/uuid';
 import { deepMerge } from '/@/utils';
-
-import './index.less';
+import { useI18n } from '/@/hooks/web/useI18n';
 
 const prefixCls = 'basic-drawer';
 export default defineComponent({
@@ -27,6 +28,8 @@ export default defineComponent({
     const visibleRef = ref(false);
     const propsRef = ref<Partial<DrawerProps> | null>(null);
 
+    const { t } = useI18n('component.drawer');
+
     const getMergeProps = computed((): any => {
       return deepMerge(toRaw(props), unref(propsRef));
     });
@@ -208,7 +211,7 @@ export default defineComponent({
                 >
                   <FullLoading
                     absolute
-                    tip="加载中..."
+                    tip={t('loadingText')}
                     class={[!unref(getProps).loading ? 'hidden' : '']}
                   />
                   {getSlot(slots, 'default')}

+ 6 - 2
src/components/Drawer/src/props.ts

@@ -1,4 +1,8 @@
 import type { PropType } from 'vue';
+
+import { useI18n } from '/@/hooks/web/useI18n';
+const { t } = useI18n('component.drawer');
+
 export const footerProps = {
   confirmLoading: Boolean as PropType<boolean>,
   /**
@@ -11,7 +15,7 @@ export const footerProps = {
   cancelButtonProps: Object as PropType<any>,
   cancelText: {
     type: String as PropType<string>,
-    default: '关闭',
+    default: t('cancelText'),
   },
   /**
    * @description: Show confirmation button
@@ -23,7 +27,7 @@ export const footerProps = {
   okButtonProps: Object as PropType<any>,
   okText: {
     type: String as PropType<string>,
-    default: '确认',
+    default: t('okText'),
   },
   okType: {
     type: String as PropType<string>,

+ 14 - 4
src/components/Excel/src/ExportExcelModel.vue

@@ -1,5 +1,10 @@
 <template>
-  <BasicModal v-bind="$attrs" title="导出数据" @ok="handleOk" @register="registerModal">
+  <BasicModal
+    v-bind="$attrs"
+    :title="t('exportModalTitle')"
+    @ok="handleOk"
+    @register="registerModal"
+  >
     <BasicForm
       :labelWidth="100"
       :schemas="schemas"
@@ -9,22 +14,26 @@
   </BasicModal>
 </template>
 <script lang="ts">
+  import type { ExportModalResult } from './types';
   import { defineComponent } from 'vue';
   import { BasicModal, useModalInner } from '/@/components/Modal';
   import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
-  import { ExportModalResult } from './types';
+
+  import { useI18n } from '/@/hooks/web/useI18n';
+
+  const { t } = useI18n('component.excel');
 
   const schemas: FormSchema[] = [
     {
       field: 'filename',
       component: 'Input',
-      label: '文件名',
+      label: t('fileName'),
       rules: [{ required: true }],
     },
     {
       field: 'bookType',
       component: 'Select',
-      label: '文件类型',
+      label: t('fileType'),
       defaultValue: 'xlsx',
       rules: [{ required: true }],
       componentProps: {
@@ -76,6 +85,7 @@
         handleOk,
         registerForm,
         registerModal,
+        t,
       };
     },
   });

+ 1 - 1
src/components/Excel/src/ImportExcel.vue

@@ -79,7 +79,7 @@
               /* DO SOMETHING WITH workbook HERE */
               const excelData = getExcelData(workbook);
               emit('success', excelData);
-              resolve();
+              resolve('');
             } catch (error) {
               reject(error);
             } finally {

+ 6 - 3
src/components/Form/src/FormAction.tsx

@@ -6,6 +6,9 @@ import Button from '/@/components/Button/index.vue';
 import { BasicArrow } from '/@/components/Basic/index';
 
 import { getSlot } from '/@/utils/helper/tsxHelper';
+import { useI18n } from '/@/hooks/web/useI18n';
+
+const { t } = useI18n('component.form');
 
 export default defineComponent({
   name: 'BasicFormAction',
@@ -55,14 +58,14 @@ export default defineComponent({
   setup(props, { slots, emit }) {
     const getResetBtnOptionsRef = computed(() => {
       return {
-        text: '重置',
+        text: t('resetButton'),
         ...props.resetButtonOptions,
       };
     });
 
     const getSubmitBtnOptionsRef = computed(() => {
       return {
-        text: '查询',
+        text: t('submitButton'),
         // htmlType: 'submit',
         ...props.submitButtonOptions,
       };
@@ -108,7 +111,7 @@ export default defineComponent({
                     <Button type="default" class="mr-2" onClick={toggleAdvanced}>
                       {() => (
                         <>
-                          {isAdvanced ? '收起' : '展开'}
+                          {isAdvanced ? t('putAway') : t('unfold')}
                           <BasicArrow expand={!isAdvanced} />
                         </>
                       )}

+ 6 - 3
src/components/Form/src/helper.ts

@@ -1,14 +1,17 @@
 import type { ComponentType } from './types/index';
+import { useI18n } from '/@/hooks/web/useI18n';
+
+const { t } = useI18n('component.form');
 
 /**
  * @description: 生成placeholder
  */
 export function createPlaceholderMessage(component: ComponentType) {
   if (component.includes('Input') || component.includes('Complete')) {
-    return '请输入';
+    return t('input');
   }
   if (component.includes('Picker')) {
-    return '请选择';
+    return t('choose');
   }
   if (
     component.includes('Select') ||
@@ -18,7 +21,7 @@ export function createPlaceholderMessage(component: ComponentType) {
     component.includes('Switch')
   ) {
     // return `请选择${label}`;
-    return '请选择';
+    return t('choose');
   }
   return '';
 }

+ 5 - 3
src/components/Menu/src/SearchInput.vue

@@ -1,7 +1,7 @@
 <template>
   <section class="menu-search-input" @Click="handleClick" :class="searchClass">
     <a-input-search
-      placeholder="菜单搜索"
+      :placeholder="t('search')"
       class="menu-search-input__search"
       allowClear
       @change="handleChange"
@@ -12,9 +12,9 @@
   import type { PropType } from 'vue';
   import { defineComponent, computed } from 'vue';
   import { ThemeEnum } from '/@/enums/appEnum';
-
   // hook
   import { useDebounce } from '/@/hooks/core/useDebounce';
+  import { useI18n } from '/@/hooks/web/useI18n';
   //
   export default defineComponent({
     name: 'BasicMenuSearchInput',
@@ -29,6 +29,8 @@
       },
     },
     setup(props, { emit }) {
+      const { t } = useI18n('component.menu');
+
       const [debounceEmitChange] = useDebounce(emitChange, 200);
 
       function emitChange(value?: string): void {
@@ -52,7 +54,7 @@
         return cls;
       });
 
-      return { handleClick, searchClass, handleChange };
+      return { handleClick, searchClass, handleChange, t };
     },
   });
 </script>

+ 2 - 0
src/components/Menu/src/types.ts

@@ -1,4 +1,6 @@
+import { ComputedRef } from 'vue';
 import { ThemeEnum } from '/@/enums/appEnum';
+import { MenuModeEnum } from '/@/enums/menuEnum';
 export interface MenuState {
   // 默认选中的列表
   defaultSelectedKeys: string[];

+ 6 - 2
src/components/Modal/src/props.ts

@@ -1,5 +1,9 @@
 import type { PropType } from 'vue';
 import { ButtonProps } from 'ant-design-vue/es/button/buttonTypes';
+
+import { useI18n } from '/@/hooks/web/useI18n';
+const { t } = useI18n('component.modal');
+
 export const modalProps = {
   visible: Boolean as PropType<boolean>,
   // open drag
@@ -13,11 +17,11 @@ export const modalProps = {
   },
   cancelText: {
     type: String as PropType<string>,
-    default: '关闭',
+    default: t('cancelText'),
   },
   okText: {
     type: String as PropType<string>,
-    default: '确认',
+    default: t('okText'),
   },
   closeFunc: Function as PropType<() => Promise<boolean>>,
 };

+ 13 - 9
src/components/Table/src/components/TableSetting.vue

@@ -4,27 +4,27 @@
 
     <Tooltip placement="top" v-if="getSetting.redo">
       <template #title>
-        <span>刷新</span>
+        <span>{{ t('settingRedo') }}</span>
       </template>
       <RedoOutlined @click="redo" />
     </Tooltip>
 
     <Tooltip placement="top" v-if="getSetting.size">
       <template #title>
-        <span>密度</span>
+        <span>{{ t('settingDens') }}</span>
       </template>
       <Dropdown placement="bottomCenter" :trigger="['click']">
         <ColumnHeightOutlined />
         <template #overlay>
           <Menu @click="handleTitleClick" selectable v-model:selectedKeys="selectedKeysRef">
             <MenuItem key="default">
-              <span>默认</span>
+              <span>{{ t('settingDensDefault') }}</span>
             </MenuItem>
             <MenuItem key="middle">
-              <span>中等</span>
+              <span>{{ t('settingDensMiddle') }}</span>
             </MenuItem>
             <MenuItem key="small">
-              <span>紧凑</span>
+              <span>{{ t('settingDensSmall') }}</span>
             </MenuItem>
           </Menu>
         </template>
@@ -33,7 +33,7 @@
 
     <Tooltip placement="top" v-if="getSetting.setting">
       <template #title>
-        <span>列设置</span>
+        <span>{{ t('settingColumn') }}</span>
       </template>
       <Popover
         placement="bottomLeft"
@@ -58,9 +58,9 @@
               v-model:checked="checkAll"
               @change="onCheckAllChange"
             >
-              列展示
+              {{ t('settingColumnShow') }}
             </Checkbox>
-            <a-button size="small" type="link" @click="reset">重置</a-button>
+            <a-button size="small" type="link" @click="reset"> {{ t('settingReset') }}</a-button>
           </div>
         </template>
         <SettingOutlined />
@@ -69,7 +69,7 @@
 
     <Tooltip placement="top" v-if="getSetting.fullScreen">
       <template #title>
-        <span>全屏</span>
+        <span>{{ t('settingFullScreen') }}</span>
       </template>
       <FullscreenOutlined @click="handleFullScreen" v-if="!isFullscreenRef" />
       <FullscreenExitOutlined @click="handleFullScreen" v-else />
@@ -90,6 +90,7 @@
   import { useFullscreen } from '/@/hooks/web/useFullScreen';
 
   import type { SizeType, TableSetting } from '../types/table';
+  import { useI18n } from '/@/hooks/web/useI18n';
 
   interface Options {
     label: string;
@@ -139,6 +140,8 @@
         defaultCheckList: [],
       });
 
+      const { t } = useI18n('component.table');
+
       function init() {
         let ret: Options[] = [];
         table.getColumns({ ignoreIndex: true, ignoreAction: true }).forEach((item) => {
@@ -217,6 +220,7 @@
         reset,
         getSetting,
         ...toRefs(state),
+        t,
       };
     },
   });

+ 3 - 1
src/components/Table/src/hooks/useColumns.ts

@@ -4,7 +4,9 @@ import { unref, ComputedRef, Ref, computed, watchEffect, ref, toRaw } from 'vue'
 import { isBoolean, isArray, isObject } from '/@/utils/is';
 import { PAGE_SIZE } from '../const';
 import { useProps } from './useProps';
+import { useI18n } from '/@/hooks/web/useI18n';
 
+const { t } = useI18n('component.table');
 export function useColumns(
   refProps: ComputedRef<BasicTableProps>,
   getPaginationRef: ComputedRef<false | PaginationProps>
@@ -42,7 +44,7 @@ export function useColumns(
       columns.unshift({
         flag: 'INDEX',
         width: 50,
-        title: '序号',
+        title: t('index'),
         align: 'center',
         customRender: ({ index }) => {
           const getPagination = unref(getPaginationRef);

+ 4 - 1
src/components/Table/src/hooks/usePagination.tsx

@@ -8,6 +8,9 @@ import { isBoolean } from '/@/utils/is';
 
 import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '../const';
 import { useProps } from './useProps';
+import { useI18n } from '/@/hooks/web/useI18n';
+
+const { t } = useI18n('component.table');
 export function usePagination(refProps: ComputedRef<BasicTableProps>) {
   const configRef = ref<PaginationProps>({});
   const { propsRef } = useProps(refProps);
@@ -22,7 +25,7 @@ export function usePagination(refProps: ComputedRef<BasicTableProps>) {
       pageSize: PAGE_SIZE,
       size: 'small',
       defaultPageSize: PAGE_SIZE,
-      showTotal: (total) => `共 ${total} 条数据`,
+      showTotal: (total) => t('total', { total }),
       showSizeChanger: true,
       pageSizeOptions: PAGE_SIZE_OPTIONS,
       itemRender: ({ page, type, originalElement }) => {

+ 1 - 1
src/components/Tinymce/src/lineHeight.ts

@@ -13,7 +13,7 @@ const lineHeight = function (tinymce: any) {
 
     t.ui.registry.addMenuButton('lineheight', {
       icon: 'lineheight',
-      tooltip: '设置行高',
+      tooltip: 'Line Height',
       // fetch: function (callback: Fn) {
       //   var dom = t.dom;
       //   var blocks = t.selection.getSelectedBlocks();

+ 5 - 2
src/components/Upload/src/BasicUpload.vue

@@ -2,11 +2,11 @@
   <div>
     <a-button-group>
       <a-button type="primary" @click="openUploadModal" preIcon="ant-design:cloud-upload-outlined">
-        上传
+        {{ t('upload') }}
       </a-button>
       <Tooltip placement="bottom" v-if="showPreview">
         <template #title>
-          已上传
+          {{ t('uploaded') }}
           <template v-if="fileListRef.length">{{ fileListRef.length }}</template>
         </template>
         <a-button @click="openPreviewModal">
@@ -39,12 +39,14 @@
 
   import { uploadContainerProps } from './props';
   import { omit } from 'lodash-es';
+  import { useI18n } from '/@/hooks/web/useI18n';
 
   export default defineComponent({
     name: 'BasicUpload',
     components: { UploadModal, UploadPreviewModal, Icon, Tooltip },
     props: uploadContainerProps,
     setup(props, { emit, attrs }) {
+      const { t } = useI18n('component.upload');
       // 上传modal
       const [registerUploadModal, { openModal: openUploadModal }] = useModal();
 
@@ -94,6 +96,7 @@
         fileListRef,
         showPreview,
         bindValue,
+        t,
       };
     },
   });

+ 20 - 11
src/components/Upload/src/UploadModal.vue

@@ -1,8 +1,8 @@
 <template>
   <BasicModal
     width="800px"
-    title="上传"
-    okText="保存"
+    :title="t('upload')"
+    :okText="t('save')"
     v-bind="$attrs"
     @register="register"
     @ok="handleOk"
@@ -31,7 +31,7 @@
         :before-upload="beforeUpload"
         class="upload-modal-toolbar__btn"
       >
-        <a-button type="primary"> 选择文件 </a-button>
+        <a-button type="primary"> {{ t('choose') }} </a-button>
       </Upload>
     </div>
     <FileList :dataSource="fileListRef" :columns="columns" :actionColumn="actionColumn" />
@@ -57,11 +57,15 @@
   import { isFunction } from '/@/utils/is';
   import { warn } from '/@/utils/log';
   import FileList from './FileList';
+
+  import { useI18n } from '/@/hooks/web/useI18n';
   export default defineComponent({
     components: { BasicModal, Upload, Alert, FileList },
     props: basicProps,
     setup(props, { emit }) {
       //   是否正在上传
+      const { t } = useI18n('component.upload');
+
       const isUploadingRef = ref(false);
       const fileListRef = ref<FileItem[]>([]);
       const state = reactive<{ fileList: FileItem[] }>({
@@ -100,7 +104,11 @@
         const someError = fileListRef.value.some(
           (item) => item.status === UploadResultStatus.ERROR
         );
-        return isUploadingRef.value ? '上传中' : someError ? '重新上传失败文件' : '开始上传';
+        return isUploadingRef.value
+          ? t('uploading')
+          : someError
+          ? t('reUploadFailed')
+          : t('startUpload');
       });
 
       // 上传前校验
@@ -111,13 +119,13 @@
 
         // 设置最大值,则判断
         if (maxSize && file.size / 1024 / 1024 >= maxSize) {
-          createMessage.error(`只能上传不超过${maxSize}MB的文件!`);
+          createMessage.error(t('maxSizeMultiple', [maxSize]));
           return false;
         }
 
         // 设置类型,则判断
         if (accept.length > 0 && !checkFileType(file, accept)) {
-          createMessage.error!(`只能上传${accept.join(',')}格式文件`);
+          createMessage.error!(t('acceptUpload', [accept.join(',')]));
           return false;
         }
         const commonItem = {
@@ -198,7 +206,7 @@
       async function handleStartUpload() {
         const { maxNumber } = props;
         if (fileListRef.value.length > maxNumber) {
-          return createMessage.warning(`最多只能上传${maxNumber}个文件`);
+          return createMessage.warning(t('maxNumber', [maxNumber]));
         }
         try {
           isUploadingRef.value = true;
@@ -225,10 +233,10 @@
         const { maxNumber } = props;
 
         if (fileListRef.value.length > maxNumber) {
-          return createMessage.warning(`最多只能上传${maxNumber}个文件`);
+          return createMessage.warning(t('maxNumber', [maxNumber]));
         }
         if (isUploadingRef.value) {
-          return createMessage.warning('请等待文件上传后,保存');
+          return createMessage.warning(t('saveWarn'));
         }
         const fileList: string[] = [];
 
@@ -240,7 +248,7 @@
         }
         // 存在一个上传成功的即可保存
         if (fileList.length <= 0) {
-          return createMessage.warning('没有上传成功的文件,无法保存');
+          return createMessage.warning(t('saveError'));
         }
         fileListRef.value = [];
         closeModal();
@@ -253,7 +261,7 @@
           fileListRef.value = [];
           return true;
         } else {
-          createMessage.warning('请等待文件上传结束后操作');
+          createMessage.warning(t('uploadWait'));
           return false;
         }
       }
@@ -285,6 +293,7 @@
         handleCloseFunc,
         getIsSelectFile,
         getUploadBtnText,
+        t,
       };
     },
   });

+ 6 - 1
src/components/Upload/src/UploadPreviewModal.vue

@@ -1,7 +1,7 @@
 <template>
   <BasicModal
     width="800px"
-    title="预览"
+    :title="t('preview')"
     wrapClassName="upload-preview-modal"
     v-bind="$attrs"
     @register="register"
@@ -23,11 +23,15 @@
   import { downloadByUrl } from '/@/utils/file/download';
 
   import { createPreviewColumns, createPreviewActionColumn } from './data';
+
+  import { useI18n } from '/@/hooks/web/useI18n';
   export default defineComponent({
     components: { BasicModal, FileList },
     props: previewProps,
     setup(props, { emit }) {
       const [register, { closeModal }] = useModalInner();
+      const { t } = useI18n('component.upload');
+
       const fileListRef = ref<PreviewFileItem[]>([]);
       watch(
         () => props.value,
@@ -74,6 +78,7 @@
       }
 
       return {
+        t,
         register,
         closeModal,
         fileListRef,

+ 19 - 16
src/components/Upload/src/data.tsx

@@ -6,12 +6,15 @@ import { Progress, Tag } from 'ant-design-vue';
 
 import TableAction from '/@/components/Table/src/components/TableAction';
 
+import { useI18n } from '/@/hooks/web/useI18n';
+const { t } = useI18n('component.upload');
+
 // 文件上传列表
 export function createTableColumns(): BasicColumn[] {
   return [
     {
       dataIndex: 'thumbUrl',
-      title: '图例',
+      title: t('legend'),
       width: 100,
       customRender: ({ record }) => {
         const { thumbUrl, type } = (record as FileItem) || {};
@@ -20,7 +23,7 @@ export function createTableColumns(): BasicColumn[] {
     },
     {
       dataIndex: 'name',
-      title: '文件名',
+      title: t('fileName'),
       align: 'left',
       customRender: ({ text, record }) => {
         const { percent, status: uploadStatus } = (record as FileItem) || {};
@@ -44,7 +47,7 @@ export function createTableColumns(): BasicColumn[] {
     },
     {
       dataIndex: 'size',
-      title: '文件大小',
+      title: t('fileSize'),
       width: 100,
       customRender: ({ text = 0 }) => {
         return text && (text / 1024).toFixed(2) + 'KB';
@@ -57,15 +60,15 @@ export function createTableColumns(): BasicColumn[] {
     // },
     {
       dataIndex: 'status',
-      title: '状态',
+      title: t('fileStatue'),
       width: 100,
       customRender: ({ text }) => {
         if (text === UploadResultStatus.SUCCESS) {
-          return <Tag color="green">{() => '上传成功'}</Tag>;
+          return <Tag color="green">{() => t('uploadSuccess')}</Tag>;
         } else if (text === UploadResultStatus.ERROR) {
-          return <Tag color="red">{() => '上传失败'}</Tag>;
+          return <Tag color="red">{() => t('uploadError')}</Tag>;
         } else if (text === UploadResultStatus.UPLOADING) {
-          return <Tag color="blue">{() => '上传中'}</Tag>;
+          return <Tag color="blue">{() => t('uploading')}</Tag>;
         }
 
         return text;
@@ -76,20 +79,20 @@ export function createTableColumns(): BasicColumn[] {
 export function createActionColumn(handleRemove: Function, handlePreview: Function): BasicColumn {
   return {
     width: 120,
-    title: '操作',
+    title: t('operating'),
     dataIndex: 'action',
     fixed: false,
     customRender: ({ record }) => {
       const actions: ActionItem[] = [
         {
-          label: '删除',
+          label: t('del'),
           color: 'error',
           onClick: handleRemove.bind(null, record),
         },
       ];
       if (checkImgType(record)) {
         actions.unshift({
-          label: '预览',
+          label: t('preview'),
           onClick: handlePreview.bind(null, record),
         });
       }
@@ -102,7 +105,7 @@ export function createPreviewColumns(): BasicColumn[] {
   return [
     {
       dataIndex: 'url',
-      title: '图例',
+      title: t('legend'),
       width: 100,
       customRender: ({ record }) => {
         const { url, type } = (record as PreviewFileItem) || {};
@@ -113,7 +116,7 @@ export function createPreviewColumns(): BasicColumn[] {
     },
     {
       dataIndex: 'name',
-      title: '文件名',
+      title: t('fileName'),
       align: 'left',
     },
   ];
@@ -130,7 +133,7 @@ export function createPreviewActionColumn({
 }): BasicColumn {
   return {
     width: 160,
-    title: '操作',
+    title: t('operating'),
     dataIndex: 'action',
     fixed: false,
     customRender: ({ record }) => {
@@ -138,18 +141,18 @@ export function createPreviewActionColumn({
 
       const actions: ActionItem[] = [
         {
-          label: '删除',
+          label: t('del'),
           color: 'error',
           onClick: handleRemove.bind(null, record),
         },
         {
-          label: '下载',
+          label: t('download'),
           onClick: handleDownload.bind(null, record),
         },
       ];
       if (isImgTypeByName(url)) {
         actions.unshift({
-          label: '预览',
+          label: t('preview'),
           onClick: handlePreview.bind(null, record),
         });
       }

+ 5 - 4
src/components/Upload/src/useUpload.ts

@@ -1,5 +1,6 @@
 import { Ref, unref, computed } from 'vue';
-
+import { useI18n } from '/@/hooks/web/useI18n';
+const { t } = useI18n('component.upload');
 export function useUploadType({
   acceptRef,
   //   uploadTypeRef,
@@ -37,17 +38,17 @@ export function useUploadType({
 
     const accept = unref(acceptRef);
     if (accept.length > 0) {
-      helpTexts.push(`支持${accept.join(',')}格式`);
+      helpTexts.push(t('accept', [accept.join(',')]));
     }
 
     const maxSize = unref(maxSizeRef);
     if (maxSize) {
-      helpTexts.push(`单个文件不超过${maxSize}MB`);
+      helpTexts.push(t('maxSize', [maxSize]));
     }
 
     const maxNumber = unref(maxNumberRef);
     if (maxNumber && maxNumber !== Infinity) {
-      helpTexts.push(`最多只能上传${maxNumber}个文件`);
+      helpTexts.push(t('maxNumber', [maxNumber]));
     }
     return helpTexts.join(',');
   });

+ 7 - 3
src/components/Verify/src/ImgRotate.tsx

@@ -1,3 +1,5 @@
+import './ImgRotate.less';
+
 import type { MoveData, DragVerifyActionType } from './types';
 
 import { defineComponent, computed, unref, reactive, watch, ref, getCurrentInstance } from 'vue';
@@ -8,7 +10,8 @@ import BasicDragVerify from './DragVerify';
 import { hackCss } from '/@/utils/domUtils';
 
 import { rotateProps } from './props';
-import './ImgRotate.less';
+import { useI18n } from '/@/hooks/web/useI18n';
+
 export default defineComponent({
   name: 'ImgRotateDargVerify',
   inheritAttrs: false,
@@ -27,6 +30,7 @@ export default defineComponent({
       endTime: 0,
       draged: false,
     });
+    const { t } = useI18n('component.verify');
 
     watch(
       () => state.isPassing,
@@ -142,11 +146,11 @@ export default defineComponent({
             />
             {state.showTip && (
               <span class={[`ir-dv-img__tip`, state.isPassing ? 'success' : 'error']}>
-                {state.isPassing ? `校验成功,耗时${time.toFixed(1)}秒!` : '验证失败!'}
+                {state.isPassing ? t('time', { time: time.toFixed(1) }) : t('error')}
               </span>
             )}
             {!state.showTip && !state.draged && (
-              <span class={[`ir-dv-img__tip`, 'normal']}>点击图片可刷新</span>
+              <span class={[`ir-dv-img__tip`, 'normal']}>t('redoTip')</span>
             )}
           </div>
           <BasicDragVerify

+ 0 - 44
src/components/Verify/src/VerifyModal.vue

@@ -1,44 +0,0 @@
-<script lang="tsx">
-  import { defineComponent, ref, unref } from 'vue';
-  import { BasicModal } from '/@/components/Modal/index';
-  import { useTimeoutFn } from '/@/hooks/core/useTimeout';
-
-  import { RotateDragVerify, DragVerifyActionType } from '/@/components/Verify/index';
-  export default defineComponent({
-    name: 'VerifyModal',
-
-    setup(_, { attrs, emit }) {
-      const dragRef = ref<DragVerifyActionType | null>(null);
-
-      function handleSuccess() {
-        useTimeoutFn(() => {
-          emit('success');
-          const dragEl = unref(dragRef);
-          if (dragEl) {
-            dragEl.resume();
-          }
-        }, 500);
-      }
-      return () => (
-        <BasicModal
-          {...attrs}
-          title="安全校验"
-          keyboard={false}
-          maskClosable={false}
-          canFullscreen={false}
-          footer={null}
-          wrapperFooterOffset={60}
-          destroyOnClose={true}
-        >
-          <RotateDragVerify
-            imgWidth={210}
-            ref={dragRef}
-            text="请拖动滑块将图片摆正"
-            {...attrs}
-            onSuccess={handleSuccess}
-          />
-        </BasicModal>
-      );
-    },
-  });
-</script>

+ 4 - 2
src/components/Verify/src/props.ts

@@ -1,5 +1,7 @@
 import type { PropType } from 'vue';
+import { useI18n } from '/@/hooks/web/useI18n';
 
+const { t } = useI18n('component.verify');
 export const basicProps = {
   value: {
     type: Boolean as PropType<boolean>,
@@ -13,11 +15,11 @@ export const basicProps = {
 
   text: {
     type: [String] as PropType<string>,
-    default: '请按住滑块拖动',
+    default: t('dragText'),
   },
   successText: {
     type: [String] as PropType<string>,
-    default: '验证通过',
+    default: t('successText'),
   },
   height: {
     type: [Number, String] as PropType<number | string>,

+ 5 - 0
src/locales/lang/en/component/drawer.ts

@@ -0,0 +1,5 @@
+export default {
+  loadingText: 'Loading...',
+  cancelText: 'Close',
+  okText: 'Confirm',
+};

+ 5 - 0
src/locales/lang/en/component/excel.ts

@@ -0,0 +1,5 @@
+export default {
+  exportModalTitle: 'Export data',
+  fileType: 'File type',
+  fileName: 'File name',
+};

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

@@ -0,0 +1,9 @@
+export default {
+  resetButton: 'Reset',
+  submitButton: 'Search',
+  putAway: 'Put away',
+  unfold: 'Unfold',
+
+  input: 'Please Input',
+  choose: 'Please Choose',
+};

+ 3 - 0
src/locales/lang/en/component/menu.ts

@@ -0,0 +1,3 @@
+export default {
+  search: 'Menu search',
+};

+ 4 - 0
src/locales/lang/en/component/modal.ts

@@ -0,0 +1,4 @@
+export default {
+  cancelText: 'Close',
+  okText: 'Confirm',
+};

+ 15 - 0
src/locales/lang/en/component/table.ts

@@ -0,0 +1,15 @@
+export default {
+  settingRedo: 'Refresh',
+  settingDens: 'Density',
+  settingDensDefault: 'Default',
+  settingDensMiddle: 'Middle',
+  settingDensSmall: 'Compact',
+  settingColumn: 'Column settings',
+  settingColumnShow: 'Column display',
+  settingReset: 'Reset',
+  settingFullScreen: 'Full Screen',
+
+  index: 'Index',
+
+  total: 'total of {total}',
+};

+ 32 - 0
src/locales/lang/en/component/upload.ts

@@ -0,0 +1,32 @@
+export default {
+  save: 'Save',
+  upload: 'Upload',
+  uploaded: 'Uploaded',
+
+  operating: 'Operating',
+  del: 'Delete',
+  download: 'download',
+  saveWarn: 'Please wait for the file to upload and save!',
+  saveError: 'There is no file successfully uploaded and cannot be saved!',
+
+  preview: 'Preview',
+  choose: 'Select the file',
+
+  accept: 'Support {0} format',
+  acceptUpload: 'Only upload files in {0} format',
+  maxSize: 'A single file does not exceed {0}MB ',
+  maxSizeMultiple: 'Only upload files up to {0}MB!',
+  maxNumber: 'Only upload up to {0} files',
+
+  legend: 'Legend',
+  fileName: 'File name',
+  fileSize: 'File size',
+  fileStatue: 'File status',
+
+  startUpload: 'Start upload',
+  uploadSuccess: 'Upload successfully',
+  uploadError: 'Upload failed',
+  uploading: 'Uploading',
+  uploadWait: 'Please wait for the file upload to finish',
+  reUploadFailed: 'Re-upload failed files',
+};

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

@@ -0,0 +1,9 @@
+export default {
+  error: 'verification failed!',
+  time: 'The verification is successful and it takes {time} seconds!',
+
+  redoTip: 'Click the picture to refresh',
+
+  dragText: 'Hold down the slider and drag',
+  successText: 'Verified',
+};

+ 5 - 0
src/locales/lang/zh_CN/component/drawer.ts

@@ -0,0 +1,5 @@
+export default {
+  loadingText: '加载中...',
+  cancelText: '关闭',
+  okText: '确认',
+};

+ 5 - 0
src/locales/lang/zh_CN/component/excel.ts

@@ -0,0 +1,5 @@
+export default {
+  exportModalTitle: '导出数据',
+  fileType: '文件类型',
+  fileName: '文件名',
+};

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

@@ -0,0 +1,9 @@
+export default {
+  resetButton: '重置',
+  submitButton: '查询',
+  putAway: '收起',
+  unfold: '展开',
+
+  input: '请输入',
+  choose: '请选择',
+};

+ 3 - 0
src/locales/lang/zh_CN/component/menu.ts

@@ -0,0 +1,3 @@
+export default {
+  search: '菜单搜索',
+};

+ 5 - 0
src/locales/lang/zh_CN/component/modal.ts

@@ -0,0 +1,5 @@
+export default {
+  loadingText: '加载中...',
+  cancelText: '关闭',
+  okText: '确认',
+};

+ 15 - 0
src/locales/lang/zh_CN/component/table.ts

@@ -0,0 +1,15 @@
+export default {
+  settingRedo: '刷新',
+  settingDens: '密度',
+  settingDensDefault: '默认',
+  settingDensMiddle: '中等',
+  settingDensSmall: '紧凑',
+  settingColumn: '列设置',
+  settingColumnShow: '列展示',
+  settingReset: '重置',
+  settingFullScreen: '全屏',
+
+  index: '序号',
+
+  total: '共 {total} 条数据',
+};

+ 32 - 0
src/locales/lang/zh_CN/component/upload.ts

@@ -0,0 +1,32 @@
+export default {
+  save: '保存',
+  upload: '上传',
+  uploaded: '已上传',
+
+  operating: '操作',
+  del: '删除',
+  download: '下载',
+  saveWarn: '请等待文件上传后,保存!',
+  saveError: '没有上传成功的文件,无法保存!',
+
+  preview: '预览',
+  choose: '选择文件',
+
+  accept: '支持{0}格式',
+  acceptUpload: '只能上传{0}格式文件',
+  maxSize: '单个文件不超过{0}MB',
+  maxSizeMultiple: '只能上传不超过{0}MB的文件!',
+  maxNumber: '最多只能上传{0}个文件',
+
+  legend: '图例',
+  fileName: '文件名',
+  fileSize: '文件大小',
+  fileStatue: '状态',
+
+  startUpload: '开始上传',
+  uploadSuccess: '上传成功',
+  uploadError: '上传失败',
+  uploading: '上传中',
+  uploadWait: '请等待文件上传结束后操作',
+  reUploadFailed: '重新上传失败文件',
+};

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

@@ -0,0 +1,9 @@
+export default {
+  error: '验证失败!',
+  time: '验证校验成功,耗时{time}秒!',
+
+  redoTip: '点击图片可刷新',
+
+  dragText: '请按住滑块拖动',
+  successText: '验证通过',
+};

+ 148 - 34
yarn.lock

@@ -292,6 +292,11 @@
   resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.12.5.tgz#b4af32ddd473c0bfa643bd7ff0728b8e71b81ea0"
   integrity sha512-FVM6RZQ0mn2KCf1VUED7KepYeUWoVShczewOCfm3nzoBybaih51h+sYVVGthW9M6lPByEPTQf+xm27PBdlpwmQ==
 
+"@babel/parser@^7.12.7":
+  version "7.12.7"
+  resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz#fee7b39fe809d0e73e5b25eecaf5780ef3d73056"
+  integrity sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==
+
 "@babel/plugin-proposal-async-generator-functions@^7.12.1":
   version "7.12.1"
   resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz#dc6c1170e27d8aca99ff65f4925bd06b1c90550e"
@@ -1136,10 +1141,10 @@
   dependencies:
     "@iconify/iconify" ">=2.0.0-rc.1"
 
-"@rollup/plugin-commonjs@^15.1.0":
-  version "15.1.0"
-  resolved "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-15.1.0.tgz#1e7d076c4f1b2abf7e65248570e555defc37c238"
-  integrity sha512-xCQqz4z/o0h2syQ7d9LskIMvBSH4PX5PjYdpSSvgS+pQik3WahkQVNWg3D8XJeYjZoVWnIUQYDghuEMRGrmQYQ==
+"@rollup/plugin-commonjs@^16.0.0":
+  version "16.0.0"
+  resolved "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-16.0.0.tgz#169004d56cd0f0a1d0f35915d31a036b0efe281f"
+  integrity sha512-LuNyypCP3msCGVQJ7ki8PqYdpjfEkE/xtFa5DqlF+7IBD0JsfMZ87C58heSwIMint58sAUZbt3ITqOmdQv/dXw==
   dependencies:
     "@rollup/pluginutils" "^3.1.0"
     commondir "^1.0.1"
@@ -1156,6 +1161,18 @@
   dependencies:
     "@rollup/pluginutils" "^3.0.8"
 
+"@rollup/plugin-node-resolve@^10.0.0":
+  version "10.0.0"
+  resolved "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-10.0.0.tgz#44064a2b98df7530e66acf8941ff262fc9b4ead8"
+  integrity sha512-sNijGta8fqzwA1VwUEtTvWCx2E7qC70NMsDh4ZG13byAXYigBNZMxALhKUSycBks5gupJdq0lFrKumFrRZ8H3A==
+  dependencies:
+    "@rollup/pluginutils" "^3.1.0"
+    "@types/resolve" "1.17.1"
+    builtin-modules "^3.1.0"
+    deepmerge "^4.2.2"
+    is-module "^1.0.0"
+    resolve "^1.17.0"
+
 "@rollup/plugin-node-resolve@^7.1.1":
   version "7.1.3"
   resolved "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz#80de384edfbd7bfc9101164910f86078151a3eca"
@@ -1209,7 +1226,7 @@
     estree-walker "^1.0.1"
     picomatch "^2.2.2"
 
-"@rollup/pluginutils@^4.0.0":
+"@rollup/pluginutils@^4.0.0", "@rollup/pluginutils@^4.1.0":
   version "4.1.0"
   resolved "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.0.tgz#0dcc61c780e39257554feb7f77207dceca13c838"
   integrity sha512-TrBhfJkFxA+ER+ew2U2/fHbebhLT/l/2pRk0hfj9KusXUuRXd2v0R58AfaZK9VXDQ4TogOSEmICVrQAA3zFnHQ==
@@ -1608,7 +1625,18 @@
     estree-walker "^2.0.1"
     source-map "^0.6.1"
 
-"@vue/compiler-dom@3.0.2", "@vue/compiler-dom@^3.0.2":
+"@vue/compiler-core@3.0.3":
+  version "3.0.3"
+  resolved "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.0.3.tgz#dbb4d5eb91f294038f0bed170a1c25f59f7dc74f"
+  integrity sha512-iWlRT8RYLmz7zkg84pTOriNUzjH7XACWN++ImFkskWXWeev29IKi7p76T9jKDaMZoPiGcUZ0k9wayuASWVxOwg==
+  dependencies:
+    "@babel/parser" "^7.12.0"
+    "@babel/types" "^7.12.0"
+    "@vue/shared" "3.0.3"
+    estree-walker "^2.0.1"
+    source-map "^0.6.1"
+
+"@vue/compiler-dom@3.0.2":
   version "3.0.2"
   resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.0.2.tgz#1d40de04bcdf9aabb79fb6a802dd70a2f3c2992a"
   integrity sha512-jvaL4QF2yXBJVD+JLbM2YA3e5fNfflJnfQ+GtfYk46ENGsEetqbkZqcX7fO+RHdG8tZBo7LCNBvgD0QLr+V4sg==
@@ -1616,7 +1644,15 @@
     "@vue/compiler-core" "3.0.2"
     "@vue/shared" "3.0.2"
 
-"@vue/compiler-sfc@*", "@vue/compiler-sfc@^3.0.0-rc.5", "@vue/compiler-sfc@^3.0.2":
+"@vue/compiler-dom@3.0.3", "@vue/compiler-dom@^3.0.3":
+  version "3.0.3"
+  resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.0.3.tgz#582ba30bc82da8409868bc1153ff0e0e2be617e5"
+  integrity sha512-6GdUbDPjsc0MDZGAgpi4lox+d+aW9/brscwBOLOFfy9wcI9b6yLPmBbjdIsJq3pYdJWbdvACdJ77avBBdHEP8A==
+  dependencies:
+    "@vue/compiler-core" "3.0.3"
+    "@vue/shared" "3.0.3"
+
+"@vue/compiler-sfc@*", "@vue/compiler-sfc@^3.0.0-rc.5":
   version "3.0.2"
   resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.0.2.tgz#22c70fed72c347a4d5fa2db2e80594b3193dce57"
   integrity sha512-viYjT5ehDSLM3v0jQ9hbTs4I5e/7lSlYsDOp7TQ1qcwHRvzoTQMTkFpY/Iae+LFKM124Ld17tBfXgfrZl9dt+g==
@@ -1638,6 +1674,28 @@
     postcss-selector-parser "^6.0.4"
     source-map "^0.6.1"
 
+"@vue/compiler-sfc@^3.0.3":
+  version "3.0.3"
+  resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.0.3.tgz#7fad9d40e139dd717713c0db701e1eb776f8349f"
+  integrity sha512-YocHSirye85kRVC4lU0+SE6uhrwGJzbhwkrqG4g6kmsAUopZ0qUjbICMlej5bYx2+AUz9yBIM7hpK8nIKFVFjg==
+  dependencies:
+    "@babel/parser" "^7.12.0"
+    "@babel/types" "^7.12.0"
+    "@vue/compiler-core" "3.0.3"
+    "@vue/compiler-dom" "3.0.3"
+    "@vue/compiler-ssr" "3.0.3"
+    "@vue/shared" "3.0.3"
+    consolidate "^0.16.0"
+    estree-walker "^2.0.1"
+    hash-sum "^2.0.0"
+    lru-cache "^5.1.1"
+    magic-string "^0.25.7"
+    merge-source-map "^1.1.0"
+    postcss "^7.0.32"
+    postcss-modules "^3.2.2"
+    postcss-selector-parser "^6.0.4"
+    source-map "^0.6.1"
+
 "@vue/compiler-ssr@3.0.2":
   version "3.0.2"
   resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.0.2.tgz#73af4d274a79bfcc72a996a9b45f1072e7deaa26"
@@ -1646,6 +1704,14 @@
     "@vue/compiler-dom" "3.0.2"
     "@vue/shared" "3.0.2"
 
+"@vue/compiler-ssr@3.0.3":
+  version "3.0.3"
+  resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.0.3.tgz#7d9e5c1b8c71d69865ac6c48d2e6eb2eecb68501"
+  integrity sha512-IjJMoHCiDk939Ix7Q5wrex59TVJr6JFQ95gf36f4G4UrVau0GGY/3HudnWT/6eyWJ7267+odqQs1uCZgDfL/Ww==
+  dependencies:
+    "@vue/compiler-dom" "3.0.3"
+    "@vue/shared" "3.0.3"
+
 "@vue/reactivity@3.0.2":
   version "3.0.2"
   resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.0.2.tgz#42ed5af6025b494a5e69b05169fcddf04eebfe77"
@@ -1653,6 +1719,13 @@
   dependencies:
     "@vue/shared" "3.0.2"
 
+"@vue/reactivity@3.0.3":
+  version "3.0.3"
+  resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.0.3.tgz#681ee01ceff9219bc4da6bbb7d9c97d452e44d1d"
+  integrity sha512-t39Qmc42MX7wJtf8L6tHlu17eP9Rc5w4aRnxpLHNWoaRxddv/7FBhWqusJ2Bwkk8ixFHOQeejcLMt5G469WYJw==
+  dependencies:
+    "@vue/shared" "3.0.3"
+
 "@vue/runtime-core@3.0.2":
   version "3.0.2"
   resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.0.2.tgz#d7ed462af1cb0bf9836668e4e6fab3f2f4b1bc00"
@@ -1661,7 +1734,24 @@
     "@vue/reactivity" "3.0.2"
     "@vue/shared" "3.0.2"
 
-"@vue/runtime-dom@3.0.2", "@vue/runtime-dom@^3.0.0":
+"@vue/runtime-core@3.0.3":
+  version "3.0.3"
+  resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.0.3.tgz#edab3c9ad122cf8afd034b174cd20c073fbf950a"
+  integrity sha512-Fd1JVnYI6at0W/2ERwJuTSq4S22gNt8bKEbICcvCAac7hJUZ1rylThlrhsvrgA+DVkWU01r0niNZQ4UddlNw7g==
+  dependencies:
+    "@vue/reactivity" "3.0.3"
+    "@vue/shared" "3.0.3"
+
+"@vue/runtime-dom@3.0.3":
+  version "3.0.3"
+  resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.0.3.tgz#5e3e5e5418b9defcac988d2be0cf65596fa2cc03"
+  integrity sha512-ytTvSlRaEYvLQUkkpruIBizWIwuIeHER0Ch/evO6kUaPLjZjX3NerVxA40cqJx8rRjb9keQso21U2Jcpk8GsTg==
+  dependencies:
+    "@vue/runtime-core" "3.0.3"
+    "@vue/shared" "3.0.3"
+    csstype "^2.6.8"
+
+"@vue/runtime-dom@^3.0.0":
   version "3.0.2"
   resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.0.2.tgz#9d166d03225558025d3d80f5039b646e0051b71c"
   integrity sha512-vqC1KK1yWthTw1FKzajT0gYQaEqAq7bpeeXQC473nllGC5YHbJhNAJLSmrDun1tjXqGF0UNCWYljYm+++BJv6w==
@@ -1675,6 +1765,11 @@
   resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.0.2.tgz#419bd85a2ebdbd4f42963e98c5a1b103452176d9"
   integrity sha512-Zx869zlNoujFOclKIoYmkh8ES2RcS/+Jn546yOiPyZ+3+Ejivnr+fb8l+DdXUEFjo+iVDNR3KyLzg03aBFfZ4Q==
 
+"@vue/shared@3.0.3":
+  version "3.0.3"
+  resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.0.3.tgz#ef12ebff93a446df281e8a0fd765b5aea8e7745b"
+  integrity sha512-yGgkF7u4W0Dmwri9XdeY50kOowN4UIX7aBQ///jbxx37itpzVjK7QzvD3ltQtPfWaJDGBfssGL0wpAgwX9OJpQ==
+
 "@vuedx/analyze@0.2.4-0":
   version "0.2.4-0"
   resolved "https://registry.npmjs.org/@vuedx/analyze/-/analyze-0.2.4-0.tgz#52766a6dcd2867320409fe517540fd0bf0394d48"
@@ -2213,6 +2308,11 @@ bytes@3.1.0:
   resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
   integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
 
+cac@^6.6.1:
+  version "6.6.1"
+  resolved "https://registry.npmjs.org/cac/-/cac-6.6.1.tgz#3dde3f6943f45d42a56729ea3573c08b3e7b6a6d"
+  integrity sha512-uhki4T3Ax68hw7Dufi0bATVAF8ayBSwOKUEJHjObPrUN4tlQ8Lf7oljpTje/mArLxYN0D743c2zJt4C1bVTCqg==
+
 cache-base@^1.0.1:
   version "1.0.1"
   resolved "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
@@ -3012,6 +3112,13 @@ debug@^4.3.0:
   dependencies:
     ms "2.1.2"
 
+debug@^4.3.1:
+  version "4.3.1"
+  resolved "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
+  integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
+  dependencies:
+    ms "2.1.2"
+
 debug@~3.1.0:
   version "3.1.0"
   resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
@@ -3344,11 +3451,16 @@ esbuild-register@^1.1.0:
     source-map-support "^0.5.19"
     strip-json-comments "^3.1.1"
 
-esbuild@^0.7.17, esbuild@^0.7.19, esbuild@^0.7.21:
+esbuild@^0.7.17, esbuild@^0.7.19:
   version "0.7.22"
   resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.7.22.tgz#9149b903f8128b7c45a754046c24199d76bbe08e"
   integrity sha512-B43SYg8LGWYTCv9Gs0RnuLNwjzpuWOoCaZHTWEDEf5AfrnuDMerPVMdCEu7xOdhFvQ+UqfP2MGU9lxEy0JzccA==
 
+esbuild@^0.8.12:
+  version "0.8.15"
+  resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.8.15.tgz#cbc4d82a7fc4571d455233456e6fba83fd0364f1"
+  integrity sha512-mSaLo9t/oYtQE6FRUEdO47Pr8PisSPzHtgr+LcihIcjBEhbYwjT6WLCQ7noDoTBfIatBCw229rtmIwl9u9UQwg==
+
 escalade@^3.1.1:
   version "3.1.1"
   resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
@@ -6871,10 +6983,10 @@ rollup-plugin-visualizer@^4.1.2:
     source-map "^0.7.3"
     yargs "^16.0.3"
 
-rollup-plugin-vue@^6.0.0-beta.10:
-  version "6.0.0-beta.11"
-  resolved "https://registry.npmjs.org/rollup-plugin-vue/-/rollup-plugin-vue-6.0.0-beta.11.tgz#fdbc6b7484a361ef8c5e8009cef4a6bd45435013"
-  integrity sha512-osqLkFc7N76TOI0CeW0BOujlMFsMIoytyTRVUivaeYSMponNfk1iSuqyoeciUB3EjFqyL/dTTFPi+7rhaAm73w==
+rollup-plugin-vue@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.npmjs.org/rollup-plugin-vue/-/rollup-plugin-vue-6.0.0.tgz#e379e93e5ae9a8648522f698be2e452e8672aaf2"
+  integrity sha512-oVvUd84d5u73M2HYM3XsMDLtZRIA/tw2U0dmHlXU2UWP5JARYHzh/U9vcxaN/x/9MrepY7VH3pHFeOhrWpxs/Q==
   dependencies:
     debug "^4.1.1"
     hash-sum "^2.0.0"
@@ -8104,30 +8216,31 @@ vite-plugin-pwa@^0.1.5:
     fast-glob "^3.2.4"
     rollup-plugin-workbox "^5.2.1"
 
-vite@^1.0.0-rc.9:
-  version "1.0.0-rc.9"
-  resolved "https://registry.npmjs.org/vite/-/vite-1.0.0-rc.9.tgz#63621a39cf36fe9a6dccafdb11360a5ebbdb2663"
-  integrity sha512-u0PT2sKMes2RtE5rZsLY0nFm6kEmce7IhVRWKFXmrsjn0MBOCNEi+S6iNnJDmsj1nzvU2dMZ5MHhFyXIqTgjzA==
+vite@^1.0.0-rc.10:
+  version "1.0.0-rc.10"
+  resolved "https://registry.npmjs.org/vite/-/vite-1.0.0-rc.10.tgz#d8d139dc640fa073e4a1b8abdb037a131fa364cc"
+  integrity sha512-Kh2lq2zpsbyYRlI/uXHEyEMLzOSBXmza23k69LB6imIeH8HddvSoi+AqOTbSK/CQhfw3lvoPgb3h+tIbK5zymg==
   dependencies:
-    "@babel/parser" "^7.12.3"
+    "@babel/parser" "^7.12.7"
     "@koa/cors" "^3.1.0"
-    "@rollup/plugin-commonjs" "^15.1.0"
+    "@rollup/plugin-commonjs" "^16.0.0"
     "@rollup/plugin-json" "^4.1.0"
-    "@rollup/plugin-node-resolve" "^9.0.0"
-    "@rollup/pluginutils" "^4.0.0"
+    "@rollup/plugin-node-resolve" "^10.0.0"
+    "@rollup/pluginutils" "^4.1.0"
     "@types/koa" "^2.11.4"
     "@types/lru-cache" "^5.1.0"
-    "@vue/compiler-dom" "^3.0.2"
-    "@vue/compiler-sfc" "^3.0.2"
+    "@vue/compiler-dom" "^3.0.3"
+    "@vue/compiler-sfc" "^3.0.3"
     brotli-size "^4.0.0"
+    cac "^6.6.1"
     chalk "^4.1.0"
     chokidar "^3.4.2"
     clean-css "^4.2.3"
-    debug "^4.1.1"
+    debug "^4.3.1"
     dotenv "^8.2.0"
     dotenv-expand "^5.1.0"
     es-module-lexer "^0.3.25"
-    esbuild "^0.7.21"
+    esbuild "^0.8.12"
     etag "^1.8.1"
     execa "^4.0.3"
     fs-extra "^9.0.1"
@@ -8155,11 +8268,12 @@ vite@^1.0.0-rc.9:
     rollup "^2.32.1"
     rollup-plugin-dynamic-import-variables "^1.1.0"
     rollup-plugin-terser "^7.0.2"
-    rollup-plugin-vue "^6.0.0-beta.10"
+    rollup-plugin-vue "^6.0.0"
     rollup-plugin-web-worker-loader "^1.3.1"
     selfsigned "^1.10.8"
     slash "^3.0.0"
-    vue "^3.0.2"
+    source-map "^0.7.3"
+    vue "^3.0.3"
     ws "^7.3.1"
 
 vscode-languageserver-textdocument@^1.0.1:
@@ -8203,14 +8317,14 @@ vue-types@^3.0.0:
   dependencies:
     is-plain-object "3.0.1"
 
-vue@^3.0.2:
-  version "3.0.2"
-  resolved "https://registry.npmjs.org/vue/-/vue-3.0.2.tgz#9d5b7b2983f35e64a34d13c7c9d6831239feca3c"
-  integrity sha512-ciKFjutKRs+2Vbvgrist1oDd5wZQqtOel/K//ku54zLbf8tcTV+XbyAfanTHcTkML9CUj09vnC+y+5uaOz2/9g==
+vue@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.npmjs.org/vue/-/vue-3.0.3.tgz#ad94a475e6ebbf3904673b6a0ae46e47b957bd72"
+  integrity sha512-BZG5meD5vLWdvfnRL5WqfDy+cnXO1X/SweModGUna78bdFPZW6+ZO1tU9p0acrskX3DKFcfSp2s4SZnMjABx6w==
   dependencies:
-    "@vue/compiler-dom" "3.0.2"
-    "@vue/runtime-dom" "3.0.2"
-    "@vue/shared" "3.0.2"
+    "@vue/compiler-dom" "3.0.3"
+    "@vue/runtime-dom" "3.0.3"
+    "@vue/shared" "3.0.3"
 
 vuex-module-decorators@^1.0.1:
   version "1.0.1"