Commit 737b1b190cf288d7ab7ad7e9bd21acb9da16cc6c

Authored by vben
1 parent b49950a3

wip: multi-language support

Showing 59 changed files with 512 additions and 272 deletions
CHANGELOG.zh_CN.md
  1 +## Wip
  2 +
  3 +### 🎫 Chores
  4 +
  5 +- 移除 messageSetting 配置
  6 +
1 ## 2.0.0-rc.11 (2020-11-18) 7 ## 2.0.0-rc.11 (2020-11-18)
2 8
3 ### ✨ Features 9 ### ✨ Features
package.json
@@ -26,6 +26,7 @@ @@ -26,6 +26,7 @@
26 "ant-design-vue": "2.0.0-beta.15", 26 "ant-design-vue": "2.0.0-beta.15",
27 "apexcharts": "3.22.0", 27 "apexcharts": "3.22.0",
28 "axios": "^0.21.0", 28 "axios": "^0.21.0",
  29 + "crypto-es": "^1.2.6",
29 "echarts": "^4.9.0", 30 "echarts": "^4.9.0",
30 "lodash-es": "^4.17.15", 31 "lodash-es": "^4.17.15",
31 "mockjs": "^1.1.0", 32 "mockjs": "^1.1.0",
src/App.vue
1 <template> 1 <template>
2 - <ConfigProvider v-bind="lockEvent" :locale="zhCN" :transform-cell-text="transformCellText"> 2 + <ConfigProvider
  3 + v-bind="lockEvent"
  4 + :locale="antConfigLocale"
  5 + :transform-cell-text="transformCellText"
  6 + >
3 <router-view /> 7 <router-view />
4 </ConfigProvider> 8 </ConfigProvider>
5 </template> 9 </template>
@@ -7,16 +11,12 @@ @@ -7,16 +11,12 @@
7 <script lang="ts"> 11 <script lang="ts">
8 import { defineComponent } from 'vue'; 12 import { defineComponent } from 'vue';
9 import { ConfigProvider } from 'ant-design-vue'; 13 import { ConfigProvider } from 'ant-design-vue';
10 - import { createBreakpointListen } from '/@/hooks/event/useBreakpoint';  
11 -  
12 - import zhCN from 'ant-design-vue/es/locale/zh_CN';  
13 - import moment from 'moment';  
14 - import 'moment/dist/locale/zh-cn';  
15 14
16 import { getConfigProvider, initAppConfigStore } from '/@/setup/App'; 15 import { getConfigProvider, initAppConfigStore } from '/@/setup/App';
17 - import { useLockPage } from '/@/hooks/web/useLockPage';  
18 16
19 - moment.locale('zh-cn'); 17 + import { useLockPage } from '/@/hooks/web/useLockPage';
  18 + import { useLocale } from '/@/hooks/web/useLocale';
  19 + import { createBreakpointListen } from '/@/hooks/event/useBreakpoint';
20 20
21 export default defineComponent({ 21 export default defineComponent({
22 name: 'App', 22 name: 'App',
@@ -34,9 +34,12 @@ @@ -34,9 +34,12 @@
34 // Create a lock screen monitor 34 // Create a lock screen monitor
35 const lockEvent = useLockPage(); 35 const lockEvent = useLockPage();
36 36
  37 + // support Multi-language
  38 + const { antConfigLocale } = useLocale();
  39 +
37 return { 40 return {
38 transformCellText, 41 transformCellText,
39 - zhCN, 42 + antConfigLocale,
40 lockEvent, 43 lockEvent,
41 }; 44 };
42 }, 45 },
src/components/Application/index.ts 0 → 100644
  1 +import AppLocalPicker from './src/AppLocalPicker.vue';
  2 +
  3 +export { AppLocalPicker };
src/components/Application/src/AppLocalPicker.vue 0 → 100644
  1 +<template>
  2 + <Dropdown
  3 + :trigger="['click']"
  4 + :dropMenuList="localeList"
  5 + :selectedKeys="selectedKeys"
  6 + @menuEvent="handleMenuEvent"
  7 + >
  8 + <GlobalOutlined class="app-locale" />
  9 + </Dropdown>
  10 +</template>
  11 +<script lang="ts">
  12 + import { defineComponent, ref, watchEffect, unref } from 'vue';
  13 +
  14 + import { Dropdown, DropMenu } from '/@/components/Dropdown';
  15 + import { GlobalOutlined } from '@ant-design/icons-vue';
  16 +
  17 + import { useLocale } from '/@/hooks/web/useLocale';
  18 + import { useLocaleSetting } from '/@/settings/use/useLocaleSetting';
  19 +
  20 + import { LocaleType } from '/@/locales/types';
  21 +
  22 + export default defineComponent({
  23 + name: 'AppLocalPicker',
  24 + components: { GlobalOutlined, Dropdown },
  25 + setup() {
  26 + const { localeList } = useLocaleSetting();
  27 + const selectedKeys = ref<string[]>([]);
  28 +
  29 + const { changeLocale, getLang } = useLocale();
  30 +
  31 + watchEffect(() => {
  32 + selectedKeys.value = [unref(getLang)];
  33 + });
  34 +
  35 + function toggleLocale(lang: LocaleType | string) {
  36 + changeLocale(lang as LocaleType);
  37 + selectedKeys.value = [lang as string];
  38 + }
  39 +
  40 + function handleMenuEvent(menu: DropMenu) {
  41 + toggleLocale(menu.event as string);
  42 + }
  43 +
  44 + return { localeList, handleMenuEvent, selectedKeys };
  45 + },
  46 + });
  47 +</script>
  48 +
  49 +<style lang="less" scoped>
  50 + .app-locale {
  51 + cursor: pointer;
  52 + }
  53 +</style>
src/components/Dropdown/index.ts
1 -export { default as Dropdown } from './Dropdown';  
2 -export * from './types'; 1 +export { default as Dropdown } from './src/Dropdown';
  2 +export * from './src/types';
src/components/Dropdown/Dropdown.tsx renamed to src/components/Dropdown/src/Dropdown.tsx
1 import { defineComponent, computed, unref } from 'vue'; 1 import { defineComponent, computed, unref } from 'vue';
2 -import { Dropdown, Menu } from 'ant-design-vue'; 2 +import { Dropdown, Menu, Divider } from 'ant-design-vue';
3 3
4 import Icon from '/@/components/Icon/index'; 4 import Icon from '/@/components/Icon/index';
5 5
6 import { basicDropdownProps } from './props'; 6 import { basicDropdownProps } from './props';
7 import { getSlot } from '/@/utils/helper/tsxHelper'; 7 import { getSlot } from '/@/utils/helper/tsxHelper';
  8 +import { Trigger } from './types';
8 9
9 export default defineComponent({ 10 export default defineComponent({
10 name: 'Dropdown', 11 name: 'Dropdown',
11 props: basicDropdownProps, 12 props: basicDropdownProps,
  13 + emits: ['menuEvent'],
12 setup(props, { slots, emit, attrs }) { 14 setup(props, { slots, emit, attrs }) {
13 const getMenuList = computed(() => props.dropMenuList); 15 const getMenuList = computed(() => props.dropMenuList);
14 16
15 function handleClickMenu({ key }: any) { 17 function handleClickMenu({ key }: any) {
16 - const menu = unref(getMenuList)[key]; 18 + const menu = unref(getMenuList).find((item) => item.event === key);
17 emit('menuEvent', menu); 19 emit('menuEvent', menu);
18 } 20 }
19 21
20 function renderMenus() { 22 function renderMenus() {
21 return ( 23 return (
22 - <Menu onClick={handleClickMenu}> 24 + <Menu onClick={handleClickMenu} selectedKeys={props.selectedKeys}>
23 {() => ( 25 {() => (
24 <> 26 <>
25 {unref(getMenuList).map((item, index) => { 27 {unref(getMenuList).map((item, index) => {
26 - const { disabled, icon, text, divider } = item;  
27 - 28 + const { disabled, icon, text, divider, event } = item;
28 return [ 29 return [
29 - <Menu.Item key={`${index}`} disabled={disabled}> 30 + <Menu.Item key={`${event}`} disabled={disabled}>
30 {() => ( 31 {() => (
31 <> 32 <>
32 {icon && <Icon icon={icon} />} 33 {icon && <Icon icon={icon} />}
@@ -34,8 +35,7 @@ export default defineComponent({ @@ -34,8 +35,7 @@ export default defineComponent({
34 </> 35 </>
35 )} 36 )}
36 </Menu.Item>, 37 </Menu.Item>,
37 - // @ts-ignore  
38 - divider && <Menu.Divider key={`d-${index}`} />, 38 + divider && <Divider key={`d-${index}`} />,
39 ]; 39 ];
40 })} 40 })}
41 </> 41 </>
@@ -45,7 +45,7 @@ export default defineComponent({ @@ -45,7 +45,7 @@ export default defineComponent({
45 } 45 }
46 46
47 return () => ( 47 return () => (
48 - <Dropdown trigger={props.trigger as any} {...attrs}> 48 + <Dropdown trigger={props.trigger as Trigger[]} {...attrs}>
49 {{ 49 {{
50 default: () => <span>{getSlot(slots)}</span>, 50 default: () => <span>{getSlot(slots)}</span>,
51 overlay: () => renderMenus(), 51 overlay: () => renderMenus(),
src/components/Dropdown/props.ts renamed to src/components/Dropdown/src/props.ts
1 import type { PropType } from 'vue'; 1 import type { PropType } from 'vue';
  2 +import type { DropMenu } from './types';
2 3
3 export const dropdownProps = { 4 export const dropdownProps = {
4 /** 5 /**
@@ -15,7 +16,11 @@ export const dropdownProps = { @@ -15,7 +16,11 @@ export const dropdownProps = {
15 }; 16 };
16 export const basicDropdownProps = Object.assign({}, dropdownProps, { 17 export const basicDropdownProps = Object.assign({}, dropdownProps, {
17 dropMenuList: { 18 dropMenuList: {
18 - type: Array as PropType<any[]>, 19 + type: Array as PropType<DropMenu[]>,
  20 + default: () => [],
  21 + },
  22 + selectedKeys: {
  23 + type: Array as PropType<string[]>,
19 default: () => [], 24 default: () => [],
20 }, 25 },
21 }); 26 });
src/components/Dropdown/types.ts renamed to src/components/Dropdown/src/types.ts
@@ -6,3 +6,5 @@ export interface DropMenu { @@ -6,3 +6,5 @@ export interface DropMenu {
6 disabled?: boolean; 6 disabled?: boolean;
7 divider?: boolean; 7 divider?: boolean;
8 } 8 }
  9 +
  10 +export type Trigger = 'click' | 'hover' | 'contextMenu';
src/hooks/web/useI18n.ts deleted 100644 → 0
1 -import { createI18n } from 'vue-i18n';  
2 -import { ref, watch } from 'vue';  
3 -import type { I18nOptions } from 'vue-i18n';  
4 -export function useI18n(options?: I18nOptions) {  
5 - const i18n = createI18n(options);  
6 -  
7 - const localeRef = ref(i18n.global.locale);  
8 -  
9 - watch(localeRef, () => {  
10 - i18n.global.locale = localeRef.value as any;  
11 - });  
12 - return {  
13 - t: i18n.global.t,  
14 - localeRef,  
15 - };  
16 -}  
src/hooks/web/useLocale.ts
  1 +/**
  2 + * Multi-language related operations
  3 + */
1 import type { LocaleType } from '/@/locales/types'; 4 import type { LocaleType } from '/@/locales/types';
2 -import { appStore } from '/@/store/modules/app'; 5 +
  6 +import { unref, ref } from 'vue';
  7 +
  8 +import { getI18n } from '/@/setup/i18n';
  9 +
  10 +import { useLocaleSetting } from '/@/settings/use/useLocaleSetting';
  11 +
  12 +import moment from 'moment';
  13 +
  14 +import 'moment/dist/locale/zh-cn';
  15 +
  16 +moment.locale('zh-cn');
  17 +
  18 +const antConfigLocaleRef = ref<any>(null);
3 19
4 export function useLocale() { 20 export function useLocale() {
5 - /**  
6 - *  
7 - */  
8 - function getLocale(): string {  
9 - return appStore.getProjectConfig.locale; 21 + const { getLang, getLocale, setLocale: setLocalSetting } = useLocaleSetting();
  22 +
  23 + // Switching the language will change the locale of useI18n
  24 + // And submit to configuration modification
  25 + function changeLocale(lang: LocaleType): void {
  26 + (getI18n().global.locale as any).value = lang;
  27 + setLocalSetting({ lang });
  28 + // i18n.global.setLocaleMessage(locale, messages);
  29 +
  30 + antConfigLocaleRef.value = { a: 1 };
  31 + switch (lang) {
  32 + // Simplified Chinese
  33 + case 'zh_CN':
  34 + import('ant-design-vue/es/locale/zh_CN').then((locale) => {
  35 + antConfigLocaleRef.value = locale.default;
  36 + });
  37 +
  38 + moment.locale('cn');
  39 + break;
  40 + // English
  41 + case 'en':
  42 + import('ant-design-vue/es/locale/en_US').then((locale) => {
  43 + antConfigLocaleRef.value = locale.default;
  44 + });
  45 + moment.locale('en-us');
  46 + break;
  47 +
  48 + // other
  49 + default:
  50 + break;
  51 + }
10 } 52 }
11 53
12 - /**  
13 - *  
14 - * @param locale  
15 - */  
16 - async function changeLocale(locale: LocaleType): Promise<void> {  
17 - appStore.commitProjectConfigState({ locale: locale }); 54 + // initialization
  55 + function setupLocale() {
  56 + const lang = unref(getLang);
  57 + lang && changeLocale(lang);
18 } 58 }
19 59
20 - return { getLocale, changeLocale }; 60 + return {
  61 + setupLocale,
  62 + getLocale,
  63 + getLang,
  64 + changeLocale,
  65 + antConfigLocale: antConfigLocaleRef,
  66 + };
  67 +}
  68 +
  69 +/**
  70 + * For non-setup use
  71 + */
  72 +export function useExternalI18n() {
  73 + return getI18n().global;
21 } 74 }
src/hooks/web/useMessage.tsx
@@ -3,7 +3,6 @@ import type { ModalFunc, ModalFuncProps } from &#39;ant-design-vue/lib/modal/Modal&#39;; @@ -3,7 +3,6 @@ import type { ModalFunc, ModalFuncProps } from &#39;ant-design-vue/lib/modal/Modal&#39;;
3 import { Modal, message as Message, notification } from 'ant-design-vue'; 3 import { Modal, message as Message, notification } from 'ant-design-vue';
4 import { InfoCircleFilled, CheckCircleFilled, CloseCircleFilled } from '@ant-design/icons-vue'; 4 import { InfoCircleFilled, CheckCircleFilled, CloseCircleFilled } from '@ant-design/icons-vue';
5 5
6 -import { useSetting } from '/@/hooks/core/useSetting';  
7 import { ArgsProps, ConfigProps } from 'ant-design-vue/lib/notification'; 6 import { ArgsProps, ConfigProps } from 'ant-design-vue/lib/notification';
8 7
9 export interface NotifyApi { 8 export interface NotifyApi {
@@ -33,8 +32,6 @@ interface ConfirmOptions { @@ -33,8 +32,6 @@ interface ConfirmOptions {
33 warning: ModalFunc; 32 warning: ModalFunc;
34 } 33 }
35 34
36 -const { projectSetting } = useSetting();  
37 -  
38 function getIcon(iconType: string) { 35 function getIcon(iconType: string) {
39 if (iconType === 'warning') { 36 if (iconType === 'warning') {
40 return <InfoCircleFilled class="modal-icon-warning" />; 37 return <InfoCircleFilled class="modal-icon-warning" />;
@@ -60,7 +57,6 @@ function createConfirm(options: ModalOptionsEx): ConfirmOptions { @@ -60,7 +57,6 @@ function createConfirm(options: ModalOptionsEx): ConfirmOptions {
60 const opt: ModalFuncProps = { 57 const opt: ModalFuncProps = {
61 centered: true, 58 centered: true,
62 icon: getIcon(iconType), 59 icon: getIcon(iconType),
63 - ...projectSetting.messageSetting,  
64 ...options, 60 ...options,
65 }; 61 };
66 return Modal.confirm(opt) as any; 62 return Modal.confirm(opt) as any;
src/layouts/default/setting/SettingDrawer.tsx
@@ -5,7 +5,6 @@ import Button from &#39;/@/components/Button/index.vue&#39;; @@ -5,7 +5,6 @@ import Button from &#39;/@/components/Button/index.vue&#39;;
5 import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum'; 5 import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
6 import { CopyOutlined, RedoOutlined, CheckOutlined } from '@ant-design/icons-vue'; 6 import { CopyOutlined, RedoOutlined, CheckOutlined } from '@ant-design/icons-vue';
7 import { appStore } from '/@/store/modules/app'; 7 import { appStore } from '/@/store/modules/app';
8 -import { userStore } from '/@/store/modules/user';  
9 import { ProjectConfig } from '/@/types/config'; 8 import { ProjectConfig } from '/@/types/config';
10 9
11 import { useMessage } from '/@/hooks/web/useMessage'; 10 import { useMessage } from '/@/hooks/web/useMessage';
@@ -97,7 +96,7 @@ export default defineComponent({ @@ -97,7 +96,7 @@ export default defineComponent({
97 96
98 function handleClearAndRedo() { 97 function handleClearAndRedo() {
99 localStorage.clear(); 98 localStorage.clear();
100 - userStore.resumeAllState(); 99 + appStore.resumeAllState();
101 location.reload(); 100 location.reload();
102 } 101 }
103 102
src/layouts/logo/index.vue
@@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
7 <script lang="ts"> 7 <script lang="ts">
8 import { computed, defineComponent, PropType, ref, watch } from 'vue'; 8 import { computed, defineComponent, PropType, ref, watch } from 'vue';
9 // hooks 9 // hooks
10 - import { useSetting } from '/@/hooks/core/useSetting'; 10 + import { useGlobSetting } from '/@/settings/use';
11 import { useTimeoutFn } from '/@/hooks/core/useTimeout'; 11 import { useTimeoutFn } from '/@/hooks/core/useTimeout';
12 import { useGo } from '/@/hooks/web/usePage'; 12 import { useGo } from '/@/hooks/web/usePage';
13 13
@@ -30,7 +30,7 @@ @@ -30,7 +30,7 @@
30 }, 30 },
31 setup(props) { 31 setup(props) {
32 const showRef = ref<boolean>(!!props.showTitle); 32 const showRef = ref<boolean>(!!props.showTitle);
33 - const { globSetting } = useSetting(); 33 + const globSetting = useGlobSetting();
34 const go = useGo(); 34 const go = useGo();
35 35
36 function handleGoHome() { 36 function handleGoHome() {
src/layouts/page/index.tsx
@@ -4,7 +4,7 @@ import { RouterView, RouteLocation } from &#39;vue-router&#39;; @@ -4,7 +4,7 @@ import { RouterView, RouteLocation } from &#39;vue-router&#39;;
4 import FrameLayout from '/@/layouts/iframe/index.vue'; 4 import FrameLayout from '/@/layouts/iframe/index.vue';
5 5
6 import { useTransition } from './useTransition'; 6 import { useTransition } from './useTransition';
7 -import { useSetting } from '/@/hooks/core/useSetting'; 7 +import { useProjectSetting } from '/@/settings/use';
8 8
9 import { tabStore } from '/@/store/modules/tab'; 9 import { tabStore } from '/@/store/modules/tab';
10 import { appStore } from '/@/store/modules/app'; 10 import { appStore } from '/@/store/modules/app';
@@ -29,7 +29,7 @@ export default defineComponent({ @@ -29,7 +29,7 @@ export default defineComponent({
29 const { on: transitionOn } = useTransition(); 29 const { on: transitionOn } = useTransition();
30 on = transitionOn; 30 on = transitionOn;
31 } 31 }
32 - const { projectSetting } = useSetting(); 32 + const projectSetting = useProjectSetting();
33 return () => { 33 return () => {
34 const { 34 const {
35 routerTransition, 35 routerTransition,
src/locales/index.ts
1 import messages from 'globby?locale!/@/locales/lang/**/*.@(ts)'; 1 import messages from 'globby?locale!/@/locales/lang/**/*.@(ts)';
2 2
  3 +import type { DropMenu } from '/@/components/Dropdown';
  4 +
  5 +// locale list
  6 +export const localeList: DropMenu[] = [
  7 + {
  8 + text: '简体中文',
  9 + event: 'zh_CN',
  10 + },
  11 + {
  12 + text: 'English',
  13 + event: 'en',
  14 + },
  15 +];
  16 +
3 export default messages; 17 export default messages;
src/locales/lang/en/sys/errorLog.ts 0 → 100644
  1 +export default {
  2 + tableTitle: 'Error log list',
  3 + tableColumnType: 'Type',
  4 + tableColumnDate: 'Time',
  5 + tableColumnFile: 'File',
  6 + tableColumnMsg: 'Error message',
  7 + tableColumnStackMsg: 'Stack info',
  8 +
  9 + tableActionDesc: 'Details',
  10 +
  11 + modalTitle: 'Error details',
  12 +
  13 + fireVueError: 'Fire vue error',
  14 + fireResourceError: 'Fire resource error',
  15 + fireAjaxError: 'Fire ajax error',
  16 +
  17 + enableMessage: 'Only effective when useErrorHandle=true in `/src/settings/projectSetting.ts`.',
  18 +};
src/locales/lang/en/sys/exception.ts 0 → 100644
  1 +export default {
  2 + backLogin: 'Back Login',
  3 + backHome: 'Back Home',
  4 + redo: 'Refresh',
  5 + subTitle403: "Sorry, you don't have access to this page.",
  6 + subTitle404: 'Sorry, the page you visited does not exist.',
  7 + subTitle500: 'Sorry, the server is reporting an error.',
  8 + noDataTitle: 'No data on the current page.',
  9 + networkErrorTitle: 'Network Error',
  10 + networkErrorSubTitle:
  11 + 'Sorry,Your network connection has been disconnected, please check your network!',
  12 +};
src/locales/lang/en/sys/lock.ts 0 → 100644
  1 +export default {
  2 + alert: 'Lock screen password error',
  3 + backToLogin: 'Back to login',
  4 + entry: 'Enter the system',
  5 + placeholder: 'Please enter the lock screen password or user password',
  6 +};
src/locales/lang/en/sys/login.ts 0 → 100644
  1 +export default {
  2 + loginButton: 'Login',
  3 + autoLogin: 'AutoLogin',
  4 + forgetPassword: 'Forget Password',
  5 +
  6 + // notify
  7 + loginSuccessTitle: 'Login successful',
  8 + loginSuccessDesc: 'Welcome back',
  9 +
  10 + // placeholder
  11 + accountPlaceholder: 'Please input Username',
  12 + passwordPlaceholder: 'Please input Password',
  13 +};
src/locales/lang/en/system/basic.ts deleted 100644 → 0
1 -export default {  
2 - some: 'Get Out',  
3 -};  
src/locales/lang/en/system/login.ts deleted 100644 → 0
1 -export default {  
2 - button: 'Login',  
3 -};  
src/locales/lang/ru/routes/menus/dashboard.ts deleted 100644 → 0
1 -export default {  
2 - someentry: 'some text',  
3 -};  
src/locales/lang/ru/system/basic.ts deleted 100644 → 0
1 -export default {  
2 - some: 'Get Out',  
3 -};  
src/locales/lang/ru/system/login.ts deleted 100644 → 0
1 -export default {  
2 - button: 'Login',  
3 - validation: {  
4 - account: 'Required Field account',  
5 - password: 'Required Field password',  
6 - },  
7 -};  
src/locales/lang/zhCN/system/basic.ts deleted 100644 → 0
1 -export default {  
2 - some: '出去',  
3 -};  
src/locales/lang/zhCN/system/login.ts deleted 100644 → 0
1 -export default {  
2 - button: '登录',  
3 -};  
src/locales/lang/zhCN/routes/menus/dashboard.ts renamed to src/locales/lang/zh_CN/routes/menus/dashboard.ts
src/locales/lang/zh_CN/sys/errorLog.ts 0 → 100644
  1 +export default {
  2 + tableTitle: '错误日志列表',
  3 + tableColumnType: '类型',
  4 + tableColumnDate: '时间',
  5 + tableColumnFile: '文件',
  6 + tableColumnMsg: '错误信息',
  7 + tableColumnStackMsg: 'stack信息',
  8 +
  9 + tableActionDesc: '详情',
  10 +
  11 + modalTitle: '错误详情',
  12 +
  13 + fireVueError: '点击触发vue错误',
  14 + fireResourceError: '点击触发资源加载错误',
  15 + fireAjaxError: '点击触发ajax错误',
  16 +
  17 + enableMessage: '只在`/src/settings/projectSetting.ts` 内的useErrorHandle=true时生效.',
  18 +};
src/locales/lang/zh_CN/sys/exception.ts 0 → 100644
  1 +export default {
  2 + backLogin: '返回登录',
  3 + backHome: '返回首页',
  4 + redo: '刷新',
  5 + subTitle403: '抱歉,您无权访问此页面。',
  6 + subTitle404: '抱歉,您访问的页面不存在。',
  7 + subTitle500: '抱歉,服务器报告错误。',
  8 + noDataTitle: '当前页无数据',
  9 + networkErrorTitle: '网络错误',
  10 + networkErrorSubTitle: '抱歉,您的网络连接已断开,请检查您的网络!',
  11 +};
src/locales/lang/zh_CN/sys/lock.ts 0 → 100644
  1 +export default {
  2 + alert: '锁屏密码错误',
  3 + backToLogin: '返回登录',
  4 + entry: '进入系统',
  5 + placeholder: '请输入锁屏密码或者用户密码',
  6 +};
src/locales/lang/zh_CN/sys/login.ts 0 → 100644
  1 +export default {
  2 + loginButton: '登录',
  3 + autoLogin: '自动登录',
  4 + forgetPassword: '忘记密码',
  5 +
  6 + // notify
  7 + loginSuccessTitle: '登录成功',
  8 + loginSuccessDesc: '欢迎回来',
  9 +
  10 + // placeholder
  11 + accountPlaceholder: '请输入账号',
  12 + passwordPlaceholder: '请输入密码',
  13 +};
src/locales/types.ts
1 -export type LocaleType = 'zhCN' | 'en' | 'ru' | 'ja'; 1 +export type LocaleType = 'zh_CN' | 'en' | 'ru' | 'ja';
src/router/guard/index.ts
@@ -6,7 +6,7 @@ import { createProgressGuard } from &#39;./progressGuard&#39;; @@ -6,7 +6,7 @@ import { createProgressGuard } from &#39;./progressGuard&#39;;
6 import { createPermissionGuard } from './permissionGuard'; 6 import { createPermissionGuard } from './permissionGuard';
7 import { createPageLoadingGuard } from './pageLoadingGuard'; 7 import { createPageLoadingGuard } from './pageLoadingGuard';
8 8
9 -import { useSetting } from '/@/hooks/core/useSetting'; 9 +import { useGlobSetting, useProjectSetting } from '/@/settings/use';
10 10
11 import { getIsOpenTab, setCurrentTo } from '/@/utils/helper/routeHelper'; 11 import { getIsOpenTab, setCurrentTo } from '/@/utils/helper/routeHelper';
12 import { setTitle } from '/@/utils/browser'; 12 import { setTitle } from '/@/utils/browser';
@@ -14,9 +14,9 @@ import { AxiosCanceler } from &#39;/@/utils/http/axios/axiosCancel&#39;; @@ -14,9 +14,9 @@ import { AxiosCanceler } from &#39;/@/utils/http/axios/axiosCancel&#39;;
14 14
15 import { tabStore } from '/@/store/modules/tab'; 15 import { tabStore } from '/@/store/modules/tab';
16 16
17 -const { projectSetting, globSetting } = useSetting(); 17 +const globSetting = useGlobSetting();
18 export function createGuard(router: Router) { 18 export function createGuard(router: Router) {
19 - const { openNProgress, closeMessageOnSwitch, removeAllHttpPending } = projectSetting; 19 + const { openNProgress, closeMessageOnSwitch, removeAllHttpPending } = useProjectSetting();
20 let axiosCanceler: AxiosCanceler | null; 20 let axiosCanceler: AxiosCanceler | null;
21 if (removeAllHttpPending) { 21 if (removeAllHttpPending) {
22 axiosCanceler = new AxiosCanceler(); 22 axiosCanceler = new AxiosCanceler();
src/router/guard/permissionGuard.ts
1 import type { Router, RouteRecordRaw } from 'vue-router'; 1 import type { Router, RouteRecordRaw } from 'vue-router';
2 2
3 -import { userStore } from '/@/store/modules/user'; 3 +import { appStore } from '/@/store/modules/app';
4 import { permissionStore } from '/@/store/modules/permission'; 4 import { permissionStore } from '/@/store/modules/permission';
5 5
6 import { PageEnum } from '/@/enums/pageEnum'; 6 import { PageEnum } from '/@/enums/pageEnum';
@@ -72,7 +72,7 @@ export function createPermissionGuard(router: Router) { @@ -72,7 +72,7 @@ export function createPermissionGuard(router: Router) {
72 router.afterEach((to) => { 72 router.afterEach((to) => {
73 // Just enter the login page and clear the authentication information 73 // Just enter the login page and clear the authentication information
74 if (to.path === LOGIN_PATH) { 74 if (to.path === LOGIN_PATH) {
75 - userStore.resumeAllState(); 75 + appStore.resumeAllState();
76 } 76 }
77 }); 77 });
78 } 78 }
src/router/menus/modules/demo/feat.ts
@@ -36,10 +36,6 @@ const menu: MenuModule = { @@ -36,10 +36,6 @@ const menu: MenuModule = {
36 name: '图片预览', 36 name: '图片预览',
37 }, 37 },
38 { 38 {
39 - path: 'i18n',  
40 - name: '国际化',  
41 - },  
42 - {  
43 path: 'copy', 39 path: 'copy',
44 name: '剪切板', 40 name: '剪切板',
45 }, 41 },
src/router/routes/modules/demo/feat.ts
@@ -81,14 +81,6 @@ const feat: AppRouteModule = { @@ -81,14 +81,6 @@ const feat: AppRouteModule = {
81 }, 81 },
82 }, 82 },
83 { 83 {
84 - path: '/i18n',  
85 - name: 'I18nDemo',  
86 - component: () => import('/@/views/demo/feat/i18n/index.vue'),  
87 - meta: {  
88 - title: '国际化',  
89 - },  
90 - },  
91 - {  
92 path: '/watermark', 84 path: '/watermark',
93 name: 'WatermarkDemo', 85 name: 'WatermarkDemo',
94 component: () => import('/@/views/demo/feat/watermark/index.vue'), 86 component: () => import('/@/views/demo/feat/watermark/index.vue'),
src/settings/projectSetting.ts
@@ -7,7 +7,16 @@ import { isProdMode } from &#39;/@/utils/env&#39;; @@ -7,7 +7,16 @@ import { isProdMode } from &#39;/@/utils/env&#39;;
7 7
8 // ! You need to clear the browser cache after the change 8 // ! You need to clear the browser cache after the change
9 const setting: ProjectConfig = { 9 const setting: ProjectConfig = {
10 - locale: 'en', 10 + // locale setting
  11 + locale: {
  12 + // Locales
  13 + lang: 'zh_CN',
  14 + // Default locale
  15 + fallback: 'zh_CN',
  16 + // available Locales
  17 + availableLocales: ['zh_CN', 'en'],
  18 + },
  19 +
11 // color 20 // color
12 // TODO 主题色 21 // TODO 主题色
13 themeColor: primaryColor, 22 themeColor: primaryColor,
@@ -87,15 +96,7 @@ const setting: ProjectConfig = { @@ -87,15 +96,7 @@ const setting: ProjectConfig = {
87 // 开启手风琴模式,只显示一个菜单 96 // 开启手风琴模式,只显示一个菜单
88 accordion: true, 97 accordion: true,
89 }, 98 },
90 - // 消息配置  
91 - messageSetting: {  
92 - // 弹窗title  
93 - title: '操作提示',  
94 - // 取消按钮的文子,  
95 - cancelText: '取消',  
96 - // 确认按钮的文字  
97 - okText: '确定',  
98 - }, 99 +
99 // 多标签 100 // 多标签
100 multiTabsSetting: { 101 multiTabsSetting: {
101 // 开启 102 // 开启
src/hooks/core/useSetting.ts renamed to src/settings/use/index.ts
1 -import type { ProjectConfig, GlobConfig, SettingWrap, GlobEnvConfig } from '/@/types/config'; 1 +import type { ProjectConfig, GlobConfig, GlobEnvConfig } from '/@/types/config';
2 2
3 import getProjectSetting from '/@/settings/projectSetting'; 3 import getProjectSetting from '/@/settings/projectSetting';
4 4
5 -import { getGlobEnvConfig, isDevMode } from '/@/utils/env';  
6 import { getShortName } from '../../../build/getShortName'; 5 import { getShortName } from '../../../build/getShortName';
7 import { warn } from '/@/utils/log'; 6 import { warn } from '/@/utils/log';
  7 +import { getGlobEnvConfig, isDevMode } from '/@/utils/env';
8 8
9 const reg = /[a-zA-Z\_]*/; 9 const reg = /[a-zA-Z\_]*/;
10 10
@@ -12,6 +12,7 @@ const ENV_NAME = getShortName(import.meta.env); @@ -12,6 +12,7 @@ const ENV_NAME = getShortName(import.meta.env);
12 const ENV = ((isDevMode() 12 const ENV = ((isDevMode()
13 ? getGlobEnvConfig() 13 ? getGlobEnvConfig()
14 : window[ENV_NAME as any]) as unknown) as GlobEnvConfig; 14 : window[ENV_NAME as any]) as unknown) as GlobEnvConfig;
  15 +
15 const { 16 const {
16 VITE_GLOB_APP_TITLE, 17 VITE_GLOB_APP_TITLE,
17 VITE_GLOB_API_URL, 18 VITE_GLOB_API_URL,
@@ -25,7 +26,7 @@ if (!reg.test(VITE_GLOB_APP_SHORT_NAME)) { @@ -25,7 +26,7 @@ if (!reg.test(VITE_GLOB_APP_SHORT_NAME)) {
25 ); 26 );
26 } 27 }
27 28
28 -export const useSetting = (): SettingWrap => { 29 +export const useGlobSetting = (): Readonly<GlobConfig> => {
29 // Take global configuration 30 // Take global configuration
30 const glob: Readonly<GlobConfig> = { 31 const glob: Readonly<GlobConfig> = {
31 title: VITE_GLOB_APP_TITLE, 32 title: VITE_GLOB_APP_TITLE,
@@ -33,9 +34,10 @@ export const useSetting = (): SettingWrap =&gt; { @@ -33,9 +34,10 @@ export const useSetting = (): SettingWrap =&gt; {
33 shortName: VITE_GLOB_APP_SHORT_NAME, 34 shortName: VITE_GLOB_APP_SHORT_NAME,
34 urlPrefix: VITE_GLOB_API_URL_PREFIX, 35 urlPrefix: VITE_GLOB_API_URL_PREFIX,
35 }; 36 };
36 - const projectSetting: Readonly<ProjectConfig> = getProjectSetting;  
37 - return {  
38 - globSetting: glob as Readonly<GlobConfig>,  
39 - projectSetting,  
40 - }; 37 + return glob as Readonly<GlobConfig>;
  38 +};
  39 +
  40 +export const useProjectSetting = (): ProjectConfig => {
  41 + // TODO computed
  42 + return getProjectSetting;
41 }; 43 };
src/settings/use/useLocaleSetting.ts 0 → 100644
  1 +import type { LocaleSetting } from '/@/types/config';
  2 +
  3 +import { computed } from 'vue';
  4 +import { appStore } from '/@/store/modules/app';
  5 +
  6 +import getProjectSetting from '/@/settings/projectSetting';
  7 +import { localeList } from '/@/locales';
  8 +
  9 +export function useLocaleSetting() {
  10 + // Get locale configuration
  11 + const getLocale = computed(() => {
  12 + return appStore.getProjectConfig.locale || getProjectSetting.locale;
  13 + });
  14 +
  15 + // get current language
  16 + const getLang = computed(() => {
  17 + return getLocale.value.lang;
  18 + });
  19 +
  20 + // get Available Locales
  21 + const getAvailableLocales = computed((): string[] => {
  22 + return getLocale.value.availableLocales;
  23 + });
  24 +
  25 + // get Fallback Locales
  26 + const getFallbackLocale = computed((): string => {
  27 + return getLocale.value.fallback;
  28 + });
  29 +
  30 + // Set locale configuration
  31 + function setLocale(locale: Partial<LocaleSetting>): void {
  32 + appStore.commitProjectConfigState({ locale });
  33 + }
  34 +
  35 + return { getLocale, getLang, localeList, setLocale, getAvailableLocales, getFallbackLocale };
  36 +}
src/setup/directives/permission.ts
@@ -14,9 +14,7 @@ function isAuth(el: Element, binding: any) { @@ -14,9 +14,7 @@ function isAuth(el: Element, binding: any) {
14 const value = binding.value; 14 const value = binding.value;
15 if (!value) return; 15 if (!value) return;
16 if (!hasPermission(value)) { 16 if (!hasPermission(value)) {
17 - if (el.parentNode) {  
18 - el.parentNode.removeChild(el);  
19 - } 17 + el.parentNode?.removeChild(el);
20 } 18 }
21 } 19 }
22 20
src/setup/directives/repeatClick.ts
@@ -9,7 +9,7 @@ const repeatDirective: Directive = { @@ -9,7 +9,7 @@ const repeatDirective: Directive = {
9 beforeMount(el: Element, binding: DirectiveBinding<any>) { 9 beforeMount(el: Element, binding: DirectiveBinding<any>) {
10 let interval: Nullable<IntervalHandle> = null; 10 let interval: Nullable<IntervalHandle> = null;
11 let startTime = 0; 11 let startTime = 0;
12 - const handler = (): void => binding.value && binding.value(); 12 + const handler = (): void => binding?.value();
13 const clear = (): void => { 13 const clear = (): void => {
14 if (Date.now() - startTime < 100) { 14 if (Date.now() - startTime < 100) {
15 handler(); 15 handler();
src/setup/error-handle/index.ts
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 */ 3 */
4 4
5 import { errorStore, ErrorInfo } from '/@/store/modules/error'; 5 import { errorStore, ErrorInfo } from '/@/store/modules/error';
6 -import { useSetting } from '/@/hooks/core/useSetting'; 6 +import { useProjectSetting } from '/@/settings/use';
7 import { ErrorTypeEnum } from '/@/enums/exceptionEnum'; 7 import { ErrorTypeEnum } from '/@/enums/exceptionEnum';
8 import { App } from 'vue'; 8 import { App } from 'vue';
9 9
@@ -89,7 +89,7 @@ export function scriptErrorHandler( @@ -89,7 +89,7 @@ export function scriptErrorHandler(
89 const errorInfo: Partial<ErrorInfo> = {}; 89 const errorInfo: Partial<ErrorInfo> = {};
90 colno = colno || (window.event && (window.event as any).errorCharacter) || 0; 90 colno = colno || (window.event && (window.event as any).errorCharacter) || 0;
91 errorInfo.message = event as string; 91 errorInfo.message = event as string;
92 - if (error && error.stack) { 92 + if (error?.stack) {
93 errorInfo.stack = error.stack; 93 errorInfo.stack = error.stack;
94 } else { 94 } else {
95 errorInfo.stack = ''; 95 errorInfo.stack = '';
@@ -160,8 +160,7 @@ function registerResourceErrorHandler() { @@ -160,8 +160,7 @@ function registerResourceErrorHandler() {
160 * @param app 160 * @param app
161 */ 161 */
162 export function setupErrorHandle(app: App) { 162 export function setupErrorHandle(app: App) {
163 - const { projectSetting } = useSetting();  
164 - const { useErrorHandle } = projectSetting; 163 + const { useErrorHandle } = useProjectSetting();
165 if (!useErrorHandle) return; 164 if (!useErrorHandle) return;
166 // Vue exception monitoring; 165 // Vue exception monitoring;
167 app.config.errorHandler = vueErrorHandler; 166 app.config.errorHandler = vueErrorHandler;
src/setup/i18n/index.ts
1 -import type { App } from 'vue';  
2 -import type { I18n, Locale, I18nOptions } from 'vue-i18n'; 1 +import { App, unref } from 'vue';
  2 +import type { I18n, I18nOptions } from 'vue-i18n';
3 3
4 import { createI18n } from 'vue-i18n'; 4 import { createI18n } from 'vue-i18n';
5 import localeMessages from '/@/locales'; 5 import localeMessages from '/@/locales';
6 import { useLocale } from '/@/hooks/web/useLocale'; 6 import { useLocale } from '/@/hooks/web/useLocale';
  7 +import { useLocaleSetting } from '/@/settings/use/useLocaleSetting';
7 8
8 -const { getLocale } = useLocale(); 9 +const { setupLocale } = useLocale();
9 10
  11 +const { getLang, getAvailableLocales, getFallbackLocale } = useLocaleSetting();
10 const localeData: I18nOptions = { 12 const localeData: I18nOptions = {
11 legacy: false, 13 legacy: false,
12 - locale: getLocale(),  
13 - // TODO: setting fallback inside settings  
14 - fallbackLocale: 'en', 14 + locale: unref(getLang),
  15 + fallbackLocale: unref(getFallbackLocale),
15 messages: localeMessages, 16 messages: localeMessages,
16 - // availableLocales: ['ru'], 17 + availableLocales: unref(getAvailableLocales),
17 sync: true, //If you don’t want to inherit locale from global scope, you need to set sync of i18n component option to false. 18 sync: true, //If you don’t want to inherit locale from global scope, you need to set sync of i18n component option to false.
18 silentTranslationWarn: false, // true - warning off 19 silentTranslationWarn: false, // true - warning off
19 silentFallbackWarn: true, 20 silentFallbackWarn: true,
@@ -24,12 +25,10 @@ let i18n: I18n; @@ -24,12 +25,10 @@ let i18n: I18n;
24 // setup i18n instance with glob 25 // setup i18n instance with glob
25 export function setupI18n(app: App) { 26 export function setupI18n(app: App) {
26 i18n = createI18n(localeData) as I18n; 27 i18n = createI18n(localeData) as I18n;
27 - setI18nLanguage(getLocale()); 28 + setupLocale();
28 app.use(i18n); 29 app.use(i18n);
29 } 30 }
30 31
31 -export function setI18nLanguage(locale: Locale): void {  
32 - // @ts-ignore  
33 - i18n.global.locale.value = locale;  
34 - // i18n.global.setLocaleMessage(locale, messages); 32 +export function getI18n(): I18n {
  33 + return i18n;
35 } 34 }
src/store/modules/app.ts
@@ -6,9 +6,19 @@ import store from &#39;/@/store&#39;; @@ -6,9 +6,19 @@ import store from &#39;/@/store&#39;;
6 import { PROJ_CFG_KEY, LOCK_INFO_KEY } from '/@/enums/cacheEnum'; 6 import { PROJ_CFG_KEY, LOCK_INFO_KEY } from '/@/enums/cacheEnum';
7 7
8 import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper'; 8 import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
9 -import { setLocal, getLocal, removeLocal } from '/@/utils/helper/persistent'; 9 +import {
  10 + setLocal,
  11 + getLocal,
  12 + removeLocal,
  13 + clearSession,
  14 + clearLocal,
  15 +} from '/@/utils/helper/persistent';
10 import { deepMerge } from '/@/utils'; 16 import { deepMerge } from '/@/utils';
11 17
  18 +import { resetRouter } from '/@/router';
  19 +import { permissionStore } from './permission';
  20 +import { tabStore } from './tab';
  21 +
12 import { userStore } from './user'; 22 import { userStore } from './user';
13 23
14 export interface LockInfo { 24 export interface LockInfo {
@@ -78,6 +88,17 @@ class App extends VuexModule { @@ -78,6 +88,17 @@ class App extends VuexModule {
78 } 88 }
79 89
80 @Action 90 @Action
  91 + async resumeAllState() {
  92 + resetRouter();
  93 + clearSession();
  94 + clearLocal();
  95 +
  96 + permissionStore.commitResetState();
  97 + tabStore.commitResetState();
  98 + userStore.commitResetState();
  99 + }
  100 +
  101 + @Action
81 public async setPageLoadingAction(loading: boolean): Promise<void> { 102 public async setPageLoadingAction(loading: boolean): Promise<void> {
82 if (loading) { 103 if (loading) {
83 clearTimeout(timeId); 104 clearTimeout(timeId);
src/store/modules/error.ts
@@ -4,7 +4,7 @@ import { VuexModule, getModule, Module, Mutation, Action } from &#39;vuex-module-dec @@ -4,7 +4,7 @@ import { VuexModule, getModule, Module, Mutation, Action } from &#39;vuex-module-dec
4 4
5 import { formatToDateTime } from '/@/utils/dateUtil'; 5 import { formatToDateTime } from '/@/utils/dateUtil';
6 import { ErrorTypeEnum } from '/@/enums/exceptionEnum'; 6 import { ErrorTypeEnum } from '/@/enums/exceptionEnum';
7 -import { useSetting } from '/@/hooks/core/useSetting'; 7 +import { useProjectSetting } from '/@/settings/use';
8 8
9 export interface ErrorInfo { 9 export interface ErrorInfo {
10 type: ErrorTypeEnum; 10 type: ErrorTypeEnum;
@@ -16,6 +16,7 @@ export interface ErrorInfo { @@ -16,6 +16,7 @@ export interface ErrorInfo {
16 url: string; 16 url: string;
17 time?: string; 17 time?: string;
18 } 18 }
  19 +
19 export interface ErrorState { 20 export interface ErrorState {
20 errorInfoState: ErrorInfo[] | null; 21 errorInfoState: ErrorInfo[] | null;
21 errorListCountState: number; 22 errorListCountState: number;
@@ -56,8 +57,7 @@ class Error extends VuexModule implements ErrorState { @@ -56,8 +57,7 @@ class Error extends VuexModule implements ErrorState {
56 57
57 @Action 58 @Action
58 setupErrorHandle(error: any) { 59 setupErrorHandle(error: any) {
59 - const { projectSetting } = useSetting();  
60 - const { useErrorHandle } = projectSetting; 60 + const { useErrorHandle } = useProjectSetting();
61 if (!useErrorHandle) return; 61 if (!useErrorHandle) return;
62 62
63 const errInfo: Partial<ErrorInfo> = { 63 const errInfo: Partial<ErrorInfo> = {
src/store/modules/user.ts
@@ -15,13 +15,11 @@ import { ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from &#39;/@/enums/cacheEnum&#39;; @@ -15,13 +15,11 @@ import { ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from &#39;/@/enums/cacheEnum&#39;;
15 15
16 import { useMessage } from '/@/hooks/web/useMessage'; 16 import { useMessage } from '/@/hooks/web/useMessage';
17 17
18 -import router, { resetRouter } from '/@/router';  
19 -import { permissionStore } from './permission';  
20 -import { tabStore } from './tab'; 18 +import router from '/@/router';
21 19
22 import { loginApi, getUserInfoById } from '/@/api/sys/user'; 20 import { loginApi, getUserInfoById } from '/@/api/sys/user';
23 21
24 -import { setLocal, getLocal, clearSession, clearLocal } from '/@/utils/helper/persistent'; 22 +import { setLocal, getLocal } from '/@/utils/helper/persistent';
25 // import { FULL_PAGE_NOT_FOUND_ROUTE } from '/@/router/constant'; 23 // import { FULL_PAGE_NOT_FOUND_ROUTE } from '/@/router/constant';
26 24
27 export type UserInfo = Omit<GetUserInfoByUserIdModel, 'roles'>; 25 export type UserInfo = Omit<GetUserInfoByUserIdModel, 'roles'>;
@@ -52,7 +50,7 @@ class User extends VuexModule { @@ -52,7 +50,7 @@ class User extends VuexModule {
52 } 50 }
53 51
54 @Mutation 52 @Mutation
55 - resetState(): void { 53 + commitResetState(): void {
56 this.userInfoState = null; 54 this.userInfoState = null;
57 this.tokenState = ''; 55 this.tokenState = '';
58 this.roleListState = []; 56 this.roleListState = [];
@@ -128,16 +126,6 @@ class User extends VuexModule { @@ -128,16 +126,6 @@ class User extends VuexModule {
128 goLogin && router.push(PageEnum.BASE_LOGIN); 126 goLogin && router.push(PageEnum.BASE_LOGIN);
129 } 127 }
130 128
131 - @Action  
132 - async resumeAllState() {  
133 - resetRouter();  
134 - clearSession();  
135 - clearLocal();  
136 - permissionStore.commitResetState();  
137 - tabStore.commitResetState();  
138 - this.resetState();  
139 - }  
140 -  
141 /** 129 /**
142 * @description: Confirm before logging out 130 * @description: Confirm before logging out
143 */ 131 */
src/types/config.d.ts
@@ -2,13 +2,7 @@ @@ -2,13 +2,7 @@
2 import { MenuTypeEnum, MenuModeEnum, TriggerEnum } from '/@/enums/menuEnum'; 2 import { MenuTypeEnum, MenuModeEnum, TriggerEnum } from '/@/enums/menuEnum';
3 import { ContentEnum, PermissionModeEnum, ThemeEnum, RouterTransitionEnum } from '/@/enums/appEnum'; 3 import { ContentEnum, PermissionModeEnum, ThemeEnum, RouterTransitionEnum } from '/@/enums/appEnum';
4 import type { LocaleType } from '/@/locales/types'; 4 import type { LocaleType } from '/@/locales/types';
5 -export interface MessageSetting {  
6 - title: string;  
7 - // 取消按钮的文字,  
8 - cancelText: string;  
9 - // 确认按钮的文字  
10 - okText: string;  
11 -} 5 +
12 export interface MenuSetting { 6 export interface MenuSetting {
13 collapsed: boolean; 7 collapsed: boolean;
14 collapsedShowTitle: boolean; 8 collapsedShowTitle: boolean;
@@ -54,8 +48,18 @@ export interface HeaderSetting { @@ -54,8 +48,18 @@ export interface HeaderSetting {
54 // 显示消息中心按钮 48 // 显示消息中心按钮
55 showNotice: boolean; 49 showNotice: boolean;
56 } 50 }
  51 +
  52 +export interface LocaleSetting {
  53 + // Current language
  54 + lang: LocaleType;
  55 + // default language
  56 + fallback: LocaleType;
  57 + // available Locales
  58 + availableLocales: LocaleType[];
  59 +}
  60 +
57 export interface ProjectConfig { 61 export interface ProjectConfig {
58 - locale: LocaleType; 62 + locale: LocaleSetting;
59 // header背景色 63 // header背景色
60 headerBgColor: string; 64 headerBgColor: string;
61 // 左侧菜单背景色 65 // 左侧菜单背景色
@@ -81,8 +85,6 @@ export interface ProjectConfig { @@ -81,8 +85,6 @@ export interface ProjectConfig {
81 // menuType: MenuTypeEnum; 85 // menuType: MenuTypeEnum;
82 menuSetting: MenuSetting; 86 menuSetting: MenuSetting;
83 87
84 - messageSetting: MessageSetting;  
85 -  
86 // 多标签页设置 88 // 多标签页设置
87 multiTabsSetting: MultiTabsSetting; 89 multiTabsSetting: MultiTabsSetting;
88 // pageLayout是否开启keep-alive 90 // pageLayout是否开启keep-alive
@@ -133,12 +135,6 @@ export interface GlobEnvConfig { @@ -133,12 +135,6 @@ export interface GlobEnvConfig {
133 VITE_GLOB_APP_SHORT_NAME: string; 135 VITE_GLOB_APP_SHORT_NAME: string;
134 } 136 }
135 137
136 -// 修改配置  
137 -export type SetProjectSettingFn = <T extends keyof ProjectConfig>(  
138 - key: T,  
139 - value: ProjectConfig[T]  
140 -) => void;  
141 -  
142 interface GlobWrap { 138 interface GlobWrap {
143 globSetting: Readonly<GlobConfig>; 139 globSetting: Readonly<GlobConfig>;
144 } 140 }
@@ -146,5 +142,3 @@ interface GlobWrap { @@ -146,5 +142,3 @@ interface GlobWrap {
146 interface ProjectSettingWrap { 142 interface ProjectSettingWrap {
147 projectSetting: Readonly<ProjectConfig>; 143 projectSetting: Readonly<ProjectConfig>;
148 } 144 }
149 -  
150 -export type SettingWrap = GlobWrap & ProjectSettingWrap;  
src/utils/helper/envHelper.ts
1 import { getEnv } from '/@/utils/env'; 1 import { getEnv } from '/@/utils/env';
2 -import { useSetting } from '/@/hooks/core/useSetting'; 2 +import { useGlobSetting } from '/@/settings/use';
3 import pkg from '../../../package.json'; 3 import pkg from '../../../package.json';
4 -const { globSetting } = useSetting(); 4 +const globSetting = useGlobSetting();
5 5
6 // Generate cache key according to version 6 // Generate cache key according to version
7 export const getStorageShortName = () => { 7 export const getStorageShortName = () => {
src/utils/http/axios/index.ts
@@ -10,7 +10,7 @@ import { AxiosTransform } from &#39;./axiosTransform&#39;; @@ -10,7 +10,7 @@ import { AxiosTransform } from &#39;./axiosTransform&#39;;
10 10
11 import { checkStatus } from './checkStatus'; 11 import { checkStatus } from './checkStatus';
12 12
13 -import { useSetting } from '/@/hooks/core/useSetting'; 13 +import { useGlobSetting } from '/@/settings/use';
14 import { useMessage } from '/@/hooks/web/useMessage'; 14 import { useMessage } from '/@/hooks/web/useMessage';
15 15
16 import { RequestEnum, ResultEnum, ContentTypeEnum } from '/@/enums/httpEnum'; 16 import { RequestEnum, ResultEnum, ContentTypeEnum } from '/@/enums/httpEnum';
@@ -21,7 +21,7 @@ import { setObjToUrlParams, deepMerge } from &#39;/@/utils&#39;; @@ -21,7 +21,7 @@ import { setObjToUrlParams, deepMerge } from &#39;/@/utils&#39;;
21 import { errorStore } from '/@/store/modules/error'; 21 import { errorStore } from '/@/store/modules/error';
22 import { errorResult } from './const'; 22 import { errorResult } from './const';
23 23
24 -const { globSetting } = useSetting(); 24 +const globSetting = useGlobSetting();
25 const prefix = globSetting.urlPrefix; 25 const prefix = globSetting.urlPrefix;
26 const { createMessage, createErrorModal } = useMessage(); 26 const { createMessage, createErrorModal } = useMessage();
27 27
src/views/demo/feat/i18n/index.vue deleted 100644 → 0
1 -<template>  
2 - <div class="p-4">  
3 - <Alert message="国际化方式,没有进行全局国际化,有需要可以自行处理。" type="info" />  
4 - <Divider />  
5 - 国际化信息: {{ t('hello') }}  
6 - <Divider />  
7 - <a-button :type="localeRef === 'zhCN' ? 'primary' : 'default'" @click="localeRef = 'zhCN'">  
8 - 中文  
9 - </a-button>  
10 - <a-button :type="localeRef === 'en' ? 'primary' : 'default'" @click="localeRef = 'en'">  
11 - 英文  
12 - </a-button>  
13 - <Divider />  
14 - </div>  
15 -</template>  
16 -<script lang="ts">  
17 - import { defineComponent } from 'vue';  
18 - import { Alert, Divider } from 'ant-design-vue';  
19 -  
20 - import { useI18n } from '/@/hooks/web/useI18n';  
21 - export default defineComponent({  
22 - components: { Alert, Divider },  
23 - setup() {  
24 - const { t, localeRef } = useI18n({  
25 - locale: 'zhCN',  
26 - messages: {  
27 - en: {  
28 - hello: 'hello',  
29 - },  
30 - zhCN: {  
31 - hello: '你好',  
32 - },  
33 - },  
34 - });  
35 - return { localeRef, t };  
36 - },  
37 - });  
38 -</script>  
src/views/sys/error-log/DetailModal.vue
1 <template> 1 <template>
2 - <BasicModal :width="800" title="错误详情" v-bind="$attrs"> 2 + <BasicModal :width="800" :title="t('sys.errorLog.tableActionDesc')" v-bind="$attrs">
3 <Description :data="info" @register="register" /> 3 <Description :data="info" @register="register" />
4 </BasicModal> 4 </BasicModal>
5 </template> 5 </template>
6 <script lang="ts"> 6 <script lang="ts">
7 import { defineComponent, PropType } from 'vue'; 7 import { defineComponent, PropType } from 'vue';
  8 + import { useI18n } from 'vue-i18n';
  9 +
8 import { BasicModal } from '/@/components/Modal/index'; 10 import { BasicModal } from '/@/components/Modal/index';
9 import { ErrorInfo } from '/@/store/modules/error'; 11 import { ErrorInfo } from '/@/store/modules/error';
10 import { Description, useDescription } from '/@/components/Description/index'; 12 import { Description, useDescription } from '/@/components/Description/index';
  13 +
11 import { getDescSchema } from './data'; 14 import { getDescSchema } from './data';
12 15
13 export default defineComponent({ 16 export default defineComponent({
@@ -20,12 +23,15 @@ @@ -20,12 +23,15 @@
20 }, 23 },
21 }, 24 },
22 setup() { 25 setup() {
  26 + const { t } = useI18n();
23 const [register] = useDescription({ 27 const [register] = useDescription({
24 column: 2, 28 column: 2,
25 schema: getDescSchema(), 29 schema: getDescSchema(),
26 }); 30 });
27 return { 31 return {
28 register, 32 register,
  33 + useI18n,
  34 + t,
29 }; 35 };
30 }, 36 },
31 }); 37 });
src/views/sys/error-log/data.tsx
@@ -2,11 +2,15 @@ import { Tag } from &#39;ant-design-vue&#39;; @@ -2,11 +2,15 @@ import { Tag } from &#39;ant-design-vue&#39;;
2 import { BasicColumn } from '/@/components/Table/index'; 2 import { BasicColumn } from '/@/components/Table/index';
3 import { ErrorTypeEnum } from '/@/enums/exceptionEnum'; 3 import { ErrorTypeEnum } from '/@/enums/exceptionEnum';
4 4
  5 +import { useExternalI18n } from '/@/hooks/web/useLocale';
  6 +
  7 +const { t } = useExternalI18n();
  8 +
5 export function getColumns(): BasicColumn[] { 9 export function getColumns(): BasicColumn[] {
6 return [ 10 return [
7 { 11 {
8 dataIndex: 'type', 12 dataIndex: 'type',
9 - title: '类型', 13 + title: t('sys.errorLog.tableColumnType'),
10 width: 80, 14 width: 80,
11 customRender: ({ text }) => { 15 customRender: ({ text }) => {
12 const color = 16 const color =
@@ -24,17 +28,17 @@ export function getColumns(): BasicColumn[] { @@ -24,17 +28,17 @@ export function getColumns(): BasicColumn[] {
24 }, 28 },
25 { 29 {
26 dataIndex: 'url', 30 dataIndex: 'url',
27 - title: '地址', 31 + title: 'URL',
28 width: 200, 32 width: 200,
29 }, 33 },
30 { 34 {
31 dataIndex: 'time', 35 dataIndex: 'time',
32 - title: '时间', 36 + title: t('sys.errorLog.tableColumnDate'),
33 width: 160, 37 width: 160,
34 }, 38 },
35 { 39 {
36 dataIndex: 'file', 40 dataIndex: 'file',
37 - title: '文件', 41 + title: t('sys.errorLog.tableColumnFile'),
38 width: 200, 42 width: 200,
39 }, 43 },
40 { 44 {
@@ -44,12 +48,12 @@ export function getColumns(): BasicColumn[] { @@ -44,12 +48,12 @@ export function getColumns(): BasicColumn[] {
44 }, 48 },
45 { 49 {
46 dataIndex: 'message', 50 dataIndex: 'message',
47 - title: '错误信息', 51 + title: t('sys.errorLog.tableColumnMsg'),
48 width: 300, 52 width: 300,
49 }, 53 },
50 { 54 {
51 dataIndex: 'stack', 55 dataIndex: 'stack',
52 - title: 'stack信息', 56 + title: t('sys.errorLog.tableColumnStackMsg'),
53 width: 300, 57 width: 300,
54 }, 58 },
55 ]; 59 ];
src/views/sys/error-log/index.vue
@@ -6,12 +6,22 @@ @@ -6,12 +6,22 @@
6 <DetailModal :info="rowInfoRef" @register="registerModal" /> 6 <DetailModal :info="rowInfoRef" @register="registerModal" />
7 <BasicTable @register="register" class="error-handle-table"> 7 <BasicTable @register="register" class="error-handle-table">
8 <template #toolbar> 8 <template #toolbar>
9 - <a-button @click="fireVueError" type="primary"> 点击触发vue错误 </a-button>  
10 - <a-button @click="fireResourceError" type="primary"> 点击触发resource错误 </a-button>  
11 - <a-button @click="fireAjaxError" type="primary"> 点击触发ajax错误 </a-button> 9 + <a-button @click="fireVueError" type="primary">
  10 + {{ t('sys.errorLog.fireVueError') }}
  11 + </a-button>
  12 + <a-button @click="fireResourceError" type="primary">
  13 + {{ t('sys.errorLog.fireResourceError') }}
  14 + </a-button>
  15 + <a-button @click="fireAjaxError" type="primary">
  16 + {{ t('sys.errorLog.fireAjaxError') }}
  17 + </a-button>
12 </template> 18 </template>
13 <template #action="{ record }"> 19 <template #action="{ record }">
14 - <TableAction :actions="[{ label: '详情', onClick: handleDetail.bind(null, record) }]" /> 20 + <TableAction
  21 + :actions="[
  22 + { label: t('sys.errorLog.tableActionDesc'), onClick: handleDetail.bind(null, record) },
  23 + ]"
  24 + />
15 </template> 25 </template>
16 </BasicTable> 26 </BasicTable>
17 </div> 27 </div>
@@ -21,10 +31,11 @@ @@ -21,10 +31,11 @@
21 import { defineComponent, watch, ref, nextTick } from 'vue'; 31 import { defineComponent, watch, ref, nextTick } from 'vue';
22 32
23 import DetailModal from './DetailModal.vue'; 33 import DetailModal from './DetailModal.vue';
  34 + import { BasicTable, useTable, TableAction } from '/@/components/Table/index';
  35 +
24 import { useModal } from '/@/components/Modal/index'; 36 import { useModal } from '/@/components/Modal/index';
25 import { useMessage } from '/@/hooks/web/useMessage'; 37 import { useMessage } from '/@/hooks/web/useMessage';
26 -  
27 - import { BasicTable, useTable, TableAction } from '/@/components/Table/index'; 38 + import { useI18n } from 'vue-i18n';
28 39
29 import { errorStore, ErrorInfo } from '/@/store/modules/error'; 40 import { errorStore, ErrorInfo } from '/@/store/modules/error';
30 41
@@ -42,12 +53,14 @@ @@ -42,12 +53,14 @@
42 const rowInfoRef = ref<ErrorInfo>(); 53 const rowInfoRef = ref<ErrorInfo>();
43 const imgListRef = ref<string[]>([]); 54 const imgListRef = ref<string[]>([]);
44 55
  56 + const { t } = useI18n();
  57 +
45 const [register, { setTableData }] = useTable({ 58 const [register, { setTableData }] = useTable({
46 - title: '错误日志列表', 59 + title: t('sys.errorLog.tableTitle'),
47 columns: getColumns(), 60 columns: getColumns(),
48 actionColumn: { 61 actionColumn: {
49 width: 80, 62 width: 80,
50 - title: '操作', 63 + title: 'Action',
51 dataIndex: 'action', 64 dataIndex: 'action',
52 slots: { customRender: 'action' }, 65 slots: { customRender: 'action' },
53 }, 66 },
@@ -67,7 +80,7 @@ @@ -67,7 +80,7 @@
67 ); 80 );
68 const { createMessage } = useMessage(); 81 const { createMessage } = useMessage();
69 if (isDevMode()) { 82 if (isDevMode()) {
70 - createMessage.info('只在`/src/settings/projectSetting.ts` 内的useErrorHandle=true时生效!'); 83 + createMessage.info(t('sys.errorLog.enableMessage'));
71 } 84 }
72 // 查看详情 85 // 查看详情
73 function handleDetail(row: ErrorInfo) { 86 function handleDetail(row: ErrorInfo) {
@@ -96,6 +109,7 @@ @@ -96,6 +109,7 @@
96 fireAjaxError, 109 fireAjaxError,
97 imgListRef, 110 imgListRef,
98 rowInfoRef, 111 rowInfoRef,
  112 + t,
99 }; 113 };
100 }, 114 },
101 }); 115 });
src/views/sys/exception/Exception.tsx
@@ -12,6 +12,7 @@ import { useRoute } from &#39;vue-router&#39;; @@ -12,6 +12,7 @@ import { useRoute } from &#39;vue-router&#39;;
12 12
13 import { useGo, useRedo } from '/@/hooks/web/usePage'; 13 import { useGo, useRedo } from '/@/hooks/web/usePage';
14 import { PageEnum } from '/@/enums/pageEnum'; 14 import { PageEnum } from '/@/enums/pageEnum';
  15 +import { useI18n } from 'vue-i18n';
15 16
16 import './exception.less'; 17 import './exception.less';
17 interface MapValue { 18 interface MapValue {
@@ -47,9 +48,12 @@ export default defineComponent({ @@ -47,9 +48,12 @@ export default defineComponent({
47 }, 48 },
48 setup(props) { 49 setup(props) {
49 const statusMapRef = ref(new Map<string | number, MapValue>()); 50 const statusMapRef = ref(new Map<string | number, MapValue>());
  51 +
50 const { query } = useRoute(); 52 const { query } = useRoute();
51 const go = useGo(); 53 const go = useGo();
52 const redo = useRedo(); 54 const redo = useRedo();
  55 + const { t } = useI18n();
  56 +
53 const getStatus = computed(() => { 57 const getStatus = computed(() => {
54 const { status: routeStatus } = query; 58 const { status: routeStatus } = query;
55 const { status } = props; 59 const { status } = props;
@@ -62,41 +66,44 @@ export default defineComponent({ @@ -62,41 +66,44 @@ export default defineComponent({
62 } 66 }
63 ); 67 );
64 68
  69 + const backLoginI18n = t('sys.exception.backLogin');
  70 + const backHomeI18n = t('sys.exception.backHome');
  71 +
65 unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_ACCESS, { 72 unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_ACCESS, {
66 title: '403', 73 title: '403',
67 status: `${ExceptionEnum.PAGE_NOT_ACCESS}`, 74 status: `${ExceptionEnum.PAGE_NOT_ACCESS}`,
68 - subTitle: `Sorry, you don't have access to this page.!`,  
69 - btnText: props.full ? 'Back Login' : 'Back Home', 75 + subTitle: t('sys.exception.subTitle403'),
  76 + btnText: props.full ? backLoginI18n : backHomeI18n,
70 handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()), 77 handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()),
71 }); 78 });
72 79
73 unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_FOUND, { 80 unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_FOUND, {
74 title: '404', 81 title: '404',
75 status: `${ExceptionEnum.PAGE_NOT_FOUND}`, 82 status: `${ExceptionEnum.PAGE_NOT_FOUND}`,
76 - subTitle: `Sorry, the page you visited does not exist.`,  
77 - btnText: props.full ? 'Back Login' : 'Back Home', 83 + subTitle: t('sys.exception.subTitle404'),
  84 + btnText: props.full ? backLoginI18n : backHomeI18n,
78 handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()), 85 handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()),
79 }); 86 });
80 87
81 unref(statusMapRef).set(ExceptionEnum.ERROR, { 88 unref(statusMapRef).set(ExceptionEnum.ERROR, {
82 title: '500', 89 title: '500',
83 status: `${ExceptionEnum.ERROR}`, 90 status: `${ExceptionEnum.ERROR}`,
84 - subTitle: `Sorry, the server is reporting an error.`,  
85 - btnText: 'Back Home', 91 + subTitle: t('sys.exception.subTitle500'),
  92 + btnText: backHomeI18n,
86 handler: () => go(), 93 handler: () => go(),
87 }); 94 });
88 95
89 unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_DATA, { 96 unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_DATA, {
90 - title: 'No data on the current page', 97 + title: t('sys.exception.noDataTitle'),
91 subTitle: '', 98 subTitle: '',
92 - btnText: 'Refresh', 99 + btnText: t('sys.exception.redo'),
93 handler: () => redo(), 100 handler: () => redo(),
94 icon: notDataImg, 101 icon: notDataImg,
95 }); 102 });
96 103
97 unref(statusMapRef).set(ExceptionEnum.NET_WORK_ERROR, { 104 unref(statusMapRef).set(ExceptionEnum.NET_WORK_ERROR, {
98 - title: 'Network Error',  
99 - subTitle: 'Sorry,Your network connection has been disconnected, please check your network!', 105 + title: t('sys.exception.networkErrorTitle'),
  106 + subTitle: t('sys.exception.networkErrorSubTitle'),
100 btnText: 'Refresh', 107 btnText: 'Refresh',
101 handler: () => redo(), 108 handler: () => redo(),
102 icon: netWorkImg, 109 icon: netWorkImg,
src/views/sys/lock/index.vue
@@ -6,36 +6,38 @@ @@ -6,36 +6,38 @@
6 <p class="lock-page__header-name">{{ realName }}</p> 6 <p class="lock-page__header-name">{{ realName }}</p>
7 </div> 7 </div>
8 <BasicForm @register="register" v-if="!getIsNotPwd" /> 8 <BasicForm @register="register" v-if="!getIsNotPwd" />
9 - <Alert v-if="errMsgRef" type="error" message="锁屏密码错误" banner /> 9 + <Alert v-if="errMsgRef" type="error" :message="t('sys.lock.alert')" banner />
10 <div class="lock-page__footer"> 10 <div class="lock-page__footer">
11 <a-button type="default" class="mt-2 mr-2" @click="goLogin" v-if="!getIsNotPwd"> 11 <a-button type="default" class="mt-2 mr-2" @click="goLogin" v-if="!getIsNotPwd">
12 - 返回登录 12 + {{ t('sys.lock.backToLogin') }}
13 </a-button> 13 </a-button>
14 <a-button type="primary" class="mt-2" @click="unLock(!getIsNotPwd)" :loading="loadingRef"> 14 <a-button type="primary" class="mt-2" @click="unLock(!getIsNotPwd)" :loading="loadingRef">
15 - 进入系统 15 + {{ t('sys.lock.entry') }}
16 </a-button> 16 </a-button>
17 </div> 17 </div>
18 </div> 18 </div>
19 </div> 19 </div>
20 </template> 20 </template>
21 <script lang="ts"> 21 <script lang="ts">
22 - // 组件相关  
23 import { defineComponent, ref, computed } from 'vue'; 22 import { defineComponent, ref, computed } from 'vue';
24 import { Alert } from 'ant-design-vue'; 23 import { Alert } from 'ant-design-vue';
25 - // hook 24 +
26 import { BasicForm, useForm } from '/@/components/Form'; 25 import { BasicForm, useForm } from '/@/components/Form';
27 26
28 import { userStore } from '/@/store/modules/user'; 27 import { userStore } from '/@/store/modules/user';
29 import { appStore } from '/@/store/modules/app'; 28 import { appStore } from '/@/store/modules/app';
  29 +
  30 + import { useI18n } from 'vue-i18n';
  31 +
30 export default defineComponent({ 32 export default defineComponent({
31 name: 'LockPage', 33 name: 'LockPage',
32 components: { Alert, BasicForm }, 34 components: { Alert, BasicForm },
33 35
34 setup() { 36 setup() {
35 - // 获取配置文件  
36 - // 样式前缀  
37 const loadingRef = ref(false); 37 const loadingRef = ref(false);
38 const errMsgRef = ref(false); 38 const errMsgRef = ref(false);
  39 +
  40 + const { t } = useI18n();
39 const [register, { validateFields }] = useForm({ 41 const [register, { validateFields }] = useForm({
40 showActionButtonGroup: false, 42 showActionButtonGroup: false,
41 schemas: [ 43 schemas: [
@@ -45,7 +47,7 @@ @@ -45,7 +47,7 @@
45 component: 'InputPassword', 47 component: 'InputPassword',
46 componentProps: { 48 componentProps: {
47 style: { width: '100%' }, 49 style: { width: '100%' },
48 - placeholder: '请输入锁屏密码或者用户密码', 50 + placeholder: t('sys.lock.placeholder'),
49 }, 51 },
50 rules: [{ required: true }], 52 rules: [{ required: true }],
51 }, 53 },
@@ -55,6 +57,14 @@ @@ -55,6 +57,14 @@
55 const { realName } = userStore.getUserInfoState || {}; 57 const { realName } = userStore.getUserInfoState || {};
56 return realName; 58 return realName;
57 }); 59 });
  60 +
  61 + const getIsNotPwd = computed(() => {
  62 + if (!appStore.getLockInfo) {
  63 + return true;
  64 + }
  65 + return appStore.getLockInfo.pwd === undefined;
  66 + });
  67 +
58 /** 68 /**
59 * @description: unLock 69 * @description: unLock
60 */ 70 */
@@ -76,17 +86,12 @@ @@ -76,17 +86,12 @@
76 loadingRef.value = false; 86 loadingRef.value = false;
77 } 87 }
78 } 88 }
  89 +
79 function goLogin() { 90 function goLogin() {
80 userStore.loginOut(true); 91 userStore.loginOut(true);
81 appStore.resetLockInfo(); 92 appStore.resetLockInfo();
82 } 93 }
83 - const getIsNotPwd = computed(() => {  
84 - if (!appStore.getLockInfo) {  
85 - return true;  
86 - }  
87 - return appStore.getLockInfo.pwd === undefined;  
88 - });  
89 - // 账号密码登录 94 +
90 return { 95 return {
91 register, 96 register,
92 getIsNotPwd, 97 getIsNotPwd,
@@ -95,6 +100,7 @@ @@ -95,6 +100,7 @@
95 unLock, 100 unLock,
96 errMsgRef, 101 errMsgRef,
97 loadingRef, 102 loadingRef,
  103 + t,
98 }; 104 };
99 }, 105 },
100 }); 106 });
src/views/sys/login/Login.vue
@@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
4 <div class="login-form-wrap"> 4 <div class="login-form-wrap">
5 <div class="login-form mx-6"> 5 <div class="login-form mx-6">
6 <div class="login-form__content px-2 py-10"> 6 <div class="login-form__content px-2 py-10">
  7 + <AppLocalPicker class="login-form__locale" />
7 <header> 8 <header>
8 <img :src="logo" class="mr-4" /> 9 <img :src="logo" class="mr-4" />
9 <h1>{{ title }}</h1> 10 <h1>{{ title }}</h1>
@@ -29,13 +30,15 @@ @@ -29,13 +30,15 @@
29 <a-col :span="12"> 30 <a-col :span="12">
30 <a-form-item> 31 <a-form-item>
31 <!-- No logic, you need to deal with it yourself --> 32 <!-- No logic, you need to deal with it yourself -->
32 - <a-checkbox v-model:checked="autoLogin" size="small">自动登录</a-checkbox> 33 + <a-checkbox v-model:checked="autoLogin" size="small">{{
  34 + t('sys.login.autoLogin')
  35 + }}</a-checkbox>
33 </a-form-item> 36 </a-form-item>
34 </a-col> 37 </a-col>
35 <a-col :span="12"> 38 <a-col :span="12">
36 <a-form-item :style="{ 'text-align': 'right' }"> 39 <a-form-item :style="{ 'text-align': 'right' }">
37 <!-- No logic, you need to deal with it yourself --> 40 <!-- No logic, you need to deal with it yourself -->
38 - <a-button type="link" size="small">忘记密码</a-button> 41 + <a-button type="link" size="small">{{ t('sys.login.forgetPassword') }}</a-button>
39 </a-form-item> 42 </a-form-item>
40 </a-col> 43 </a-col>
41 </a-row> 44 </a-row>
@@ -47,7 +50,7 @@ @@ -47,7 +50,7 @@
47 :block="true" 50 :block="true"
48 @click="login" 51 @click="login"
49 :loading="formState.loading" 52 :loading="formState.loading"
50 - >{{ t('system.login.button') }}</a-button 53 + >{{ t('sys.login.loginButton') }}</a-button
51 > 54 >
52 </a-form-item> 55 </a-form-item>
53 </a-form> 56 </a-form>
@@ -61,6 +64,7 @@ @@ -61,6 +64,7 @@
61 import { Checkbox } from 'ant-design-vue'; 64 import { Checkbox } from 'ant-design-vue';
62 65
63 import Button from '/@/components/Button/index.vue'; 66 import Button from '/@/components/Button/index.vue';
  67 + import { AppLocalPicker } from '/@/components/Application';
64 // import { BasicDragVerify, DragVerifyActionType } from '/@/components/Verify/index'; 68 // import { BasicDragVerify, DragVerifyActionType } from '/@/components/Verify/index';
65 69
66 import { userStore } from '/@/store/modules/user'; 70 import { userStore } from '/@/store/modules/user';
@@ -68,7 +72,7 @@ @@ -68,7 +72,7 @@
68 72
69 // import { appStore } from '/@/store/modules/app'; 73 // import { appStore } from '/@/store/modules/app';
70 import { useMessage } from '/@/hooks/web/useMessage'; 74 import { useMessage } from '/@/hooks/web/useMessage';
71 - import { useSetting } from '/@/hooks/core/useSetting'; 75 + import { useGlobSetting } from '/@/settings/use';
72 import logo from '/@/assets/images/logo.png'; 76 import logo from '/@/assets/images/logo.png';
73 77
74 export default defineComponent({ 78 export default defineComponent({
@@ -76,14 +80,16 @@ @@ -76,14 +80,16 @@
76 // BasicDragVerify, 80 // BasicDragVerify,
77 AButton: Button, 81 AButton: Button,
78 ACheckbox: Checkbox, 82 ACheckbox: Checkbox,
  83 + AppLocalPicker,
79 }, 84 },
80 setup() { 85 setup() {
81 const formRef = ref<any>(null); 86 const formRef = ref<any>(null);
82 const autoLoginRef = ref(false); 87 const autoLoginRef = ref(false);
83 // const verifyRef = ref<RefInstanceType<DragVerifyActionType>>(null); 88 // const verifyRef = ref<RefInstanceType<DragVerifyActionType>>(null);
84 89
85 - const { globSetting } = useSetting(); 90 + const globSetting = useGlobSetting();
86 const { notification } = useMessage(); 91 const { notification } = useMessage();
  92 + const { t } = useI18n();
87 93
88 // const openLoginVerifyRef = computed(() => appStore.getProjectConfig.openLoginVerify); 94 // const openLoginVerifyRef = computed(() => appStore.getProjectConfig.openLoginVerify);
89 95
@@ -97,8 +103,10 @@ @@ -97,8 +103,10 @@
97 }); 103 });
98 104
99 const formRules = reactive({ 105 const formRules = reactive({
100 - account: [{ required: true, message: '请输入账号', trigger: 'blur' }],  
101 - password: [{ required: true, message: '请输入密码', trigger: 'blur' }], 106 + account: [{ required: true, message: t('sys.login.accountPlaceholder'), trigger: 'blur' }],
  107 + password: [
  108 + { required: true, message: t('sys.login.passwordPlaceholder'), trigger: 'blur' },
  109 + ],
102 // verify: unref(openLoginVerifyRef) ? [{ required: true, message: '请通过验证码校验' }] : [], 110 // verify: unref(openLoginVerifyRef) ? [{ required: true, message: '请通过验证码校验' }] : [],
103 }); 111 });
104 112
@@ -123,8 +131,8 @@ @@ -123,8 +131,8 @@
123 ); 131 );
124 if (userInfo) { 132 if (userInfo) {
125 notification.success({ 133 notification.success({
126 - message: '登录成功',  
127 - description: `欢迎回来: ${userInfo.realName}`, 134 + message: t('sys.login.loginSuccessTitle'),
  135 + description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realName}`,
128 duration: 3, 136 duration: 3,
129 }); 137 });
130 } 138 }
@@ -134,7 +142,6 @@ @@ -134,7 +142,6 @@
134 formState.loading = false; 142 formState.loading = false;
135 } 143 }
136 } 144 }
137 - const { t } = useI18n();  
138 return { 145 return {
139 formRef, 146 formRef,
140 // verifyRef, 147 // verifyRef,
@@ -195,7 +202,14 @@ @@ -195,7 +202,14 @@
195 .respond-to(xlarge, { width: 540px; right:0}); 202 .respond-to(xlarge, { width: 540px; right:0});
196 } 203 }
197 204
  205 + &__locale {
  206 + position: absolute;
  207 + top: 10px;
  208 + right: 10px;
  209 + }
  210 +
198 &__content { 211 &__content {
  212 + position: relative;
199 width: 100%; 213 width: 100%;
200 height: 100%; 214 height: 100%;
201 border: 1px solid #999; 215 border: 1px solid #999;
vite.config.ts
@@ -126,7 +126,12 @@ const viteConfig: UserConfig = { @@ -126,7 +126,12 @@ const viteConfig: UserConfig = {
126 }, 126 },
127 // The package will be recompiled using rollup, and the new package compiled into the esm module specification will be put into node_modules/.vite_opt_cache 127 // The package will be recompiled using rollup, and the new package compiled into the esm module specification will be put into node_modules/.vite_opt_cache
128 optimizeDeps: { 128 optimizeDeps: {
129 - include: ['echarts/map/js/china', 'ant-design-vue/es/locale/zh_CN', '@ant-design/icons-vue'], 129 + include: [
  130 + 'echarts/map/js/china',
  131 + 'ant-design-vue/es/locale/zh_CN',
  132 + 'ant-design-vue/es/locale/en_US',
  133 + '@ant-design/icons-vue',
  134 + ],
130 }, 135 },
131 136
132 // Local cross-domain proxy 137 // Local cross-domain proxy
yarn.lock
@@ -2926,6 +2926,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2: @@ -2926,6 +2926,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2:
2926 shebang-command "^2.0.0" 2926 shebang-command "^2.0.0"
2927 which "^2.0.1" 2927 which "^2.0.1"
2928 2928
  2929 +crypto-es@^1.2.6:
  2930 + version "1.2.6"
  2931 + resolved "https://registry.npmjs.org/crypto-es/-/crypto-es-1.2.6.tgz#468f3573a5d7b82e3b63b0004f55f905a6d3b12c"
  2932 + integrity sha512-PQnrovdr5ibmOxqAh/Vy+A30RokHom7kb9Z61EPwfASfbcJCrCG4+vNNegmebNVHiXvS7WjYpHDePxnE/biEbA==
  2933 +
2929 crypto-random-string@^1.0.0: 2934 crypto-random-string@^1.0.0:
2930 version "1.0.0" 2935 version "1.0.0"
2931 resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" 2936 resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"