vben
2020-12-01 962f90de445d7935ad76ea7b74a98f12ce9a7498
feat: support vscode i18n-ally plugin
39个文件已修改
522 ■■■■ 已修改文件
.vscode/extensions.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
.vscode/settings.json 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CHANGELOG.zh_CN.md 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Drawer/src/BasicDrawer.tsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Drawer/src/props.ts 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Excel/src/ExportExcelModel.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Form/src/FormAction.tsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Form/src/FormItem.tsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Form/src/helper.ts 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Menu/src/SearchInput.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Modal/src/props.ts 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Table/src/components/TableSetting.vue 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Table/src/hooks/useColumns.ts 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Table/src/hooks/usePagination.tsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Upload/src/BasicUpload.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Upload/src/UploadModal.vue 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Upload/src/UploadPreviewModal.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Upload/src/data.tsx 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Upload/src/useUpload.ts 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Verify/src/ImgRotate.tsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Verify/src/props.ts 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/default/footer/index.tsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/default/header/LayoutHeader.tsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/default/header/UserDropdown.tsx 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/default/lock/LockAction.tsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/default/multitabs/TabContent.tsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/default/multitabs/data.ts 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/default/setting/SettingDrawer.tsx 95 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/default/setting/enum.ts 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/permission.ts 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/user.ts 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/http/axios/checkStatus.ts 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/http/axios/index.ts 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/sys/error-log/DetailModal.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/sys/error-log/data.tsx 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/sys/error-log/index.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/sys/exception/Exception.tsx 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/sys/lock/index.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/sys/login/Login.vue 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.vscode/extensions.json
@@ -5,8 +5,8 @@
    "stylelint.vscode-stylelint",
    "DavidAnson.vscode-markdownlint",
    "esbenp.prettier-vscode",
    "mrmlnc.vscode-scss",
    "mrmlnc.vscode-less",
    "antfu.i18n-ally",
    "cpylua.language-postcss",
    "Orta.vscode-jest",
    "antfu.iconify",
.vscode/settings.json
@@ -10,14 +10,13 @@
  "editor.smoothScrolling": true,
  "editor.cursorBlinking": "phase",
  "editor.cursorSmoothCaretAnimation": true,
  "editor.detectIndentation": false, // vscode默认启用了根据文件类型自动设置tabsize的选项
  "editor.detectIndentation": false,
  "diffEditor.ignoreTrimWhitespace": false,
  "editor.formatOnPaste": true, //自动格式化粘贴的内容
  "editor.formatOnSave": true, //保存自动格式化
  "editor.formatOnPaste": true,
  "editor.formatOnSave": true,
  "editor.suggestSelection": "first",
  "editor.trimAutoWhitespace": true,
  "editor.quickSuggestions": {
    //   快速提示
    "other": true,
    "comments": true,
    "strings": true
@@ -25,41 +24,33 @@
  //===========================================
  //============= Other =======================
  //===========================================
  "breadcrumbs.enabled": true, // 启用/禁用导航路径
  "open-in-browser.default": "chrome", // 默认浏览器
  "breadcrumbs.enabled": true,
  "open-in-browser.default": "chrome",
  //===========================================
  //============= emmet =======================
  //===========================================
  "emmet.triggerExpansionOnTab": true, // 配置emmet是否启用tab展开缩写
  "emmet.triggerExpansionOnTab": true,
  "emmet.showAbbreviationSuggestions": true,
  "emmet.showExpandedAbbreviation": "always",
  "emmet.syntaxProfiles": {
    // 配置emmet对文件类型的支持,比如vue后缀文件按照html文件来进行emmet扩写
    "vue-html": "html",
    "vue": "html",
    "javascript": "javascriptreact",
    // xml类型文件默认都是单引号,开启对非单引号的emmet识别
    "xml": {
      "attr_quotes": "single"
    }
  },
  "emmet.includeLanguages": {
    // 在react的jsx中添加对emmet的支持
    "jsx-sublime-babel-tags": "javascriptreact"
  },
  //===========================================
  //============= files =======================
  //===========================================
  // "files.autoSave": "onWindowChange", // 窗口失去焦点自动保存
  // "files.autoSaveDelay": 1000, // 自动保存时间
  "files.trimTrailingWhitespace": true, // 启用后,将在保存文件时剪裁尾随空格。
  // 文件末尾插入新行
  "files.trimTrailingWhitespace": true,
  "files.insertFinalNewline": true,
  // 删除文件末尾多余的新行
  "files.trimFinalNewlines": true,
  "files.eol": "\n",
  "search.exclude": {
    // 搜索排除这些区域
    "**/node_modules": true,
    "**/*.log": true,
    "**/*.log*": true,
@@ -76,8 +67,6 @@
    "**/tmp": true
  },
  "files.exclude": {
    // 排除文件搜索区域,比如node_modules(默认设置已经屏蔽了)
    // "**/node_modules": true,
    "**/bower_components": true,
    "**/.idea": true,
    "**/yarn.lock": true,
@@ -100,7 +89,6 @@
    "**/yarn.lock": true
  },
  "files.associations": {
    // 配置文件关联,以便启用对应的智能提示,比如wxss使用css
    "*.vue": "vue",
    "*.wxss": "css"
  },
@@ -109,13 +97,11 @@
  "css.validate": true,
  "less.validate": true,
  "scss.validate": true,
  // ↓↓↓↓↓↓↓↓↓↓↓↓↓ 以下为插件设置 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
  // ↓↓↓↓↓↓↓↓↓↓↓↓↓ 需要安装对应的插件 ↓↓↓↓↓↓↓↓↓↓↓↓
  // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
  // ===========================================
  // ================ Eslint ===================
  // ===========================================
  "eslint.enable": true, // 是否开启eslint
  "eslint.enable": true,
  "eslint.options": {
    // 配置
    "plugins": [
@@ -126,53 +112,41 @@
      "typescript"
    ]
  },
  "eslint.autoFixOnSave": true, // 保存自动格式化
  "eslint.autoFixOnSave": true,
  // ===========================================
  // ================ Vetur ====================
  // ===========================================
  "vetur.experimental.templateInterpolationService": true,
  "vetur.format.options.tabSize": 2,
  "vetur.format.defaultFormatter.html": "js-beautify-html", // 使用js-beautify-html格式化
  "vetur.format.defaultFormatter.scss": "prettier", // 使用js-beautify-html格式化
  "vetur.format.defaultFormatter.css": "prettier", // 使用js-beautify-html格式化
  //   "vetur.format.defaultFormatter.html": "prettyhtml",
  "vetur.format.defaultFormatter.html": "js-beautify-html",
  "vetur.format.defaultFormatter.scss": "prettier",
  "vetur.format.defaultFormatter.css": "prettier",
  "vetur.format.defaultFormatter.ts": "prettier-tslint",
  "vetur.format.defaultFormatter.js": "prettier",
    "vetur.languageFeatures.codeActions": false,
  // "vetur.useWorkspaceDependencies": true,
  "vetur.languageFeatures.codeActions": false,
  "vetur.format.defaultFormatterOptions": {
    "js-beautify-html": {
      //   "wrap_attributes": "force-aligned", // 单行
      "wrap_attributes": "force-expand-multiline" // 属性强制折行对齐 多行
      "wrap_attributes": "force-expand-multiline"
    },
    "prettier": {
      "eslintIntegration": true, // 让perttier使用eslint的格式进行检查
      "arrowParens": "always", // 箭头函数参数括号 默认avoid 可选 avoid | always
      "semi": false, // 使用分号, 默认true
      "singleQuote": true // 使用单引号, 默认false(在jsx中配置无效, 默认都是双引号)
      "eslintIntegration": true,
      "arrowParens": "always",
      "semi": false,
      "singleQuote": true
    }
  },
  // 函数注释
  //===========================================
  //============= Code Runner =================
  //===========================================
  "javascript.updateImportsOnFileMove.enabled": "never",
  "liveServer.settings.donotShowInfoMsg": true,
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "terminal.integrated.rendererType": "dom", //关闭liveserver提示
  "terminal.integrated.rendererType": "dom",
  "telemetry.enableCrashReporter": false,
  "telemetry.enableTelemetry": false,
  "workbench.settings.enableNaturalLanguageSearch": false,
  // 引用路径设置
  "path-intellisense.mappings": {
    "/@/": "${workspaceRoot}/src"
  },
  "prettier.requireConfig": true,
  "typescript.updateImportsOnFileMove.enabled": "always",
  "workbench.sideBar.location": "left",
  "[javascriptreact]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
@@ -203,8 +177,18 @@
  "[markdown]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}
  },
  "i18n-ally.localesPaths": [
    "src/locales/lang",
  ],
  "i18n-ally.keystyle": "nested",
  "i18n-ally.sortKeys": true,
  "i18n-ally.namespace": true,
  "i18n-ally.pathMatcher":"{locale}/{namespaces}.{ext}",
  "i18n-ally.enabledParsers": [
    "ts"
  ],
  "i18n-ally.sourceLanguage": "zh"
}
CHANGELOG.zh_CN.md
@@ -3,6 +3,7 @@
### ✨ Features
- 还原 antdv 默认 loading,重构 `Loading` 组件,增加`useLoading`和`v-loading`指令。并增加示例
- i18n 支持 vscode `i18n-ally`插件
### 🎫 Chores
src/components/Drawer/src/BasicDrawer.tsx
@@ -29,7 +29,7 @@
    const visibleRef = ref(false);
    const propsRef = ref<Partial<Nullable<DrawerProps>>>(null);
    const { t } = useI18n('component.drawer');
    const { t } = useI18n();
    const getMergeProps = computed(
      (): DrawerProps => {
@@ -228,7 +228,11 @@
            default: () => (
              <>
                <div ref={scrollRef} style={unref(getScrollContentStyle)}>
                  <Loading absolute tip={t('loadingText')} loading={unref(getLoading)} />
                  <Loading
                    absolute
                    tip={t('component.drawer.loadingText')}
                    loading={unref(getLoading)}
                  />
                  {getSlot(slots)}
                </div>
                {renderFooter()}
src/components/Drawer/src/props.ts
@@ -2,7 +2,7 @@
import { useI18n } from '/@/hooks/web/useI18n';
import { propTypes } from '/@/utils/propTypes';
const { t } = useI18n('component.drawer');
const { t } = useI18n();
export const footerProps = {
  confirmLoading: propTypes.bool,
@@ -11,13 +11,13 @@
   */
  showCancelBtn: propTypes.bool.def(true),
  cancelButtonProps: Object as PropType<any>,
  cancelText: propTypes.string.def(t('cancelText')),
  cancelText: propTypes.string.def(t('component.drawer.cancelText')),
  /**
   * @description: Show confirmation button
   */
  showOkBtn: propTypes.bool.def(true),
  okButtonProps: propTypes.any,
  okText: propTypes.string.def(t('okText')),
  okText: propTypes.string.def(t('component.drawer.okText')),
  okType: propTypes.string.def('primary'),
  showFooter: propTypes.bool,
  footerHeight: {
src/components/Excel/src/ExportExcelModel.vue
@@ -1,7 +1,7 @@
<template>
  <BasicModal
    v-bind="$attrs"
    :title="t('exportModalTitle')"
    :title="t('component.excel.exportModalTitle')"
    @ok="handleOk"
    @register="registerModal"
  >
@@ -21,19 +21,19 @@
  import { useI18n } from '/@/hooks/web/useI18n';
  const { t } = useI18n('component.excel');
  const { t } = useI18n();
  const schemas: FormSchema[] = [
    {
      field: 'filename',
      component: 'Input',
      label: t('fileName'),
      label: t('component.excel.fileName'),
      rules: [{ required: true }],
    },
    {
      field: 'bookType',
      component: 'Select',
      label: t('fileType'),
      label: t('component.excel.fileType'),
      defaultValue: 'xlsx',
      rules: [{ required: true }],
      componentProps: {
src/components/Form/src/FormAction.tsx
@@ -9,7 +9,7 @@
import { useI18n } from '/@/hooks/web/useI18n';
import { propTypes } from '/@/utils/propTypes';
const { t } = useI18n('component.form');
const { t } = useI18n();
export default defineComponent({
  name: 'BasicFormAction',
@@ -38,14 +38,14 @@
  setup(props, { slots, emit }) {
    const getResetBtnOptionsRef = computed(() => {
      return {
        text: t('resetButton'),
        text: t('component.form.resetButton'),
        ...props.resetButtonOptions,
      };
    });
    const getSubmitBtnOptionsRef = computed(() => {
      return {
        text: t('submitButton'),
        text: t('component.form.submitButton'),
        // htmlType: 'submit',
        ...props.submitButtonOptions,
      };
@@ -77,7 +77,7 @@
        <Button type="default" class="mr-2" onClick={toggleAdvanced}>
          {() => (
            <>
              {isAdvanced ? t('putAway') : t('unfold')}
              {isAdvanced ? t('component.form.putAway') : t('component.form.unfold')}
              <BasicArrow expand={!isAdvanced} top />
            </>
          )}
src/components/Form/src/FormItem.tsx
@@ -47,7 +47,7 @@
    },
  },
  setup(props, { slots }) {
    const { t } = useI18n('component.form');
    const { t } = useI18n();
    // @ts-ignore
    const itemLabelWidthRef = useItemLabelWidth(toRef(props, 'schema'), toRef(props, 'formProps'));
@@ -175,7 +175,7 @@
      const characterInx = rules.findIndex((val) => val.max);
      if (characterInx !== -1 && !rules[characterInx].validator) {
        rules[characterInx].message =
          rules[characterInx].message || t('maxTip', [rules[characterInx].max]);
          rules[characterInx].message || t('component.form.maxTip', [rules[characterInx].max]);
      }
      return rules;
    }
src/components/Form/src/helper.ts
@@ -1,17 +1,17 @@
import type { ComponentType } from './types/index';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n('component.form');
const { t } = useI18n();
/**
 * @description: 生成placeholder
 */
export function createPlaceholderMessage(component: ComponentType) {
  if (component.includes('Input') || component.includes('Complete')) {
    return t('input');
    return t('component.form.input');
  }
  if (component.includes('Picker')) {
    return t('choose');
    return t('component.form.choose');
  }
  if (
    component.includes('Select') ||
@@ -21,7 +21,7 @@
    component.includes('Switch')
  ) {
    // return `请选择${label}`;
    return t('choose');
    return t('component.form.choose');
  }
  return '';
}
src/components/Menu/src/SearchInput.vue
@@ -1,7 +1,7 @@
<template>
  <section class="menu-search-input" @Click="handleClick" :class="searchClass">
    <a-input-search
      :placeholder="t('search')"
      :placeholder="t('component.menu.search')"
      class="menu-search-input__search"
      allowClear
      @change="handleChange"
@@ -29,7 +29,7 @@
      },
    },
    setup(props, { emit }) {
      const { t } = useI18n('component.menu');
      const { t } = useI18n();
      const [debounceEmitChange] = useDebounce(emitChange, 200);
src/components/Modal/src/props.ts
@@ -3,15 +3,15 @@
import { useI18n } from '/@/hooks/web/useI18n';
import { propTypes } from '/@/utils/propTypes';
const { t } = useI18n('component.modal');
const { t } = useI18n();
export const modalProps = {
  visible: propTypes.bool,
  // open drag
  draggable: propTypes.bool.def(true),
  centered: propTypes.bool,
  cancelText: propTypes.string.def(t('cancelText')),
  okText: propTypes.string.def(t('okText')),
  cancelText: propTypes.string.def(t('component.modal.cancelText')),
  okText: propTypes.string.def(t('component.modal.okText')),
  closeFunc: Function as PropType<() => Promise<boolean>>,
};
src/components/Table/src/components/TableSetting.vue
@@ -4,27 +4,27 @@
    <Tooltip placement="top" v-if="getSetting.redo">
      <template #title>
        <span>{{ t('settingRedo') }}</span>
        <span>{{ t('component.table.settingRedo') }}</span>
      </template>
      <RedoOutlined @click="redo" />
    </Tooltip>
    <Tooltip placement="top" v-if="getSetting.size">
      <template #title>
        <span>{{ t('settingDens') }}</span>
        <span>{{ t('component.table.settingDens') }}</span>
      </template>
      <Dropdown placement="bottomCenter" :trigger="['click']">
        <ColumnHeightOutlined />
        <template #overlay>
          <Menu @click="handleTitleClick" selectable v-model:selectedKeys="selectedKeysRef">
            <MenuItem key="default">
              <span>{{ t('settingDensDefault') }}</span>
              <span>{{ t('component.table.settingDensDefault') }}</span>
            </MenuItem>
            <MenuItem key="middle">
              <span>{{ t('settingDensMiddle') }}</span>
              <span>{{ t('component.table.settingDensMiddle') }}</span>
            </MenuItem>
            <MenuItem key="small">
              <span>{{ t('settingDensSmall') }}</span>
              <span>{{ t('component.table.settingDensSmall') }}</span>
            </MenuItem>
          </Menu>
        </template>
@@ -140,7 +140,7 @@
        defaultCheckList: [],
      });
      const { t } = useI18n('component.table');
      const { t } = useI18n();
      watchEffect(() => {
        const columns = table.getColumns();
src/components/Table/src/hooks/useColumns.ts
@@ -6,7 +6,7 @@
import { useProps } from './useProps';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n('component.table');
const { t } = useI18n();
export function useColumns(
  refProps: ComputedRef<BasicTableProps>,
  getPaginationRef: ComputedRef<false | PaginationProps>
@@ -44,7 +44,7 @@
      columns.unshift({
        flag: 'INDEX',
        width: 50,
        title: t('index'),
        title: t('component.table.index'),
        align: 'center',
        customRender: ({ index }) => {
          const getPagination = unref(getPaginationRef);
src/components/Table/src/hooks/usePagination.tsx
@@ -10,7 +10,7 @@
import { useProps } from './useProps';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n('component.table');
const { t } = useI18n();
export function usePagination(refProps: ComputedRef<BasicTableProps>) {
  const configRef = ref<PaginationProps>({});
  const { propsRef } = useProps(refProps);
@@ -25,7 +25,7 @@
      pageSize: PAGE_SIZE,
      size: 'small',
      defaultPageSize: PAGE_SIZE,
      showTotal: (total) => t('total', { total }),
      showTotal: (total) => t('component.table.total', { total }),
      showSizeChanger: true,
      pageSizeOptions: PAGE_SIZE_OPTIONS,
      itemRender: ({ page, type, originalElement }) => {
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') }}
        {{ t('component.upload.upload') }}
      </a-button>
      <Tooltip placement="bottom" v-if="showPreview">
        <template #title>
          {{ t('uploaded') }}
          {{ t('component.upload.uploaded') }}
          <template v-if="fileListRef.length">{{ fileListRef.length }}</template>
        </template>
        <a-button @click="openPreviewModal">
@@ -46,7 +46,7 @@
    components: { UploadModal, UploadPreviewModal, Icon, Tooltip },
    props: uploadContainerProps,
    setup(props, { emit, attrs }) {
      const { t } = useI18n('component.upload');
      const { t } = useI18n();
      // 上传modal
      const [registerUploadModal, { openModal: openUploadModal }] = useModal();
src/components/Upload/src/UploadModal.vue
@@ -1,8 +1,8 @@
<template>
  <BasicModal
    width="800px"
    :title="t('upload')"
    :okText="t('save')"
    :title="t('component.upload.upload')"
    :okText="t('component.upload.save')"
    v-bind="$attrs"
    @register="register"
    @ok="handleOk"
@@ -31,7 +31,7 @@
        :before-upload="beforeUpload"
        class="upload-modal-toolbar__btn"
      >
        <a-button type="primary"> {{ t('choose') }} </a-button>
        <a-button type="primary"> {{ t('component.upload.choose') }} </a-button>
      </Upload>
    </div>
    <FileList :dataSource="fileListRef" :columns="columns" :actionColumn="actionColumn" />
@@ -64,7 +64,7 @@
    props: basicProps,
    setup(props, { emit }) {
      //   是否正在上传
      const { t } = useI18n('component.upload');
      const { t } = useI18n();
      const isUploadingRef = ref(false);
      const fileListRef = ref<FileItem[]>([]);
@@ -105,10 +105,10 @@
          (item) => item.status === UploadResultStatus.ERROR
        );
        return isUploadingRef.value
          ? t('uploading')
          ? t('component.upload.uploading')
          : someError
          ? t('reUploadFailed')
          : t('startUpload');
          ? t('component.upload.reUploadFailed')
          : t('component.upload.startUpload');
      });
      // 上传前校验
@@ -119,13 +119,13 @@
        // 设置最大值,则判断
        if (maxSize && file.size / 1024 / 1024 >= maxSize) {
          createMessage.error(t('maxSizeMultiple', [maxSize]));
          createMessage.error(t('component.upload.maxSizeMultiple', [maxSize]));
          return false;
        }
        // 设置类型,则判断
        if (accept.length > 0 && !checkFileType(file, accept)) {
          createMessage.error!(t('acceptUpload', [accept.join(',')]));
          createMessage.error!(t('acomponent.upload.cceptUpload', [accept.join(',')]));
          return false;
        }
        const commonItem = {
@@ -206,7 +206,7 @@
      async function handleStartUpload() {
        const { maxNumber } = props;
        if (fileListRef.value.length > maxNumber) {
          return createMessage.warning(t('maxNumber', [maxNumber]));
          return createMessage.warning(t('component.upload.maxNumber', [maxNumber]));
        }
        try {
          isUploadingRef.value = true;
@@ -233,10 +233,10 @@
        const { maxNumber } = props;
        if (fileListRef.value.length > maxNumber) {
          return createMessage.warning(t('maxNumber', [maxNumber]));
          return createMessage.warning(t('component.upload.maxNumber', [maxNumber]));
        }
        if (isUploadingRef.value) {
          return createMessage.warning(t('saveWarn'));
          return createMessage.warning(t('component.upload.saveWarn'));
        }
        const fileList: string[] = [];
@@ -248,7 +248,7 @@
        }
        // 存在一个上传成功的即可保存
        if (fileList.length <= 0) {
          return createMessage.warning(t('saveError'));
          return createMessage.warning(t('component.upload.saveError'));
        }
        fileListRef.value = [];
        closeModal();
@@ -261,7 +261,7 @@
          fileListRef.value = [];
          return true;
        } else {
          createMessage.warning(t('uploadWait'));
          createMessage.warning(t('component.upload.uploadWait'));
          return false;
        }
      }
src/components/Upload/src/UploadPreviewModal.vue
@@ -1,7 +1,7 @@
<template>
  <BasicModal
    width="800px"
    :title="t('preview')"
    :title="t('component.upload.preview')"
    wrapClassName="upload-preview-modal"
    v-bind="$attrs"
    @register="register"
@@ -30,7 +30,7 @@
    props: previewProps,
    setup(props, { emit }) {
      const [register, { closeModal }] = useModalInner();
      const { t } = useI18n('component.upload');
      const { t } = useI18n();
      const fileListRef = ref<PreviewFileItem[]>([]);
      watch(
src/components/Upload/src/data.tsx
@@ -7,14 +7,14 @@
import TableAction from '/@/components/Table/src/components/TableAction';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n('component.upload');
const { t } = useI18n();
// 文件上传列表
export function createTableColumns(): BasicColumn[] {
  return [
    {
      dataIndex: 'thumbUrl',
      title: t('legend'),
      title: t('component.upload.legend'),
      width: 100,
      customRender: ({ record }) => {
        const { thumbUrl, type } = (record as FileItem) || {};
@@ -23,7 +23,7 @@
    },
    {
      dataIndex: 'name',
      title: t('fileName'),
      title: t('component.upload.fileName'),
      align: 'left',
      customRender: ({ text, record }) => {
        const { percent, status: uploadStatus } = (record as FileItem) || {};
@@ -47,7 +47,7 @@
    },
    {
      dataIndex: 'size',
      title: t('fileSize'),
      title: t('component.upload.fileSize'),
      width: 100,
      customRender: ({ text = 0 }) => {
        return text && (text / 1024).toFixed(2) + 'KB';
@@ -60,15 +60,15 @@
    // },
    {
      dataIndex: 'status',
      title: t('fileStatue'),
      title: t('component.upload.fileStatue'),
      width: 100,
      customRender: ({ text }) => {
        if (text === UploadResultStatus.SUCCESS) {
          return <Tag color="green">{() => t('uploadSuccess')}</Tag>;
          return <Tag color="green">{() => t('component.upload.uploadSuccess')}</Tag>;
        } else if (text === UploadResultStatus.ERROR) {
          return <Tag color="red">{() => t('uploadError')}</Tag>;
          return <Tag color="red">{() => t('component.upload.uploadError')}</Tag>;
        } else if (text === UploadResultStatus.UPLOADING) {
          return <Tag color="blue">{() => t('uploading')}</Tag>;
          return <Tag color="blue">{() => t('component.upload.uploading')}</Tag>;
        }
        return text;
@@ -79,20 +79,20 @@
export function createActionColumn(handleRemove: Function, handlePreview: Function): BasicColumn {
  return {
    width: 120,
    title: t('operating'),
    title: t('component.upload.operating'),
    dataIndex: 'action',
    fixed: false,
    customRender: ({ record }) => {
      const actions: ActionItem[] = [
        {
          label: t('del'),
          label: t('component.upload.del'),
          color: 'error',
          onClick: handleRemove.bind(null, record),
        },
      ];
      if (checkImgType(record)) {
        actions.unshift({
          label: t('preview'),
          label: t('component.upload.preview'),
          onClick: handlePreview.bind(null, record),
        });
      }
@@ -105,7 +105,7 @@
  return [
    {
      dataIndex: 'url',
      title: t('legend'),
      title: t('component.upload.legend'),
      width: 100,
      customRender: ({ record }) => {
        const { url, type } = (record as PreviewFileItem) || {};
@@ -116,7 +116,7 @@
    },
    {
      dataIndex: 'name',
      title: t('fileName'),
      title: t('component.upload.fileName'),
      align: 'left',
    },
  ];
@@ -133,7 +133,7 @@
}): BasicColumn {
  return {
    width: 160,
    title: t('operating'),
    title: t('component.upload.operating'),
    dataIndex: 'action',
    fixed: false,
    customRender: ({ record }) => {
@@ -141,18 +141,18 @@
      const actions: ActionItem[] = [
        {
          label: t('del'),
          label: t('component.upload.del'),
          color: 'error',
          onClick: handleRemove.bind(null, record),
        },
        {
          label: t('download'),
          label: t('component.upload.download'),
          onClick: handleDownload.bind(null, record),
        },
      ];
      if (isImgTypeByName(url)) {
        actions.unshift({
          label: t('preview'),
          label: t('component.upload.preview'),
          onClick: handlePreview.bind(null, record),
        });
      }
src/components/Upload/src/useUpload.ts
@@ -1,6 +1,6 @@
import { Ref, unref, computed } from 'vue';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n('component.upload');
const { t } = useI18n();
export function useUploadType({
  acceptRef,
  //   uploadTypeRef,
@@ -38,17 +38,17 @@
    const accept = unref(acceptRef);
    if (accept.length > 0) {
      helpTexts.push(t('accept', [accept.join(',')]));
      helpTexts.push(t('component.upload.accept', [accept.join(',')]));
    }
    const maxSize = unref(maxSizeRef);
    if (maxSize) {
      helpTexts.push(t('maxSize', [maxSize]));
      helpTexts.push(t('component.upload.maxSize', [maxSize]));
    }
    const maxNumber = unref(maxNumberRef);
    if (maxNumber && maxNumber !== Infinity) {
      helpTexts.push(t('maxNumber', [maxNumber]));
      helpTexts.push(t('component.upload.maxNumber', [maxNumber]));
    }
    return helpTexts.join(',');
  });
src/components/Verify/src/ImgRotate.tsx
@@ -30,7 +30,7 @@
      endTime: 0,
      draged: false,
    });
    const { t } = useI18n('component.verify');
    const { t } = useI18n();
    watch(
      () => state.isPassing,
@@ -146,7 +146,9 @@
            />
            {state.showTip && (
              <span class={[`ir-dv-img__tip`, state.isPassing ? 'success' : 'error']}>
                {state.isPassing ? t('time', { time: time.toFixed(1) }) : t('error')}
                {state.isPassing
                  ? t('component.verify.time', { time: time.toFixed(1) })
                  : t('component.verify.error')}
              </span>
            )}
            {!state.showTip && !state.draged && (
src/components/Verify/src/props.ts
@@ -1,7 +1,7 @@
import type { PropType } from 'vue';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n('component.verify');
const { t } = useI18n();
export const basicProps = {
  value: {
    type: Boolean as PropType<boolean>,
@@ -15,11 +15,11 @@
  text: {
    type: [String] as PropType<string>,
    default: t('dragText'),
    default: t('component.verify.dragText'),
  },
  successText: {
    type: [String] as PropType<string>,
    default: t('successText'),
    default: t('component.verify.successText'),
  },
  height: {
    type: [Number, String] as PropType<number | string>,
src/layouts/default/footer/index.tsx
@@ -13,16 +13,16 @@
export default defineComponent({
  name: 'LayoutContent',
  setup() {
    const { t } = useI18n('layout.footer');
    const { t } = useI18n();
    return () => {
      return (
        <Layout.Footer class="layout-footer">
          {() => (
            <>
              <div class="layout-footer__links">
                <a onClick={() => openWindow(SITE_URL)}>{t('onlinePreview')}</a>
                <a onClick={() => openWindow(SITE_URL)}>{t('layout.footer.onlinePreview')}</a>
                <GithubFilled onClick={() => openWindow(GITHUB_URL)} class="github" />
                <a onClick={() => openWindow(DOC_URL)}>{t('onlineDocument')}</a>
                <a onClick={() => openWindow(DOC_URL)}>{t('layout.footer.onlineDocument')}</a>
              </div>
              <div>Copyright &copy;2020 Vben Admin</div>
            </>
src/layouts/default/header/LayoutHeader.tsx
@@ -66,7 +66,7 @@
    const logoWidthRef = ref(200);
    const logoRef = ref<ComponentRef>(null);
    const { refreshPage } = useTabs();
    const { t } = useI18n('layout.header');
    const { t } = useI18n();
    const { getShowTopMenu, getShowHeaderTrigger, getSplit, getTopMenuAlign } = useMenuSetting();
src/layouts/default/header/UserDropdown.tsx
@@ -44,7 +44,7 @@
export default defineComponent({
  name: 'UserDropdown',
  setup() {
    const { t } = useI18n('layout.header');
    const { t } = useI18n();
    const { getShowDoc } = useHeaderSetting();
    const getUserInfo = computed(() => {
@@ -91,12 +91,18 @@
        <Menu onClick={handleMenuClick}>
          {() => (
            <>
              {showDoc && <MenuItem key="doc" text={t('dropdownItemDoc')} icon="gg:loadbar-doc" />}
              {showDoc && (
                <MenuItem
                  key="doc"
                  text={t('layout.header.dropdownItemDoc')}
                  icon="gg:loadbar-doc"
                />
              )}
              {/* @ts-ignore */}
              {showDoc && <Menu.Divider />}
              <MenuItem
                key="loginOut"
                text={t('dropdownItemLoginOut')}
                text={t('layout.header.dropdownItemLoginOut')}
                icon="ant-design:poweroff-outlined"
              />
            </>
src/layouts/default/lock/LockAction.tsx
@@ -15,7 +15,7 @@
export default defineComponent({
  name: 'LockModal',
  setup(_, { attrs }) {
    const { t } = useI18n('layout.header');
    const { t } = useI18n();
    const [register, { closeModal }] = useModalInner();
    const [registerForm, { validateFields, resetFields }] = useForm({
@@ -23,7 +23,7 @@
      schemas: [
        {
          field: 'password',
          label: t('lockScreenPassword'),
          label: t('layout.header.lockScreenPassword'),
          component: 'InputPassword',
          required: true,
        },
@@ -53,7 +53,7 @@
    return () => (
      <BasicModal
        footer={null}
        title={t('lockScreen')}
        title={t('layout.header.lockScreen')}
        {...attrs}
        class={prefixCls}
        onRegister={register}
@@ -69,10 +69,10 @@
            <div class={`${prefixCls}__footer`}>
              <Button type="primary" block class="mt-2" onClick={lock}>
                {() => t('lockScreenBtn')}
                {() => t('layout.header.lockScreenBtn')}
              </Button>
              <Button block class="mt-2" onClick={lock.bind(null, false)}>
                {() => t('notLockScreenPassword')}
                {() => t('layout.header.notLockScreenPassword')}
              </Button>
            </div>
          </div>
src/layouts/default/multitabs/TabContent.tsx
@@ -59,7 +59,7 @@
    },
  },
  setup(props) {
    const { t } = useI18n('layout.multipleTab');
    const { t } = useI18n();
    const { getShowMenu } = useMenuSetting();
    const { getShowHeader } = useHeaderSetting();
    const { getShowQuick } = useMultipleTabSetting();
@@ -76,7 +76,7 @@
    return () => {
      const scaleAction = getScaleAction(
        unref(getIsScale) ? t('putAway') : t('unfold'),
        unref(getIsScale) ? t('layout.multipleTab.putAway') : t('layout.multipleTab.unfold'),
        unref(getIsScale)
      );
      const dropMenuList = unref(getDropMenuList) || [];
src/layouts/default/multitabs/data.ts
@@ -4,7 +4,7 @@
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n('layout.multipleTab');
const { t } = useI18n();
export enum TabContentEnum {
  TAB_TYPE,
@@ -41,40 +41,40 @@
  const REFRESH_PAGE: DropMenu = {
    icon: 'ant-design:reload-outlined',
    event: MenuEventEnum.REFRESH_PAGE,
    text: t('redo'),
    text: t('layout.multipleTab.redo'),
    disabled: false,
  };
  const CLOSE_CURRENT: DropMenu = {
    icon: 'ant-design:close-outlined',
    event: MenuEventEnum.CLOSE_CURRENT,
    text: t('close'),
    text: t('layout.multipleTab.close'),
    disabled: false,
    divider: true,
  };
  const CLOSE_LEFT: DropMenu = {
    icon: 'ant-design:pic-left-outlined',
    event: MenuEventEnum.CLOSE_LEFT,
    text: t('closeLeft'),
    text: t('layout.multipleTab.closeLeft'),
    disabled: false,
    divider: false,
  };
  const CLOSE_RIGHT: DropMenu = {
    icon: 'ant-design:pic-right-outlined',
    event: MenuEventEnum.CLOSE_RIGHT,
    text: t('closeRight'),
    text: t('layout.multipleTab.closeRight'),
    disabled: false,
    divider: true,
  };
  const CLOSE_OTHER: DropMenu = {
    icon: 'ant-design:pic-center-outlined',
    event: MenuEventEnum.CLOSE_OTHER,
    text: t('closeOther'),
    text: t('layout.multipleTab.closeOther'),
    disabled: false,
  };
  const CLOSE_ALL: DropMenu = {
    icon: 'ant-design:line-outlined',
    event: MenuEventEnum.CLOSE_ALL,
    text: t('closeAll'),
    text: t('layout.multipleTab.closeAll'),
    disabled: false,
  };
  return [REFRESH_PAGE, CLOSE_CURRENT, CLOSE_LEFT, CLOSE_RIGHT, CLOSE_OTHER, CLOSE_ALL];
src/layouts/default/setting/SettingDrawer.tsx
@@ -56,7 +56,7 @@
}
const { createSuccessModal, createMessage } = useMessage();
const { t } = useI18n('layout.setting');
const { t } = useI18n();
/**
 * Menu type Picker comp
@@ -122,8 +122,8 @@
    const { isSuccessRef } = useCopyToClipboard(JSON.stringify(unref(getRootSetting), null, 2));
    unref(isSuccessRef) &&
      createSuccessModal({
        title: t('operatingTitle'),
        content: t('operatingContent'),
        title: t('layout.setting.operatingTitle'),
        content: t('layout.setting.operatingContent'),
      });
  }
  function handleResetSetting() {
@@ -133,7 +133,7 @@
      // updateTheme(themeColor);
      updateColorWeak(colorWeak);
      updateGrayMode(grayMode);
      createMessage.success(t('resetSuccess'));
      createMessage.success(t('layout.setting.resetSuccess'));
    } catch (error) {
      createMessage.error(error);
    }
@@ -151,7 +151,7 @@
        {() => (
          <>
            <CopyOutlined class="mr-2" />
            {t('copyBtn')}
            {t('layout.setting.copyBtn')}
          </>
        )}
      </Button>
@@ -159,7 +159,7 @@
        {() => (
          <>
            <RedoOutlined class="mr-2" />
            {t('resetBtn')}
            {t('layout.setting.resetBtn')}
          </>
        )}
      </Button>
@@ -167,7 +167,7 @@
        {() => (
          <>
            <RedoOutlined class="mr-2" />
            {t('clearBtn')}
            {t('layout.setting.clearBtn')}
          </>
        )}
      </Button>
@@ -226,7 +226,7 @@
      return (
        <>
          <MenuTypePicker />
          {renderSwitchItem(t('splitMenu'), {
          {renderSwitchItem(t('layout.setting.splitMenu'), {
            handler: (e) => {
              baseHandler(HandlerEnum.MENU_SPLIT, e);
            },
@@ -240,7 +240,7 @@
    function renderTheme() {
      return (
        <>
          <Divider>{() => t('headerTheme')}</Divider>
          <Divider>{() => t('layout.setting.headerTheme')}</Divider>
          <ThemePicker
            colorList={HEADER_PRESET_BG_COLOR_LIST}
            def={unref(getHeaderBgColor)}
@@ -248,7 +248,7 @@
              baseHandler(HandlerEnum.HEADER_THEME, e);
            }}
          />
          <Divider>{() => t('sidebarTheme')}</Divider>
          <Divider>{() => t('layout.setting.sidebarTheme')}</Divider>
          <ThemePicker
            colorList={SIDE_BAR_BG_COLOR_LIST}
            def={unref(getMenuBgColor)}
@@ -265,56 +265,56 @@
     */
    function renderFeatures() {
      return [
        renderSwitchItem(t('menuDrag'), {
        renderSwitchItem(t('layout.setting.menuDrag'), {
          handler: (e) => {
            baseHandler(HandlerEnum.MENU_HAS_DRAG, e);
          },
          def: unref(getCanDrag),
          disabled: !unref(getShowMenuRef),
        }),
        renderSwitchItem(t('menuSearch'), {
        renderSwitchItem(t('layout.setting.menuSearch'), {
          handler: (e) => {
            baseHandler(HandlerEnum.MENU_SHOW_SEARCH, e);
          },
          def: unref(getShowSearch),
          disabled: !unref(getShowMenuRef),
        }),
        renderSwitchItem(t('menuAccordion'), {
        renderSwitchItem(t('layout.setting.menuAccordion'), {
          handler: (e) => {
            baseHandler(HandlerEnum.MENU_ACCORDION, e);
          },
          def: unref(getAccordion),
          disabled: !unref(getShowMenuRef),
        }),
        renderSwitchItem(t('menuCollapse'), {
        renderSwitchItem(t('layout.setting.menuCollapse'), {
          handler: (e) => {
            baseHandler(HandlerEnum.MENU_COLLAPSED, e);
          },
          def: unref(getCollapsed),
          disabled: !unref(getShowMenuRef),
        }),
        renderSwitchItem(t('collapseMenuDisplayName'), {
        renderSwitchItem(t('layout.setting.collapseMenuDisplayName'), {
          handler: (e) => {
            baseHandler(HandlerEnum.MENU_COLLAPSED_SHOW_TITLE, e);
          },
          def: unref(getCollapsedShowTitle),
          disabled: !unref(getShowMenuRef) || !unref(getCollapsed),
        }),
        renderSwitchItem(t('fixedHeader'), {
        renderSwitchItem(t('layout.setting.fixedHeader'), {
          handler: (e) => {
            baseHandler(HandlerEnum.HEADER_FIXED, e);
          },
          def: unref(getHeaderFixed),
          disabled: !unref(getShowHeader),
        }),
        renderSwitchItem(t('fixedSideBar'), {
        renderSwitchItem(t('layout.setting.fixedSideBar'), {
          handler: (e) => {
            baseHandler(HandlerEnum.MENU_FIXED, e);
          },
          def: unref(getMenuFixed),
          disabled: !unref(getShowMenuRef),
        }),
        renderSelectItem(t('topMenuLayout'), {
        renderSelectItem(t('layout.setting.topMenuLayout'), {
          handler: (e) => {
            baseHandler(HandlerEnum.MENU_TOP_ALIGN, e);
          },
@@ -322,7 +322,7 @@
          options: topMenuAlignOptions,
          disabled: !unref(getShowHeader) || (!unref(getIsTopMenu) && !unref(getSplit)),
        }),
        renderSelectItem(t('menuCollapseButton'), {
        renderSelectItem(t('layout.setting.menuCollapseButton'), {
          handler: (e) => {
            baseHandler(HandlerEnum.MENU_TRIGGER, e);
          },
@@ -331,7 +331,7 @@
          options: menuTriggerOptions,
        }),
        renderSelectItem(t('contentMode'), {
        renderSelectItem(t('layout.setting.contentMode'), {
          handler: (e) => {
            baseHandler(HandlerEnum.CONTENT_MODE, e);
          },
@@ -339,7 +339,7 @@
          options: contentModeOptions,
        }),
        <div class={`setting-drawer__cell-item`}>
          <span>{t('autoScreenLock')}</span>
          <span>{t('layout.setting.autoScreenLock')}</span>
          <InputNumber
            style="width:126px"
            size="small"
@@ -350,14 +350,14 @@
            defaultValue={appStore.getProjectConfig.lockTime}
            formatter={(value: string) => {
              if (parseInt(value) === 0) {
                return `0(${t('notAutoScreenLock')})`;
                return `0(${t('layout.setting.notAutoScreenLock')})`;
              }
              return `${value}${t('minute')}`;
              return `${value}${t('layout.setting.minute')}`;
            }}
          />
        </div>,
        <div class={`setting-drawer__cell-item`}>
          <span>{t('expandedMenuWidth')}</span>
          <span>{t('layout.setting.expandedMenuWidth')}</span>
          <InputNumber
            style="width:126px"
            size="small"
@@ -377,27 +377,27 @@
    function renderContent() {
      return [
        renderSwitchItem(t('breadcrumb'), {
        renderSwitchItem(t('layout.setting.breadcrumb'), {
          handler: (e) => {
            baseHandler(HandlerEnum.SHOW_BREADCRUMB, e);
          },
          def: unref(getShowBreadCrumb),
          disabled: !unref(getShowHeader),
        }),
        renderSwitchItem(t('breadcrumbIcon'), {
        renderSwitchItem(t('layout.setting.breadcrumbIcon'), {
          handler: (e) => {
            baseHandler(HandlerEnum.SHOW_BREADCRUMB_ICON, e);
          },
          def: unref(getShowBreadCrumbIcon),
          disabled: !unref(getShowHeader),
        }),
        renderSwitchItem(t('tabs'), {
        renderSwitchItem(t('layout.setting.tabs'), {
          handler: (e) => {
            baseHandler(HandlerEnum.TABS_SHOW, e);
          },
          def: unref(getShowMultipleTab),
        }),
        renderSwitchItem(t('tabsQuickBtn'), {
        renderSwitchItem(t('layout.setting.tabsQuickBtn'), {
          handler: (e) => {
            baseHandler(HandlerEnum.TABS_SHOW_QUICK, e);
          },
@@ -405,14 +405,14 @@
          disabled: !unref(getShowMultipleTab),
        }),
        renderSwitchItem(t('sidebar'), {
        renderSwitchItem(t('layout.setting.sidebar'), {
          handler: (e) => {
            baseHandler(HandlerEnum.MENU_SHOW_SIDEBAR, e);
          },
          def: unref(getShowMenu),
          disabled: unref(getIsHorizontal),
        }),
        renderSwitchItem(t('header'), {
        renderSwitchItem(t('layout.setting.header'), {
          handler: (e) => {
            baseHandler(HandlerEnum.HEADER_SHOW, e);
          },
@@ -424,25 +424,25 @@
          },
          def: unref(getShowLogo),
        }),
        renderSwitchItem(t('footer'), {
        renderSwitchItem(t('layout.setting.footer'), {
          handler: (e) => {
            baseHandler(HandlerEnum.SHOW_FOOTER, e);
          },
          def: unref(getShowFooter),
        }),
        renderSwitchItem(t('fullContent'), {
        renderSwitchItem(t('layout.setting.fullContent'), {
          handler: (e) => {
            baseHandler(HandlerEnum.FULL_CONTENT, e);
          },
          def: unref(getFullContent),
        }),
        renderSwitchItem(t('grayMode'), {
        renderSwitchItem(t('layout.setting.grayMode'), {
          handler: (e) => {
            baseHandler(HandlerEnum.GRAY_MODE, e);
          },
          def: unref(getGrayMode),
        }),
        renderSwitchItem(t('colorWeak'), {
        renderSwitchItem(t('layout.setting.colorWeak'), {
          handler: (e) => {
            baseHandler(HandlerEnum.COLOR_WEAK, e);
          },
@@ -454,13 +454,13 @@
    function renderTransition() {
      return (
        <>
          {renderSwitchItem(t('progress'), {
          {renderSwitchItem(t('layout.setting.progress'), {
            handler: (e) => {
              baseHandler(HandlerEnum.OPEN_PROGRESS, e);
            },
            def: unref(getOpenNProgress),
          })}
          {renderSwitchItem(t('switchLoading'), {
          {renderSwitchItem(t('layout.setting.switchLoading'), {
            handler: (e) => {
              baseHandler(HandlerEnum.OPEN_PAGE_LOADING, e);
            },
@@ -468,14 +468,14 @@
            disabled: !unref(getEnableTransition),
          })}
          {renderSwitchItem(t('switchAnimation'), {
          {renderSwitchItem(t('layout.setting.switchAnimation'), {
            handler: (e) => {
              baseHandler(HandlerEnum.OPEN_ROUTE_TRANSITION, e);
            },
            def: unref(getEnableTransition),
          })}
          {renderSelectItem(t('animationType'), {
          {renderSelectItem(t('layout.setting.animationType'), {
            handler: (e) => {
              baseHandler(HandlerEnum.ROUTER_TRANSITION, e);
            },
@@ -519,26 +519,31 @@
            onChange={(e: any) => {
              handler && handler(e);
            }}
            checkedChildren={t('on')}
            unCheckedChildren={t('off')}
            checkedChildren={t('layout.setting.on')}
            unCheckedChildren={t('layout.setting.off')}
          />
        </div>
      );
    }
    return () => (
      <BasicDrawer {...attrs} title={t('drawerTitle')} width={330} wrapClassName="setting-drawer">
      <BasicDrawer
        {...attrs}
        title={t('layout.setting.drawerTitle')}
        width={330}
        wrapClassName="setting-drawer"
      >
        {{
          default: () => (
            <>
              <Divider>{() => t('navMode')}</Divider>
              <Divider>{() => t('layout.setting.navMode')}</Divider>
              {renderSidebar()}
              {renderTheme()}
              <Divider>{() => t('interfaceFunction')}</Divider>
              <Divider>{() => t('layout.setting.interfaceFunction')}</Divider>
              {renderFeatures()}
              <Divider>{() => t('interfaceDisplay')}</Divider>
              <Divider>{() => t('layout.setting.interfaceDisplay')}</Divider>
              {renderContent()}
              <Divider>{() => t('animation')}</Divider>
              <Divider>{() => t('layout.setting.animation')}</Divider>
              {renderTransition()}
              <Divider />
              <FooterButton />
src/layouts/default/setting/enum.ts
@@ -6,7 +6,7 @@
import menuTopImg from '/@/assets/images/layout/menu-top.svg';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n('layout.setting');
const { t } = useI18n();
export enum HandlerEnum {
  CHANGE_LAYOUT,
@@ -51,41 +51,41 @@
export const contentModeOptions = [
  {
    value: ContentEnum.FULL,
    label: t('contentModeFull'),
    label: t('layout.setting.contentModeFull'),
  },
  {
    value: ContentEnum.FIXED,
    label: t('contentModeFixed'),
    label: t('layout.setting.contentModeFixed'),
  },
];
export const topMenuAlignOptions = [
  {
    value: TopMenuAlignEnum.CENTER,
    label: t('topMenuAlignRight'),
    label: t('layout.setting.topMenuAlignRight'),
  },
  {
    value: TopMenuAlignEnum.START,
    label: t('topMenuAlignLeft'),
    label: t('layout.setting.topMenuAlignLeft'),
  },
  {
    value: TopMenuAlignEnum.END,
    label: t('topMenuAlignCenter'),
    label: t('layout.setting.topMenuAlignCenter'),
  },
];
export const menuTriggerOptions = [
  {
    value: TriggerEnum.NONE,
    label: t('menuTriggerNone'),
    label: t('layout.setting.menuTriggerNone'),
  },
  {
    value: TriggerEnum.FOOTER,
    label: t('menuTriggerBottom'),
    label: t('layout.setting.menuTriggerBottom'),
  },
  {
    value: TriggerEnum.HEADER,
    label: t('menuTriggerTop'),
    label: t('layout.setting.menuTriggerTop'),
  },
];
@@ -104,20 +104,20 @@
export const menuTypeList = [
  {
    title: t('menuTypeSidebar'),
    title: t('layout.setting.menuTypeSidebar'),
    mode: MenuModeEnum.INLINE,
    type: MenuTypeEnum.SIDEBAR,
    src: sidebarImg,
  },
  {
    title: t('menuTypeMix'),
    title: t('layout.setting.menuTypeMix'),
    mode: MenuModeEnum.INLINE,
    type: MenuTypeEnum.MIX,
    src: mixImg,
  },
  {
    title: t('menuTypeTopMenu'),
    title: t('layout.setting.menuTypeTopMenu'),
    mode: MenuModeEnum.HORIZONTAL,
    type: MenuTypeEnum.TOP_MENU,
    src: menuTopImg,
src/store/modules/permission.ts
@@ -22,7 +22,7 @@
// import { warn } from '/@/utils/log';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n('sys.app');
const { t } = useI18n();
const { createMessage } = useMessage();
const NAME = 'permission';
@@ -104,7 +104,7 @@
    } else if (permissionMode === PermissionModeEnum.BACK) {
      const messageKey = 'loadMenu';
      createMessage.loading({
        content: t('menuLoading'),
        content: t('sys.app.menuLoading'),
        key: messageKey,
        duration: 1,
      });
src/store/modules/user.ts
@@ -143,11 +143,11 @@
  @Action
  async confirmLoginOut() {
    const { createConfirm } = useMessage();
    const { t } = useI18n('sys.app');
    const { t } = useI18n();
    createConfirm({
      iconType: 'warning',
      title: t('loginOutTip'),
      content: t('loginOutMessage'),
      title: t('sys.app.loginOutTip'),
      content: t('sys.app.loginOutMessage'),
      onOk: async () => {
        await this.loginOut(true);
      },
src/utils/http/axios/checkStatus.ts
@@ -5,7 +5,7 @@
const error = createMessage.error!;
export function checkStatus(status: number, msg: string): void {
  const { t } = useI18n('sys.api');
  const { t } = useI18n();
  switch (status) {
    case 400:
      error(`${msg}`);
@@ -14,39 +14,39 @@
    // 未登录则跳转登录页面,并携带当前页面的路径
    // 在登录成功后返回当前页面,这一步需要在登录页操作。
    case 401:
      error(t('errMsg401'));
      error(t('sys.api.errMsg401'));
      userStore.loginOut(true);
      break;
    case 403:
      error(t('errMsg403'));
      error(t('sys.api.errMsg403'));
      break;
    // 404请求不存在
    case 404:
      error(t('errMsg404'));
      error(t('sys.api.errMsg404'));
      break;
    case 405:
      error(t('errMsg405'));
      error(t('sys.api.errMsg405'));
      break;
    case 408:
      error(t('errMsg408'));
      error(t('sys.api.errMsg408'));
      break;
    case 500:
      error(t('errMsg500'));
      error(t('sys.api.errMsg500'));
      break;
    case 501:
      error(t('errMsg501'));
      error(t('sys.api.errMsg501'));
      break;
    case 502:
      error(t('errMsg502'));
      error(t('sys.api.errMsg502'));
      break;
    case 503:
      error(t('errMsg503'));
      error(t('sys.api.errMsg503'));
      break;
    case 504:
      error(t('errMsg504'));
      error(t('sys.api.errMsg504'));
      break;
    case 505:
      error(t('errMsg505'));
      error(t('sys.api.errMsg505'));
      break;
    default:
  }
src/utils/http/axios/index.ts
@@ -34,7 +34,7 @@
   * @description: 处理请求数据
   */
  transformRequestData: (res: AxiosResponse<Result>, options: RequestOptions) => {
    const { t } = useI18n('sys.api');
    const { t } = useI18n();
    const { isTransformRequestResult } = options;
    // 不进行任何处理,直接返回
    // 用于页面代码可能需要直接获取code,data,message这些信息时开启
@@ -57,7 +57,7 @@
      if (message) {
        // errorMessageMode=‘modal’的时候会显示modal错误弹窗,而不是消息提示,用于一些比较重要的错误
        if (options.errorMessageMode === 'modal') {
          createErrorModal({ title: t('errorTip'), content: message });
          createErrorModal({ title: t('sys.api.errorTip'), content: message });
        } else {
          createMessage.error(message);
        }
@@ -76,7 +76,7 @@
        createMessage.error(data.message);
        Promise.reject(new Error(message));
      } else {
        const msg = t('errorMessage');
        const msg = t('sys.api.errorMessage');
        createMessage.error(msg);
        Promise.reject(new Error(msg));
      }
@@ -84,9 +84,9 @@
    }
    // 登录超时
    if (code === ResultEnum.TIMEOUT) {
      const timeoutMsg = t('timeoutMessage');
      const timeoutMsg = t('sys.api.timeoutMessage');
      createErrorModal({
        title: t('operationFailed'),
        title: t('sys.api.operationFailed'),
        content: timeoutMsg,
      });
      Promise.reject(new Error(timeoutMsg));
@@ -154,7 +154,7 @@
   * @description: 响应错误处理
   */
  responseInterceptorsCatch: (error: any) => {
    const { t } = useI18n('sys.api');
    const { t } = useI18n();
    errorStore.setupErrorHandle(error);
    const { response, code, message } = error || {};
    const msg: string =
@@ -162,12 +162,12 @@
    const err: string = error.toString();
    try {
      if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
        createMessage.error(t('apiTimeoutMessage'));
        createMessage.error(t('sys.api.apiTimeoutMessage'));
      }
      if (err && err.includes('Network Error')) {
        createErrorModal({
          title: t('networkException'),
          content: t('networkExceptionMsg'),
          title: t('sys.api.networkException'),
          content: t('sys.api.networkExceptionMsg'),
        });
      }
    } catch (error) {
src/views/sys/error-log/DetailModal.vue
@@ -1,5 +1,5 @@
<template>
  <BasicModal :width="800" :title="t('tableActionDesc')" v-bind="$attrs">
  <BasicModal :width="800" :title="t('sys.errorLog.tableActionDesc')" v-bind="$attrs">
    <Description :data="info" @register="register" />
  </BasicModal>
</template>
@@ -23,7 +23,7 @@
      },
    },
    setup() {
      const { t } = useI18n('sys.errorLog');
      const { t } = useI18n();
      const [register] = useDescription({
        column: 2,
        schema: getDescSchema(),
src/views/sys/error-log/data.tsx
@@ -3,13 +3,13 @@
import { ErrorTypeEnum } from '/@/enums/exceptionEnum';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n('sys.errorLog');
const { t } = useI18n();
export function getColumns(): BasicColumn[] {
  return [
    {
      dataIndex: 'type',
      title: t('tableColumnType'),
      title: t('sys.errorLog.tableColumnType'),
      width: 80,
      customRender: ({ text }) => {
        const color =
@@ -32,12 +32,12 @@
    },
    {
      dataIndex: 'time',
      title: t('tableColumnDate'),
      title: t('sys.errorLog.tableColumnDate'),
      width: 160,
    },
    {
      dataIndex: 'file',
      title: t('tableColumnFile'),
      title: t('sys.errorLog.tableColumnFile'),
      width: 200,
    },
    {
@@ -47,12 +47,12 @@
    },
    {
      dataIndex: 'message',
      title: t('tableColumnMsg'),
      title: t('sys.errorLog.tableColumnMsg'),
      width: 300,
    },
    {
      dataIndex: 'stack',
      title: t('tableColumnStackMsg'),
      title: t('sys.errorLog.tableColumnStackMsg'),
      width: 300,
    },
  ];
src/views/sys/error-log/index.vue
@@ -53,7 +53,7 @@
      const rowInfoRef = ref<ErrorInfo>();
      const imgListRef = ref<string[]>([]);
      const { t } = useI18n('sys.errorLog');
      const { t } = useI18n();
      const [register, { setTableData }] = useTable({
        title: t('sys.errorLog.tableTitle'),
@@ -80,7 +80,7 @@
      );
      const { createMessage } = useMessage();
      if (isDevMode()) {
        createMessage.info(t('enableMessage'));
        createMessage.info(t('sys.errorLog.enableMessage'));
      }
      // 查看详情
      function handleDetail(row: ErrorInfo) {
src/views/sys/exception/Exception.tsx
@@ -53,7 +53,7 @@
    const { query } = useRoute();
    const go = useGo();
    const redo = useRedo();
    const { t } = useI18n('sys.exception');
    const { t } = useI18n();
    const getStatus = computed(() => {
      const { status: routeStatus } = query;
@@ -67,13 +67,13 @@
      }
    );
    const backLoginI18n = t('backLogin');
    const backHomeI18n = t('backHome');
    const backLoginI18n = t('sys.exception.backLogin');
    const backHomeI18n = t('sys.exception.backHome');
    unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_ACCESS, {
      title: '403',
      status: `${ExceptionEnum.PAGE_NOT_ACCESS}`,
      subTitle: t('subTitle403'),
      subTitle: t('sys.exception.subTitle403'),
      btnText: props.full ? backLoginI18n : backHomeI18n,
      handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()),
    });
@@ -81,7 +81,7 @@
    unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_FOUND, {
      title: '404',
      status: `${ExceptionEnum.PAGE_NOT_FOUND}`,
      subTitle: t('subTitle404'),
      subTitle: t('sys.exception.subTitle404'),
      btnText: props.full ? backLoginI18n : backHomeI18n,
      handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()),
    });
@@ -89,22 +89,22 @@
    unref(statusMapRef).set(ExceptionEnum.ERROR, {
      title: '500',
      status: `${ExceptionEnum.ERROR}`,
      subTitle: t('subTitle500'),
      subTitle: t('sys.exception.subTitle500'),
      btnText: backHomeI18n,
      handler: () => go(),
    });
    unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_DATA, {
      title: t('noDataTitle'),
      title: t('sys.exception.noDataTitle'),
      subTitle: '',
      btnText: t('redo'),
      btnText: t('sys.exception.redo'),
      handler: () => redo(),
      icon: notDataImg,
    });
    unref(statusMapRef).set(ExceptionEnum.NET_WORK_ERROR, {
      title: t('networkErrorTitle'),
      subTitle: t('networkErrorSubTitle'),
      title: t('sys.exception.networkErrorTitle'),
      subTitle: t('sys.exception.networkErrorSubTitle'),
      btnText: 'Refresh',
      handler: () => redo(),
      icon: netWorkImg,
src/views/sys/lock/index.vue
@@ -36,7 +36,7 @@
      const loadingRef = ref(false);
      const errMsgRef = ref(false);
      const { t } = useI18n('sys.lock');
      const { t } = useI18n();
      const [register, { validateFields }] = useForm({
        showActionButtonGroup: false,
        schemas: [
@@ -46,7 +46,7 @@
            component: 'InputPassword',
            componentProps: {
              style: { width: '100%' },
              placeholder: t('placeholder'),
              placeholder: t('sys.lock.placeholder'),
            },
            rules: [{ required: true }],
          },
src/views/sys/login/Login.vue
@@ -90,7 +90,7 @@
      const globSetting = useGlobSetting();
      const { locale } = useProjectSetting();
      const { notification } = useMessage();
      const { t } = useI18n('sys.login');
      const { t } = useI18n();
      // const openLoginVerifyRef = computed(() => appStore.getProjectConfig.openLoginVerify);
@@ -104,8 +104,10 @@
      });
      const formRules = reactive({
        account: [{ required: true, message: t('accountPlaceholder'), trigger: 'blur' }],
        password: [{ required: true, message: t('passwordPlaceholder'), trigger: 'blur' }],
        account: [{ required: true, message: t('sys.login.accountPlaceholder'), trigger: 'blur' }],
        password: [
          { required: true, message: t('sys.login.passwordPlaceholder'), trigger: 'blur' },
        ],
        // verify: unref(openLoginVerifyRef) ? [{ required: true, message: '请通过验证码校验' }] : [],
      });
@@ -130,8 +132,8 @@
          );
          if (userInfo) {
            notification.success({
              message: t('loginSuccessTitle'),
              description: `${t('loginSuccessDesc')}: ${userInfo.realName}`,
              message: t('sys.login.loginSuccessTitle'),
              description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realName}`,
              duration: 3,
            });
          }