Commit e5f8ce3fd8ec25c6fdb122867cd33e4e84a6f43f

Authored by vben
1 parent cedba37e

feat: multi-language layout

Showing 44 changed files with 504 additions and 386 deletions
mock/sys/user.ts
@@ -6,7 +6,7 @@ function createFakeUserList() { @@ -6,7 +6,7 @@ function createFakeUserList() {
6 { 6 {
7 userId: '1', 7 userId: '1',
8 username: 'vben', 8 username: 'vben',
9 - realName: 'Vben', 9 + realName: 'Vben Admin',
10 desc: 'manager', 10 desc: 'manager',
11 password: '123456', 11 password: '123456',
12 token: 'fakeToken1', 12 token: 'fakeToken1',
src/components/Application/index.ts
1 -import AppLocalPicker from './src/AppLocalPicker.vue'; 1 +import AppLocalePicker from './src/AppLocalePicker.vue';
2 import AppPageFooter from './src/AppPageFooter.vue'; 2 import AppPageFooter from './src/AppPageFooter.vue';
3 import AppLogo from './src/AppLogo.vue'; 3 import AppLogo from './src/AppLogo.vue';
4 import { withInstall } from '../util'; 4 import { withInstall } from '../util';
5 5
6 -export { AppLocalPicker, AppPageFooter, AppLogo }; 6 +export { AppLocalePicker, AppPageFooter, AppLogo };
7 7
8 -export default withInstall(AppLocalPicker, AppPageFooter, AppLogo); 8 +export default withInstall(AppLocalePicker, AppPageFooter, AppLogo);
src/components/Application/src/AppLocalPicker.vue renamed to src/components/Application/src/AppLocalePicker.vue
@@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
4 :dropMenuList="localeList" 4 :dropMenuList="localeList"
5 :selectedKeys="selectedKeys" 5 :selectedKeys="selectedKeys"
6 @menuEvent="handleMenuEvent" 6 @menuEvent="handleMenuEvent"
  7 + overlayClassName="app-locale-picker-overlay"
7 > 8 >
8 <span class="app-local-picker"> 9 <span class="app-local-picker">
9 <GlobalOutlined class="app-local-picker__icon" /> 10 <GlobalOutlined class="app-local-picker__icon" />
@@ -30,8 +31,12 @@ @@ -30,8 +31,12 @@
30 type: Boolean, 31 type: Boolean,
31 default: true, 32 default: true,
32 }, 33 },
  34 + reload: {
  35 + type: Boolean,
  36 + default: false,
  37 + },
33 }, 38 },
34 - setup() { 39 + setup(props) {
35 const { localeList } = useLocaleSetting(); 40 const { localeList } = useLocaleSetting();
36 const selectedKeys = ref<string[]>([]); 41 const selectedKeys = ref<string[]>([]);
37 42
@@ -50,6 +55,7 @@ @@ -50,6 +55,7 @@
50 function toggleLocale(lang: LocaleType | string) { 55 function toggleLocale(lang: LocaleType | string) {
51 changeLocale(lang as LocaleType); 56 changeLocale(lang as LocaleType);
52 selectedKeys.value = [lang as string]; 57 selectedKeys.value = [lang as string];
  58 + props.reload && location.reload();
53 } 59 }
54 60
55 function handleMenuEvent(menu: DropMenu) { 61 function handleMenuEvent(menu: DropMenu) {
@@ -61,7 +67,13 @@ @@ -61,7 +67,13 @@
61 }); 67 });
62 </script> 68 </script>
63 69
64 -<style lang="less" scoped> 70 +<style lang="less">
  71 + .app-locale-picker-overlay {
  72 + .ant-dropdown-menu-item {
  73 + min-width: 160px;
  74 + }
  75 + }
  76 +
65 .app-local-picker { 77 .app-local-picker {
66 display: flex; 78 display: flex;
67 align-items: center; 79 align-items: center;
src/components/Dropdown/src/Dropdown.tsx
  1 +import type { Trigger } from './types';
  2 +
1 import { defineComponent, computed, unref } from 'vue'; 3 import { defineComponent, computed, unref } from 'vue';
2 -import { Dropdown, Menu, Divider } from 'ant-design-vue'; 4 +import { Dropdown, Menu } from 'ant-design-vue';
3 5
4 import Icon from '/@/components/Icon/index'; 6 import Icon from '/@/components/Icon/index';
5 7
6 import { basicDropdownProps } from './props'; 8 import { basicDropdownProps } from './props';
7 import { getSlot } from '/@/utils/helper/tsxHelper'; 9 import { getSlot } from '/@/utils/helper/tsxHelper';
8 -import { Trigger } from './types';  
9 10
10 export default defineComponent({ 11 export default defineComponent({
11 name: 'Dropdown', 12 name: 'Dropdown',
@@ -24,7 +25,7 @@ export default defineComponent({ @@ -24,7 +25,7 @@ export default defineComponent({
24 <Menu onClick={handleClickMenu} selectedKeys={props.selectedKeys}> 25 <Menu onClick={handleClickMenu} selectedKeys={props.selectedKeys}>
25 {() => ( 26 {() => (
26 <> 27 <>
27 - {unref(getMenuList).map((item, index) => { 28 + {unref(getMenuList).map((item) => {
28 const { disabled, icon, text, divider, event } = item; 29 const { disabled, icon, text, divider, event } = item;
29 return [ 30 return [
30 <Menu.Item key={`${event}`} disabled={disabled}> 31 <Menu.Item key={`${event}`} disabled={disabled}>
@@ -35,7 +36,8 @@ export default defineComponent({ @@ -35,7 +36,8 @@ export default defineComponent({
35 </> 36 </>
36 )} 37 )}
37 </Menu.Item>, 38 </Menu.Item>,
38 - divider && <Divider key={`d-${index}`} />, 39 + // @ts-ignore
  40 + divider && <Menu.Divider key={`d-${event}`} />,
39 ]; 41 ];
40 })} 42 })}
41 </> 43 </>
src/design/ant/index.less
@@ -13,20 +13,17 @@ @@ -13,20 +13,17 @@
13 } 13 }
14 } 14 }
15 15
16 -// .ant-form-item-label {  
17 -// text-align: unset;  
18 -// }  
19 -  
20 // ================================= 16 // =================================
21 // ==============descriptions======= 17 // ==============descriptions=======
22 // ================================= 18 // =================================
23 -.ant-descriptions-bordered .ant-descriptions-item-label {  
24 - background-color: @background-color-light;  
25 -} 19 +// .ant-descriptions-bordered .ant-descriptions-item-label {
  20 +// background-color: @background-color-light;
  21 +// }
  22 +
  23 +// .ant-descriptions .ant-descriptions-item-content {
  24 +// color: @text-color-call-out;
  25 +// }
26 26
27 -.ant-descriptions .ant-descriptions-item-content {  
28 - color: @text-color-call-out;  
29 -}  
30 // ================================= 27 // =================================
31 // ==============modal message====== 28 // ==============modal message======
32 // ================================= 29 // =================================
@@ -46,68 +43,6 @@ @@ -46,68 +43,6 @@
46 color: @primary-color !important; 43 color: @primary-color !important;
47 } 44 }
48 45
49 -.ant-modal-mask {  
50 - background-color: rgba(0, 0, 0, 0.2);  
51 -}  
52 -// =================================  
53 -// ==============menu===============  
54 -// =================================  
55 -.ant-menu-item {  
56 - &-selected {  
57 - a {  
58 - color: @primary-color;  
59 -  
60 - &:hover {  
61 - color: @primary-color;  
62 - }  
63 - }  
64 - }  
65 -}  
66 -// =================================  
67 -// ==============dropdown===========  
68 -// =================================  
69 -.ant-dropdown {  
70 - .ant-divider {  
71 - margin: 4px 0;  
72 - }  
73 -  
74 - &-menu-item {  
75 - line-height: 30px;  
76 - color: @text-color-call-out;  
77 -  
78 - &:hover {  
79 - color: inherit;  
80 - background-color: @border-color-shallow-light;  
81 - }  
82 - }  
83 -}  
84 -// =================================  
85 -// ==============back-top===========  
86 -// =================================  
87 -.ant-back-top {  
88 - right: 50px;  
89 - bottom: 60px;  
90 -}  
91 -// =================================  
92 -// ==============calendar===========  
93 -// =================================  
94 -.ant-calendar-picker {  
95 - width: 100%;  
96 -}  
97 -// =================================  
98 -// ==============tooltip============  
99 -// =================================  
100 -  
101 -.ant-tooltip {  
102 - &-inner {  
103 - padding: 6px 16px;  
104 - line-height: 20px;  
105 - color: @white;  
106 - background: @text-color-base;  
107 - border-radius: 4px;  
108 - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);  
109 - }  
110 -}  
111 // ================================= 46 // =================================
112 // ==============form=============== 47 // ==============form===============
113 // ================================= 48 // =================================
src/design/ant/input.less
@@ -5,24 +5,9 @@ @@ -5,24 +5,9 @@
5 .ant-input { 5 .ant-input {
6 &-number { 6 &-number {
7 min-width: 110px; 7 min-width: 110px;
8 - border-color: @border-color-shallow-dark;  
9 } 8 }
10 } 9 }
11 10
12 -.ant-input-affix-wrapper:hover .ant-input:not(.ant-input-disabled) {  
13 - border-color: @info-color;  
14 -}  
15 -  
16 -.ant-input-disabled,  
17 -.ant-select-disabled .ant-select-selection,  
18 -.ant-cascader-picker-label {  
19 - color: @text-color-base !important;  
20 -}  
21 -  
22 -.ant-input-disabled {  
23 - background-color: @background-color-light;  
24 -}  
25 -  
26 .ant-input-affix-wrapper .ant-input-suffix { 11 .ant-input-affix-wrapper .ant-input-suffix {
27 right: 9px; 12 right: 9px;
28 } 13 }
src/design/color.less
@@ -13,6 +13,9 @@ @@ -13,6 +13,9 @@
13 } 13 }
14 14
15 @white: #fff; 15 @white: #fff;
  16 +
  17 +@content-bg: #f0f2f5;
  18 +
16 @info-color: @primary-color; 19 @info-color: @primary-color;
17 20
18 @basic-mask-color: fade(@white, 30%); 21 @basic-mask-color: fade(@white, 30%);
@@ -24,7 +27,7 @@ @@ -24,7 +27,7 @@
24 @iconify-bg-color: #5551; 27 @iconify-bg-color: #5551;
25 28
26 // ================================= 29 // =================================
27 -// ==============border-color============ 30 +// ==============border-color=======
28 // ================================= 31 // =================================
29 32
30 // Dark-dark 33 // Dark-dark
src/design/index.less
@@ -54,8 +54,7 @@ input::-ms-reveal { @@ -54,8 +54,7 @@ input::-ms-reveal {
54 } 54 }
55 55
56 body { 56 body {
57 - // font-family: 'Microsoft YaHei,微软雅黑,Arial,sans-serif,Helvetica Neue,Helvetica,Pingfang SC,Hiragino Sans GB';  
58 - font-family: '-apple-system,BlinkMacSystemFont,segoe ui,Roboto,helvetica neue,Arial,noto sans,sans-serif,apple color emoji,segoe ui emoji,segoe ui symbol,noto color emoji'; 57 + font-family: 'BlinkMacSystemFont,segoe ui,Microsoft YaHei,Arial,sans-serif,Helvetica Neue,Helvetica,Pingfang SC,Hiragino Sans GB,Roboto,helvetica neue,Arial,noto sans,sans-serif,apple color emoji,segoe ui emoji,segoe ui symbol,noto color emoji';
59 font-style: normal; 58 font-style: normal;
60 font-weight: normal; 59 font-weight: normal;
61 line-height: 1.428571429; // 20/14 60 line-height: 1.428571429; // 20/14
@@ -159,17 +158,3 @@ embed, @@ -159,17 +158,3 @@ embed,
159 object { 158 object {
160 vertical-align: baseline !important; 159 vertical-align: baseline !important;
161 } 160 }
162 -  
163 -#app {  
164 - width: 100%;  
165 - height: 100%;  
166 -}  
167 -  
168 -.ant-layout {  
169 - background: #f0f2f5;  
170 -  
171 - // &-content {  
172 - // position: relative;  
173 - // overflow: hidden;  
174 - // }  
175 -}  
src/design/mixins.less
@@ -16,33 +16,33 @@ @@ -16,33 +16,33 @@
16 color: @color; 16 color: @color;
17 } 17 }
18 } 18 }
19 -// 文本截断 19 +// Text truncation
20 .text-truncate() { 20 .text-truncate() {
21 overflow: hidden; 21 overflow: hidden;
22 text-overflow: ellipsis; 22 text-overflow: ellipsis;
23 white-space: nowrap; 23 white-space: nowrap;
24 } 24 }
25 25
26 -/* 强制不换行 */ 26 +/* Force no line break */
27 .word-nowrap() { 27 .word-nowrap() {
28 word-wrap: normal; 28 word-wrap: normal;
29 white-space: nowrap; 29 white-space: nowrap;
30 } 30 }
31 31
32 -/* 强制换行 */ 32 +/* Force line break */
33 .break-all() { 33 .break-all() {
34 word-break: break-all; 34 word-break: break-all;
35 word-wrap: break-word; 35 word-wrap: break-word;
36 white-space: normal; 36 white-space: normal;
37 } 37 }
38 38
39 -// 禁止选中 39 +// Prohibit selection
40 .unselect() { 40 .unselect() {
41 cursor: pointer; 41 cursor: pointer;
42 user-select: none; 42 user-select: none;
43 } 43 }
44 44
45 -/* 适用于webkit内核和移动端 */ 45 +/* Suitable for webkit core and mobile */
46 .ellipsis-multiple(@num: 1) { 46 .ellipsis-multiple(@num: 1) {
47 display: -webkit-box; 47 display: -webkit-box;
48 overflow: hidden; 48 overflow: hidden;
src/design/public.less
  1 +#app {
  2 + width: 100%;
  3 + height: 100%;
  4 +}
  5 +
1 .app-svg-loading { 6 .app-svg-loading {
2 position: relative; 7 position: relative;
3 width: auto; 8 width: auto;
4 } 9 }
5 10
  11 +// =================================
  12 +// ==============scrollbar==========
  13 +// =================================
6 ::-webkit-scrollbar { 14 ::-webkit-scrollbar {
7 width: 6px; 15 width: 6px;
8 height: 6px; 16 height: 6px;
src/design/reset.less deleted 100644 → 0
1 -@import 'var/link';  
2 -@import './mixins/reset-text.less';  
3 -@import 'color/index';  
4 -.reset() {  
5 - html,  
6 - body {  
7 - width: 100%;  
8 - height: 100%;  
9 -  
10 - &.color-weak {  
11 - filter: invert(80%);  
12 - }  
13 -  
14 - &.gray-mode {  
15 - filter: grayscale(100%);  
16 - filter: progid:dximagetransform.microsoft.basicimage(grayscale=1);  
17 - }  
18 - }  
19 -  
20 - input::-ms-clear,  
21 - input::-ms-reveal {  
22 - display: none;  
23 - }  
24 -  
25 - body {  
26 - .reset-text();  
27 - }  
28 -  
29 - h1,  
30 - h2,  
31 - h3,  
32 - h4,  
33 - h5,  
34 - h6 {  
35 - margin-top: 0;  
36 - margin-bottom: 0.5em;  
37 - font-weight: 500;  
38 - color: @heading-color;  
39 - }  
40 -  
41 - ul,  
42 - ol {  
43 - list-style: none;  
44 - }  
45 -  
46 - li {  
47 - list-style-type: none;  
48 - }  
49 -  
50 - img {  
51 - vertical-align: top;  
52 - border: 0;  
53 - }  
54 -  
55 - table {  
56 - border-collapse: collapse;  
57 - border-spacing: 0;  
58 - }  
59 -  
60 - a:focus,  
61 - a:active {  
62 - outline: none;  
63 - }  
64 -  
65 - i,  
66 - em {  
67 - font-style: normal;  
68 - }  
69 -  
70 - div:focus {  
71 - outline: none;  
72 - }  
73 -  
74 - a {  
75 - color: @link-color;  
76 - text-decoration: @link-decoration;  
77 - cursor: pointer;  
78 - background-color: transparent; // remove the gray background on active links in IE 10.  
79 - outline: none;  
80 - transition: color 0.3s;  
81 - -webkit-text-decoration-skip: objects; // remove gaps in links underline in iOS 8+ and Safari 8+.  
82 -  
83 - &:hover {  
84 - color: @link-hover-color;  
85 - }  
86 -  
87 - &:active {  
88 - color: @link-active-color;  
89 - }  
90 -  
91 - &:active,  
92 - &:hover {  
93 - text-decoration: @link-hover-decoration;  
94 - outline: 0;  
95 - }  
96 -  
97 - &[disabled] {  
98 - color: @disabled-color;  
99 - pointer-events: none;  
100 - cursor: not-allowed;  
101 - }  
102 - }  
103 -}  
src/design/transition/base.less
1 .transition-default() { 1 .transition-default() {
2 &-enter-active, 2 &-enter-active,
3 &-leave-active { 3 &-leave-active {
4 - transition: 0.1s cubic-bezier(0.25, 0.8, 0.5, 1) !important; 4 + transition: 0.3s cubic-bezier(0.25, 0.8, 0.5, 1) !important;
5 } 5 }
6 6
7 &-move { 7 &-move {
8 - transition: transform 0.2s; 8 + transition: transform 0.4s;
9 } 9 }
10 } 10 }
11 11
src/design/transition/fade.less
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 /* fade-slide */ 11 /* fade-slide */
12 .fade-slide-leave-active, 12 .fade-slide-leave-active,
13 .fade-slide-enter-active { 13 .fade-slide-enter-active {
14 - transition: all 0.2s; 14 + transition: all 0.3s;
15 } 15 }
16 16
17 .fade-slide-enter-from { 17 .fade-slide-enter-from {
src/design/var/index.less
@@ -13,6 +13,7 @@ @@ -13,6 +13,7 @@
13 13
14 // 14 //
15 @side-drag-z-index: 200; 15 @side-drag-z-index: 200;
  16 +
16 @page-loading-z-index: 10000; 17 @page-loading-z-index: 10000;
17 18
18 // left-menu 19 // left-menu
src/hooks/setting/useLocaleSetting.ts
@@ -19,10 +19,20 @@ export function useLocaleSetting() { @@ -19,10 +19,20 @@ export function useLocaleSetting() {
19 // get Fallback Locales 19 // get Fallback Locales
20 const getFallbackLocale = computed((): string => unref(getLocale).fallback); 20 const getFallbackLocale = computed((): string => unref(getLocale).fallback);
21 21
  22 + const getShowLocale = computed(() => unref(getLocale).show);
  23 +
22 // Set locale configuration 24 // Set locale configuration
23 function setLocale(locale: Partial<LocaleSetting>): void { 25 function setLocale(locale: Partial<LocaleSetting>): void {
24 appStore.commitProjectConfigState({ locale }); 26 appStore.commitProjectConfigState({ locale });
25 } 27 }
26 28
27 - return { getLocale, getLang, localeList, setLocale, getAvailableLocales, getFallbackLocale }; 29 + return {
  30 + getLocale,
  31 + getLang,
  32 + localeList,
  33 + setLocale,
  34 + getShowLocale,
  35 + getAvailableLocales,
  36 + getFallbackLocale,
  37 + };
28 } 38 }
src/hooks/web/useI18n.ts 0 → 100644
  1 +import { getI18n } from '/@/setup/i18n';
  2 +
  3 +export function useI18n(namespace?: string) {
  4 + const { t, ...methods } = getI18n().global;
  5 +
  6 + function getKey(key: string) {
  7 + if (!namespace) {
  8 + return key;
  9 + }
  10 + if (key.startsWith(namespace)) {
  11 + return key;
  12 + }
  13 + return `${namespace}.${key}`;
  14 + }
  15 + return {
  16 + ...methods,
  17 + t: (key: string, ...arg: Parameters<typeof t>) => {
  18 + return t(getKey(key), ...arg);
  19 + },
  20 + };
  21 +}
src/hooks/web/useLocale.ts
@@ -65,10 +65,3 @@ export function useLocale() { @@ -65,10 +65,3 @@ export function useLocale() {
65 antConfigLocale: antConfigLocaleRef, 65 antConfigLocale: antConfigLocaleRef,
66 }; 66 };
67 } 67 }
68 -  
69 -/**  
70 - * For non-setup setting  
71 - */  
72 -export function useExternalI18n() {  
73 - return getI18n().global;  
74 -}  
src/layouts/default/footer/index.tsx
@@ -8,18 +8,21 @@ import { GithubFilled } from &#39;@ant-design/icons-vue&#39;; @@ -8,18 +8,21 @@ import { GithubFilled } from &#39;@ant-design/icons-vue&#39;;
8 import { DOC_URL, GITHUB_URL, SITE_URL } from '/@/settings/siteSetting'; 8 import { DOC_URL, GITHUB_URL, SITE_URL } from '/@/settings/siteSetting';
9 import { openWindow } from '/@/utils'; 9 import { openWindow } from '/@/utils';
10 10
  11 +import { useI18n } from '/@/hooks/web/useI18n';
  12 +
11 export default defineComponent({ 13 export default defineComponent({
12 name: 'LayoutContent', 14 name: 'LayoutContent',
13 setup() { 15 setup() {
  16 + const { t } = useI18n('layout.footer');
14 return () => { 17 return () => {
15 return ( 18 return (
16 <Layout.Footer class="layout-footer"> 19 <Layout.Footer class="layout-footer">
17 {() => ( 20 {() => (
18 <> 21 <>
19 <div class="layout-footer__links"> 22 <div class="layout-footer__links">
20 - <a onClick={() => openWindow(SITE_URL)}>在线预览</a> 23 + <a onClick={() => openWindow(SITE_URL)}>{t('onlinePreview')}</a>
21 <GithubFilled onClick={() => openWindow(GITHUB_URL)} class="github" /> 24 <GithubFilled onClick={() => openWindow(GITHUB_URL)} class="github" />
22 - <a onClick={() => openWindow(DOC_URL)}>在线文档</a> 25 + <a onClick={() => openWindow(DOC_URL)}>{t('onlineDocument')}</a>
23 </div> 26 </div>
24 <div>Copyright &copy;2020 Vben Admin</div> 27 <div>Copyright &copy;2020 Vben Admin</div>
25 </> 28 </>
src/layouts/default/header/LayoutHeader.tsx
1 import './index.less'; 1 import './index.less';
2 2
3 import type { FunctionalComponent } from 'vue'; 3 import type { FunctionalComponent } from 'vue';
  4 +import type { Component } from '/@/components/types';
4 5
5 import { defineComponent, unref, computed, ref, nextTick } from 'vue'; 6 import { defineComponent, unref, computed, ref, nextTick } from 'vue';
6 7
@@ -27,6 +28,7 @@ import { useWindowSizeFn } from &#39;/@/hooks/event/useWindowSizeFn&#39;; @@ -27,6 +28,7 @@ import { useWindowSizeFn } from &#39;/@/hooks/event/useWindowSizeFn&#39;;
27 import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'; 28 import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
28 import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; 29 import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
29 import { useRootSetting } from '/@/hooks/setting/useRootSetting'; 30 import { useRootSetting } from '/@/hooks/setting/useRootSetting';
  31 +import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting';
30 32
31 import { useRouter } from 'vue-router'; 33 import { useRouter } from 'vue-router';
32 34
@@ -34,7 +36,8 @@ import { errorStore } from &#39;/@/store/modules/error&#39;; @@ -34,7 +36,8 @@ import { errorStore } from &#39;/@/store/modules/error&#39;;
34 36
35 import { PageEnum } from '/@/enums/pageEnum'; 37 import { PageEnum } from '/@/enums/pageEnum';
36 import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum'; 38 import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
37 -import { Component } from '/@/components/types'; 39 +import { AppLocalePicker } from '/@/components/Application';
  40 +import { useI18n } from '/@/hooks/web/useI18n';
38 41
39 interface TooltipItemProps { 42 interface TooltipItemProps {
40 title: string; 43 title: string;
@@ -65,9 +68,11 @@ export default defineComponent({ @@ -65,9 +68,11 @@ export default defineComponent({
65 const logoWidthRef = ref(200); 68 const logoWidthRef = ref(200);
66 const logoRef = ref<ComponentRef>(null); 69 const logoRef = ref<ComponentRef>(null);
67 const { refreshPage } = useTabs(); 70 const { refreshPage } = useTabs();
  71 + const { t } = useI18n('layout.header');
68 72
69 const { getShowTopMenu, getShowHeaderTrigger, getSplit, getTopMenuAlign } = useMenuSetting(); 73 const { getShowTopMenu, getShowHeaderTrigger, getSplit, getTopMenuAlign } = useMenuSetting();
70 74
  75 + const { getShowLocale } = useLocaleSetting();
71 const { getUseErrorHandle, getShowBreadCrumbIcon } = useRootSetting(); 76 const { getUseErrorHandle, getShowBreadCrumbIcon } = useRootSetting();
72 77
73 const { 78 const {
@@ -160,8 +165,8 @@ export default defineComponent({ @@ -160,8 +165,8 @@ export default defineComponent({
160 165
161 function renderActionDefault(Comp: Component | any, event: Fn) { 166 function renderActionDefault(Comp: Component | any, event: Fn) {
162 return ( 167 return (
163 - <div class={`layout-header__action-item`} onClick={event}>  
164 - <Comp class={`layout-header__action-icon`} /> 168 + <div class="layout-header__action-item" onClick={event}>
  169 + <Comp class="layout-header__action-icon" />
165 </div> 170 </div>
166 ); 171 );
167 } 172 }
@@ -170,7 +175,7 @@ export default defineComponent({ @@ -170,7 +175,7 @@ export default defineComponent({
170 return ( 175 return (
171 <div class={`layout-header__action`}> 176 <div class={`layout-header__action`}>
172 {unref(getUseErrorHandle) && ( 177 {unref(getUseErrorHandle) && (
173 - <TooltipItem title="错误日志"> 178 + <TooltipItem title={t('layout.header.tooltipErrorLog')}>
174 {() => ( 179 {() => (
175 <Badge 180 <Badge
176 count={errorStore.getErrorListCountState} 181 count={errorStore.getErrorListCountState}
@@ -185,23 +190,31 @@ export default defineComponent({ @@ -185,23 +190,31 @@ export default defineComponent({
185 )} 190 )}
186 191
187 {unref(getUseLockPage) && ( 192 {unref(getUseLockPage) && (
188 - <TooltipItem title="锁定屏幕"> 193 + <TooltipItem title={t('layout.header.tooltipLock')}>
189 {() => renderActionDefault(LockOutlined, handleLockPage)} 194 {() => renderActionDefault(LockOutlined, handleLockPage)}
190 </TooltipItem> 195 </TooltipItem>
191 )} 196 )}
192 197
193 {unref(getShowNotice) && ( 198 {unref(getShowNotice) && (
194 - <TooltipItem title="消息通知">{() => <NoticeAction />}</TooltipItem> 199 + <TooltipItem title={t('layout.header.tooltipNotify')}>
  200 + {() => <NoticeAction />}
  201 + </TooltipItem>
195 )} 202 )}
196 203
197 {unref(getShowRedo) && ( 204 {unref(getShowRedo) && (
198 - <TooltipItem title="刷新"> 205 + <TooltipItem title={t('layout.header.tooltipRedo')}>
199 {() => renderActionDefault(RedoOutlined, refreshPage)} 206 {() => renderActionDefault(RedoOutlined, refreshPage)}
200 </TooltipItem> 207 </TooltipItem>
201 )} 208 )}
202 209
203 {unref(getShowFullScreen) && ( 210 {unref(getShowFullScreen) && (
204 - <TooltipItem title={unref(isFullscreenRef) ? '退出全屏' : '全屏'}> 211 + <TooltipItem
  212 + title={
  213 + unref(isFullscreenRef)
  214 + ? t('layout.header.tooltipExitFull')
  215 + : t('layout.header.tooltipEntryFull')
  216 + }
  217 + >
205 {() => { 218 {() => {
206 const Icon = !unref(isFullscreenRef) ? ( 219 const Icon = !unref(isFullscreenRef) ? (
207 <FullscreenOutlined /> 220 <FullscreenOutlined />
@@ -212,7 +225,14 @@ export default defineComponent({ @@ -212,7 +225,14 @@ export default defineComponent({
212 }} 225 }}
213 </TooltipItem> 226 </TooltipItem>
214 )} 227 )}
215 - <UserDropdown class={`layout-header__user-dropdown`} /> 228 + <UserDropdown class="layout-header__user-dropdown" />
  229 + {unref(getShowLocale) && (
  230 + <AppLocalePicker
  231 + reload={true}
  232 + showText={false}
  233 + class="layout-header__action-item locale"
  234 + />
  235 + )}
216 </div> 236 </div>
217 ); 237 );
218 } 238 }
src/layouts/default/header/UserDropdown.tsx
1 // components 1 // components
2 -import { Dropdown, Menu, Divider } from 'ant-design-vue'; 2 +import { Dropdown, Menu } from 'ant-design-vue';
3 3
4 import { defineComponent, computed, unref } from 'vue'; 4 import { defineComponent, computed, unref } from 'vue';
5 5
@@ -16,6 +16,7 @@ import { openWindow } from &#39;/@/utils&#39;; @@ -16,6 +16,7 @@ import { openWindow } from &#39;/@/utils&#39;;
16 16
17 import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'; 17 import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
18 import { FunctionalComponent } from 'vue'; 18 import { FunctionalComponent } from 'vue';
  19 +import { useI18n } from '/@/hooks/web/useI18n';
19 20
20 type MenuEvent = 'loginOut' | 'doc'; 21 type MenuEvent = 'loginOut' | 'doc';
21 interface MenuItemProps { 22 interface MenuItemProps {
@@ -43,6 +44,7 @@ const MenuItem: FunctionalComponent&lt;MenuItemProps&gt; = (props) =&gt; { @@ -43,6 +44,7 @@ const MenuItem: FunctionalComponent&lt;MenuItemProps&gt; = (props) =&gt; {
43 export default defineComponent({ 44 export default defineComponent({
44 name: 'UserDropdown', 45 name: 'UserDropdown',
45 setup() { 46 setup() {
  47 + const { t } = useI18n('layout.header');
46 const { getShowDoc } = useHeaderSetting(); 48 const { getShowDoc } = useHeaderSetting();
47 49
48 const getUserInfo = computed(() => { 50 const getUserInfo = computed(() => {
@@ -89,9 +91,14 @@ export default defineComponent({ @@ -89,9 +91,14 @@ export default defineComponent({
89 <Menu onClick={handleMenuClick}> 91 <Menu onClick={handleMenuClick}>
90 {() => ( 92 {() => (
91 <> 93 <>
92 - {showDoc && <MenuItem key="doc" text="文档" icon="gg:loadbar-doc" />}  
93 - {showDoc && <Divider />}  
94 - <MenuItem key="loginOut" text="退出系统" icon="ant-design:poweroff-outlined" /> 94 + {showDoc && <MenuItem key="doc" text={t('dropdownItemDoc')} icon="gg:loadbar-doc" />}
  95 + {/* @ts-ignore */}
  96 + {showDoc && <Menu.Divider />}
  97 + <MenuItem
  98 + key="loginOut"
  99 + text={t('dropdownItemLoginOut')}
  100 + icon="ant-design:poweroff-outlined"
  101 + />
95 </> 102 </>
96 )} 103 )}
97 </Menu> 104 </Menu>
@@ -100,7 +107,7 @@ export default defineComponent({ @@ -100,7 +107,7 @@ export default defineComponent({
100 107
101 return () => { 108 return () => {
102 return ( 109 return (
103 - <Dropdown placement="bottomLeft"> 110 + <Dropdown placement="bottomLeft" overlayClassName="app-layout-header-user-dropdown-overlay">
104 {{ 111 {{
105 default: () => renderSlotsDefault(), 112 default: () => renderSlotsDefault(),
106 overlay: () => renderSlotOverlay(), 113 overlay: () => renderSlotOverlay(),
src/layouts/default/header/index.less
@@ -92,6 +92,11 @@ @@ -92,6 +92,11 @@
92 &:hover { 92 &:hover {
93 background: @header-light-bg-hover-color; 93 background: @header-light-bg-hover-color;
94 } 94 }
  95 +
  96 + &.locale {
  97 + padding: 0 10px;
  98 + color: rgba(0, 0, 0, 0.65);
  99 + }
95 } 100 }
96 101
97 &-icon { 102 &-icon {
@@ -221,3 +226,9 @@ @@ -221,3 +226,9 @@
221 } 226 }
222 } 227 }
223 } 228 }
  229 +
  230 +.app-layout-header-user-dropdown-overlay {
  231 + .ant-dropdown-menu-item {
  232 + min-width: 160px;
  233 + }
  234 +}
src/layouts/default/index.less
@@ -2,9 +2,10 @@ @@ -2,9 +2,10 @@
2 2
3 .default-layout { 3 .default-layout {
4 display: flex; 4 display: flex;
5 - flex-direction: column;  
6 width: 100%; 5 width: 100%;
7 min-height: 100%; 6 min-height: 100%;
  7 + background: @content-bg;
  8 + flex-direction: column;
8 9
9 > .ant-layout { 10 > .ant-layout {
10 min-height: 100%; 11 min-height: 100%;
src/layouts/default/lock/LockAction.tsx
@@ -9,11 +9,13 @@ import headerImg from &#39;/@/assets/images/header.jpg&#39;; @@ -9,11 +9,13 @@ import headerImg from &#39;/@/assets/images/header.jpg&#39;;
9 9
10 import { appStore } from '/@/store/modules/app'; 10 import { appStore } from '/@/store/modules/app';
11 import { userStore } from '/@/store/modules/user'; 11 import { userStore } from '/@/store/modules/user';
  12 +import { useI18n } from '/@/hooks/web/useI18n';
12 13
13 const prefixCls = 'lock-modal'; 14 const prefixCls = 'lock-modal';
14 export default defineComponent({ 15 export default defineComponent({
15 name: 'LockModal', 16 name: 'LockModal',
16 setup(_, { attrs }) { 17 setup(_, { attrs }) {
  18 + const { t } = useI18n('layout.header');
17 const [register, { closeModal }] = useModalInner(); 19 const [register, { closeModal }] = useModalInner();
18 20
19 const [registerForm, { validateFields, resetFields }] = useForm({ 21 const [registerForm, { validateFields, resetFields }] = useForm({
@@ -21,7 +23,7 @@ export default defineComponent({ @@ -21,7 +23,7 @@ export default defineComponent({
21 schemas: [ 23 schemas: [
22 { 24 {
23 field: 'password', 25 field: 'password',
24 - label: '锁屏密码', 26 + label: t('lockScreenPassword'),
25 component: 'InputPassword', 27 component: 'InputPassword',
26 required: true, 28 required: true,
27 }, 29 },
@@ -49,7 +51,13 @@ export default defineComponent({ @@ -49,7 +51,13 @@ export default defineComponent({
49 } 51 }
50 52
51 return () => ( 53 return () => (
52 - <BasicModal footer={null} title="锁定屏幕" {...attrs} class={prefixCls} onRegister={register}> 54 + <BasicModal
  55 + footer={null}
  56 + title={t('lockScreen')}
  57 + {...attrs}
  58 + class={prefixCls}
  59 + onRegister={register}
  60 + >
53 {() => ( 61 {() => (
54 <div class={`${prefixCls}__entry`}> 62 <div class={`${prefixCls}__entry`}>
55 <div class={`${prefixCls}__header`}> 63 <div class={`${prefixCls}__header`}>
@@ -61,10 +69,10 @@ export default defineComponent({ @@ -61,10 +69,10 @@ export default defineComponent({
61 69
62 <div class={`${prefixCls}__footer`}> 70 <div class={`${prefixCls}__footer`}>
63 <Button type="primary" block class="mt-2" onClick={lock}> 71 <Button type="primary" block class="mt-2" onClick={lock}>
64 - {() => '锁屏'} 72 + {() => t('lockScreenBtn')}
65 </Button> 73 </Button>
66 <Button block class="mt-2" onClick={lock.bind(null, false)}> 74 <Button block class="mt-2" onClick={lock.bind(null, false)}>
67 - {() => ' 不设置密码锁屏'} 75 + {() => t('notLockScreenPassword')}
68 </Button> 76 </Button>
69 </div> 77 </div>
70 </div> 78 </div>
src/layouts/default/multitabs/TabContent.tsx
@@ -13,6 +13,7 @@ import { useTabDropdown } from &#39;./useTabDropdown&#39;; @@ -13,6 +13,7 @@ import { useTabDropdown } from &#39;./useTabDropdown&#39;;
13 import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; 13 import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
14 import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'; 14 import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
15 import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'; 15 import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
  16 +import { useI18n } from '/@/hooks/web/useI18n';
16 17
17 const ExtraContent: FunctionalComponent = () => { 18 const ExtraContent: FunctionalComponent = () => {
18 return ( 19 return (
@@ -56,6 +57,7 @@ export default defineComponent({ @@ -56,6 +57,7 @@ export default defineComponent({
56 }, 57 },
57 }, 58 },
58 setup(props) { 59 setup(props) {
  60 + const { t } = useI18n('layout.multipleTab');
59 const { getShowMenu } = useMenuSetting(); 61 const { getShowMenu } = useMenuSetting();
60 const { getShowHeader } = useHeaderSetting(); 62 const { getShowHeader } = useHeaderSetting();
61 const { getShowQuick } = useMultipleTabSetting(); 63 const { getShowQuick } = useMultipleTabSetting();
@@ -71,7 +73,10 @@ export default defineComponent({ @@ -71,7 +73,10 @@ export default defineComponent({
71 const { getDropMenuList, handleMenuEvent } = useTabDropdown(props as TabContentProps); 73 const { getDropMenuList, handleMenuEvent } = useTabDropdown(props as TabContentProps);
72 74
73 return () => { 75 return () => {
74 - const scaleAction = getScaleAction(unref(getIsScale) ? '收起' : '展开', unref(getIsScale)); 76 + const scaleAction = getScaleAction(
  77 + unref(getIsScale) ? t('putAway') : t('unfold'),
  78 + unref(getIsScale)
  79 + );
75 const dropMenuList = unref(getDropMenuList) || []; 80 const dropMenuList = unref(getDropMenuList) || [];
76 81
77 const isTab = unref(getIsTab); 82 const isTab = unref(getIsTab);
src/layouts/default/multitabs/data.ts
@@ -2,6 +2,10 @@ import { DropMenu } from &#39;/@/components/Dropdown/index&#39;; @@ -2,6 +2,10 @@ import { DropMenu } from &#39;/@/components/Dropdown/index&#39;;
2 import { AppRouteRecordRaw } from '/@/router/types'; 2 import { AppRouteRecordRaw } from '/@/router/types';
3 import type { TabItem } from '/@/store/modules/tab'; 3 import type { TabItem } from '/@/store/modules/tab';
4 4
  5 +import { useI18n } from '/@/hooks/web/useI18n';
  6 +
  7 +const { t } = useI18n('layout.multipleTab');
  8 +
5 export enum TabContentEnum { 9 export enum TabContentEnum {
6 TAB_TYPE, 10 TAB_TYPE,
7 EXTRA_TYPE, 11 EXTRA_TYPE,
@@ -37,40 +41,40 @@ export function getActions() { @@ -37,40 +41,40 @@ export function getActions() {
37 const REFRESH_PAGE: DropMenu = { 41 const REFRESH_PAGE: DropMenu = {
38 icon: 'ant-design:reload-outlined', 42 icon: 'ant-design:reload-outlined',
39 event: MenuEventEnum.REFRESH_PAGE, 43 event: MenuEventEnum.REFRESH_PAGE,
40 - text: '刷新', 44 + text: t('redo'),
41 disabled: false, 45 disabled: false,
42 }; 46 };
43 const CLOSE_CURRENT: DropMenu = { 47 const CLOSE_CURRENT: DropMenu = {
44 icon: 'ant-design:close-outlined', 48 icon: 'ant-design:close-outlined',
45 event: MenuEventEnum.CLOSE_CURRENT, 49 event: MenuEventEnum.CLOSE_CURRENT,
46 - text: '关闭', 50 + text: t('close'),
47 disabled: false, 51 disabled: false,
48 divider: true, 52 divider: true,
49 }; 53 };
50 const CLOSE_LEFT: DropMenu = { 54 const CLOSE_LEFT: DropMenu = {
51 icon: 'ant-design:pic-left-outlined', 55 icon: 'ant-design:pic-left-outlined',
52 event: MenuEventEnum.CLOSE_LEFT, 56 event: MenuEventEnum.CLOSE_LEFT,
53 - text: '关闭左侧', 57 + text: t('closeLeft'),
54 disabled: false, 58 disabled: false,
55 divider: false, 59 divider: false,
56 }; 60 };
57 const CLOSE_RIGHT: DropMenu = { 61 const CLOSE_RIGHT: DropMenu = {
58 icon: 'ant-design:pic-right-outlined', 62 icon: 'ant-design:pic-right-outlined',
59 event: MenuEventEnum.CLOSE_RIGHT, 63 event: MenuEventEnum.CLOSE_RIGHT,
60 - text: '关闭右侧', 64 + text: t('closeRight'),
61 disabled: false, 65 disabled: false,
62 divider: true, 66 divider: true,
63 }; 67 };
64 const CLOSE_OTHER: DropMenu = { 68 const CLOSE_OTHER: DropMenu = {
65 icon: 'ant-design:pic-center-outlined', 69 icon: 'ant-design:pic-center-outlined',
66 event: MenuEventEnum.CLOSE_OTHER, 70 event: MenuEventEnum.CLOSE_OTHER,
67 - text: '关闭其他', 71 + text: t('closeOther'),
68 disabled: false, 72 disabled: false,
69 }; 73 };
70 const CLOSE_ALL: DropMenu = { 74 const CLOSE_ALL: DropMenu = {
71 icon: 'ant-design:line-outlined', 75 icon: 'ant-design:line-outlined',
72 event: MenuEventEnum.CLOSE_ALL, 76 event: MenuEventEnum.CLOSE_ALL,
73 - text: '关闭全部', 77 + text: t('closeAll'),
74 disabled: false, 78 disabled: false,
75 }; 79 };
76 return [REFRESH_PAGE, CLOSE_CURRENT, CLOSE_LEFT, CLOSE_RIGHT, CLOSE_OTHER, CLOSE_ALL]; 80 return [REFRESH_PAGE, CLOSE_CURRENT, CLOSE_LEFT, CLOSE_RIGHT, CLOSE_OTHER, CLOSE_ALL];
src/layouts/default/setting/SettingDrawer.tsx
@@ -18,6 +18,7 @@ import { useMenuSetting } from &#39;/@/hooks/setting/useMenuSetting&#39;; @@ -18,6 +18,7 @@ import { useMenuSetting } from &#39;/@/hooks/setting/useMenuSetting&#39;;
18 import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'; 18 import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
19 import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'; 19 import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
20 import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting'; 20 import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
  21 +import { useI18n } from '/@/hooks/web/useI18n';
21 22
22 import { updateColorWeak, updateGrayMode } from '/@/setup/theme'; 23 import { updateColorWeak, updateGrayMode } from '/@/setup/theme';
23 24
@@ -55,6 +56,7 @@ interface ThemePickerProps { @@ -55,6 +56,7 @@ interface ThemePickerProps {
55 } 56 }
56 57
57 const { createSuccessModal, createMessage } = useMessage(); 58 const { createSuccessModal, createMessage } = useMessage();
  59 +const { t } = useI18n('layout.setting');
58 60
59 /** 61 /**
60 * Menu type Picker comp 62 * Menu type Picker comp
@@ -120,8 +122,8 @@ const FooterButton: FunctionalComponent = () =&gt; { @@ -120,8 +122,8 @@ const FooterButton: FunctionalComponent = () =&gt; {
120 const { isSuccessRef } = useCopyToClipboard(JSON.stringify(unref(getRootSetting), null, 2)); 122 const { isSuccessRef } = useCopyToClipboard(JSON.stringify(unref(getRootSetting), null, 2));
121 unref(isSuccessRef) && 123 unref(isSuccessRef) &&
122 createSuccessModal({ 124 createSuccessModal({
123 - title: '操作成功',  
124 - content: '复制成功,请到 src/settings/projectSetting.ts 中修改配置!', 125 + title: t('operatingTitle'),
  126 + content: t('operatingContent'),
125 }); 127 });
126 } 128 }
127 function handleResetSetting() { 129 function handleResetSetting() {
@@ -131,7 +133,7 @@ const FooterButton: FunctionalComponent = () =&gt; { @@ -131,7 +133,7 @@ const FooterButton: FunctionalComponent = () =&gt; {
131 // updateTheme(themeColor); 133 // updateTheme(themeColor);
132 updateColorWeak(colorWeak); 134 updateColorWeak(colorWeak);
133 updateGrayMode(grayMode); 135 updateGrayMode(grayMode);
134 - createMessage.success('重置成功!'); 136 + createMessage.success(t('resetSuccess'));
135 } catch (error) { 137 } catch (error) {
136 createMessage.error(error); 138 createMessage.error(error);
137 } 139 }
@@ -149,7 +151,7 @@ const FooterButton: FunctionalComponent = () =&gt; { @@ -149,7 +151,7 @@ const FooterButton: FunctionalComponent = () =&gt; {
149 {() => ( 151 {() => (
150 <> 152 <>
151 <CopyOutlined class="mr-2" /> 153 <CopyOutlined class="mr-2" />
152 - 拷贝 154 + {t('copyBtn')}
153 </> 155 </>
154 )} 156 )}
155 </Button> 157 </Button>
@@ -157,7 +159,7 @@ const FooterButton: FunctionalComponent = () =&gt; { @@ -157,7 +159,7 @@ const FooterButton: FunctionalComponent = () =&gt; {
157 {() => ( 159 {() => (
158 <> 160 <>
159 <RedoOutlined class="mr-2" /> 161 <RedoOutlined class="mr-2" />
160 - 重置 162 + {t('resetBtn')}
161 </> 163 </>
162 )} 164 )}
163 </Button> 165 </Button>
@@ -165,7 +167,7 @@ const FooterButton: FunctionalComponent = () =&gt; { @@ -165,7 +167,7 @@ const FooterButton: FunctionalComponent = () =&gt; {
165 {() => ( 167 {() => (
166 <> 168 <>
167 <RedoOutlined class="mr-2" /> 169 <RedoOutlined class="mr-2" />
168 - 清空缓存并返回登录页 170 + {t('clearBtn')}
169 </> 171 </>
170 )} 172 )}
171 </Button> 173 </Button>
@@ -224,7 +226,7 @@ export default defineComponent({ @@ -224,7 +226,7 @@ export default defineComponent({
224 return ( 226 return (
225 <> 227 <>
226 <MenuTypePicker /> 228 <MenuTypePicker />
227 - {renderSwitchItem('分割菜单', { 229 + {renderSwitchItem(t('splitMenu'), {
228 handler: (e) => { 230 handler: (e) => {
229 baseHandler(HandlerEnum.MENU_SPLIT, e); 231 baseHandler(HandlerEnum.MENU_SPLIT, e);
230 }, 232 },
@@ -238,7 +240,7 @@ export default defineComponent({ @@ -238,7 +240,7 @@ export default defineComponent({
238 function renderTheme() { 240 function renderTheme() {
239 return ( 241 return (
240 <> 242 <>
241 - <Divider>{() => '顶栏主题'}</Divider> 243 + <Divider>{() => t('headerTheme')}</Divider>
242 <ThemePicker 244 <ThemePicker
243 colorList={HEADER_PRESET_BG_COLOR_LIST} 245 colorList={HEADER_PRESET_BG_COLOR_LIST}
244 def={unref(getHeaderBgColor)} 246 def={unref(getHeaderBgColor)}
@@ -246,7 +248,7 @@ export default defineComponent({ @@ -246,7 +248,7 @@ export default defineComponent({
246 baseHandler(HandlerEnum.HEADER_THEME, e); 248 baseHandler(HandlerEnum.HEADER_THEME, e);
247 }} 249 }}
248 /> 250 />
249 - <Divider>{() => '菜单主题'}</Divider> 251 + <Divider>{() => t('sidebarTheme')}</Divider>
250 <ThemePicker 252 <ThemePicker
251 colorList={SIDE_BAR_BG_COLOR_LIST} 253 colorList={SIDE_BAR_BG_COLOR_LIST}
252 def={unref(getMenuBgColor)} 254 def={unref(getMenuBgColor)}
@@ -263,56 +265,56 @@ export default defineComponent({ @@ -263,56 +265,56 @@ export default defineComponent({
263 */ 265 */
264 function renderFeatures() { 266 function renderFeatures() {
265 return [ 267 return [
266 - renderSwitchItem('侧边菜单拖拽', { 268 + renderSwitchItem(t('menuDrag'), {
267 handler: (e) => { 269 handler: (e) => {
268 baseHandler(HandlerEnum.MENU_HAS_DRAG, e); 270 baseHandler(HandlerEnum.MENU_HAS_DRAG, e);
269 }, 271 },
270 def: unref(getCanDrag), 272 def: unref(getCanDrag),
271 disabled: !unref(getShowMenuRef), 273 disabled: !unref(getShowMenuRef),
272 }), 274 }),
273 - renderSwitchItem('侧边菜单搜索', { 275 + renderSwitchItem(t('menuSearch'), {
274 handler: (e) => { 276 handler: (e) => {
275 baseHandler(HandlerEnum.MENU_SHOW_SEARCH, e); 277 baseHandler(HandlerEnum.MENU_SHOW_SEARCH, e);
276 }, 278 },
277 def: unref(getShowSearch), 279 def: unref(getShowSearch),
278 disabled: !unref(getShowMenuRef), 280 disabled: !unref(getShowMenuRef),
279 }), 281 }),
280 - renderSwitchItem('侧边菜单手风琴模式', { 282 + renderSwitchItem(t('menuAccordion'), {
281 handler: (e) => { 283 handler: (e) => {
282 baseHandler(HandlerEnum.MENU_ACCORDION, e); 284 baseHandler(HandlerEnum.MENU_ACCORDION, e);
283 }, 285 },
284 def: unref(getAccordion), 286 def: unref(getAccordion),
285 disabled: !unref(getShowMenuRef), 287 disabled: !unref(getShowMenuRef),
286 }), 288 }),
287 - renderSwitchItem('折叠菜单', { 289 + renderSwitchItem(t('menuCollapse'), {
288 handler: (e) => { 290 handler: (e) => {
289 baseHandler(HandlerEnum.MENU_COLLAPSED, e); 291 baseHandler(HandlerEnum.MENU_COLLAPSED, e);
290 }, 292 },
291 def: unref(getCollapsed), 293 def: unref(getCollapsed),
292 disabled: !unref(getShowMenuRef), 294 disabled: !unref(getShowMenuRef),
293 }), 295 }),
294 - renderSwitchItem('折叠菜单显示名称', { 296 + renderSwitchItem(t('collapseMenuDisplayName'), {
295 handler: (e) => { 297 handler: (e) => {
296 baseHandler(HandlerEnum.MENU_COLLAPSED_SHOW_TITLE, e); 298 baseHandler(HandlerEnum.MENU_COLLAPSED_SHOW_TITLE, e);
297 }, 299 },
298 def: unref(getCollapsedShowTitle), 300 def: unref(getCollapsedShowTitle),
299 disabled: !unref(getShowMenuRef) || !unref(getCollapsed), 301 disabled: !unref(getShowMenuRef) || !unref(getCollapsed),
300 }), 302 }),
301 - renderSwitchItem('固定header', { 303 + renderSwitchItem(t('fixedHeader'), {
302 handler: (e) => { 304 handler: (e) => {
303 baseHandler(HandlerEnum.HEADER_FIXED, e); 305 baseHandler(HandlerEnum.HEADER_FIXED, e);
304 }, 306 },
305 def: unref(getHeaderFixed), 307 def: unref(getHeaderFixed),
306 disabled: !unref(getShowHeader), 308 disabled: !unref(getShowHeader),
307 }), 309 }),
308 - renderSwitchItem('固定Siderbar', { 310 + renderSwitchItem(t('fixedSideBar'), {
309 handler: (e) => { 311 handler: (e) => {
310 baseHandler(HandlerEnum.MENU_FIXED, e); 312 baseHandler(HandlerEnum.MENU_FIXED, e);
311 }, 313 },
312 def: unref(getMenuFixed), 314 def: unref(getMenuFixed),
313 disabled: !unref(getShowMenuRef), 315 disabled: !unref(getShowMenuRef),
314 }), 316 }),
315 - renderSelectItem('顶部菜单布局', { 317 + renderSelectItem(t('topMenuLayout'), {
316 handler: (e) => { 318 handler: (e) => {
317 baseHandler(HandlerEnum.MENU_TOP_ALIGN, e); 319 baseHandler(HandlerEnum.MENU_TOP_ALIGN, e);
318 }, 320 },
@@ -320,7 +322,7 @@ export default defineComponent({ @@ -320,7 +322,7 @@ export default defineComponent({
320 options: topMenuAlignOptions, 322 options: topMenuAlignOptions,
321 disabled: !unref(getShowHeader) || (!unref(getIsTopMenu) && !unref(getSplit)), 323 disabled: !unref(getShowHeader) || (!unref(getIsTopMenu) && !unref(getSplit)),
322 }), 324 }),
323 - renderSelectItem('菜单折叠按钮', { 325 + renderSelectItem(t('menuCollapseButton'), {
324 handler: (e) => { 326 handler: (e) => {
325 baseHandler(HandlerEnum.MENU_TRIGGER, e); 327 baseHandler(HandlerEnum.MENU_TRIGGER, e);
326 }, 328 },
@@ -329,7 +331,7 @@ export default defineComponent({ @@ -329,7 +331,7 @@ export default defineComponent({
329 options: menuTriggerOptions, 331 options: menuTriggerOptions,
330 }), 332 }),
331 333
332 - renderSelectItem('内容区域宽度', { 334 + renderSelectItem(t('contentMode'), {
333 handler: (e) => { 335 handler: (e) => {
334 baseHandler(HandlerEnum.CONTENT_MODE, e); 336 baseHandler(HandlerEnum.CONTENT_MODE, e);
335 }, 337 },
@@ -337,9 +339,9 @@ export default defineComponent({ @@ -337,9 +339,9 @@ export default defineComponent({
337 options: contentModeOptions, 339 options: contentModeOptions,
338 }), 340 }),
339 <div class={`setting-drawer__cell-item`}> 341 <div class={`setting-drawer__cell-item`}>
340 - <span>自动锁屏</span> 342 + <span>{t('autoScreenLock')}</span>
341 <InputNumber 343 <InputNumber
342 - style="width:120px" 344 + style="width:126px"
343 size="small" 345 size="small"
344 min={0} 346 min={0}
345 onChange={(e: any) => { 347 onChange={(e: any) => {
@@ -348,16 +350,16 @@ export default defineComponent({ @@ -348,16 +350,16 @@ export default defineComponent({
348 defaultValue={appStore.getProjectConfig.lockTime} 350 defaultValue={appStore.getProjectConfig.lockTime}
349 formatter={(value: string) => { 351 formatter={(value: string) => {
350 if (parseInt(value) === 0) { 352 if (parseInt(value) === 0) {
351 - return '0(不自动锁屏)'; 353 + return `0(${t('notAutoScreenLock')})`;
352 } 354 }
353 - return `${value}分钟`; 355 + return `${value}${t('minute')}`;
354 }} 356 }}
355 /> 357 />
356 </div>, 358 </div>,
357 <div class={`setting-drawer__cell-item`}> 359 <div class={`setting-drawer__cell-item`}>
358 - <span>菜单展开宽度</span> 360 + <span>{t('expandedMenuWidth')}</span>
359 <InputNumber 361 <InputNumber
360 - style="width:120px" 362 + style="width:126px"
361 size="small" 363 size="small"
362 max={600} 364 max={600}
363 min={100} 365 min={100}
@@ -375,27 +377,27 @@ export default defineComponent({ @@ -375,27 +377,27 @@ export default defineComponent({
375 377
376 function renderContent() { 378 function renderContent() {
377 return [ 379 return [
378 - renderSwitchItem('面包屑', { 380 + renderSwitchItem(t('breadcrumb'), {
379 handler: (e) => { 381 handler: (e) => {
380 baseHandler(HandlerEnum.SHOW_BREADCRUMB, e); 382 baseHandler(HandlerEnum.SHOW_BREADCRUMB, e);
381 }, 383 },
382 def: unref(getShowBreadCrumb), 384 def: unref(getShowBreadCrumb),
383 disabled: !unref(getShowHeader), 385 disabled: !unref(getShowHeader),
384 }), 386 }),
385 - renderSwitchItem('面包屑图标', { 387 + renderSwitchItem(t('breadcrumbIcon'), {
386 handler: (e) => { 388 handler: (e) => {
387 baseHandler(HandlerEnum.SHOW_BREADCRUMB_ICON, e); 389 baseHandler(HandlerEnum.SHOW_BREADCRUMB_ICON, e);
388 }, 390 },
389 def: unref(getShowBreadCrumbIcon), 391 def: unref(getShowBreadCrumbIcon),
390 disabled: !unref(getShowHeader), 392 disabled: !unref(getShowHeader),
391 }), 393 }),
392 - renderSwitchItem('标签页', { 394 + renderSwitchItem(t('tabs'), {
393 handler: (e) => { 395 handler: (e) => {
394 baseHandler(HandlerEnum.TABS_SHOW, e); 396 baseHandler(HandlerEnum.TABS_SHOW, e);
395 }, 397 },
396 def: unref(getShowMultipleTab), 398 def: unref(getShowMultipleTab),
397 }), 399 }),
398 - renderSwitchItem('标签页快捷按钮', { 400 + renderSwitchItem(t('tabsQuickBtn'), {
399 handler: (e) => { 401 handler: (e) => {
400 baseHandler(HandlerEnum.TABS_SHOW_QUICK, e); 402 baseHandler(HandlerEnum.TABS_SHOW_QUICK, e);
401 }, 403 },
@@ -403,14 +405,14 @@ export default defineComponent({ @@ -403,14 +405,14 @@ export default defineComponent({
403 disabled: !unref(getShowMultipleTab), 405 disabled: !unref(getShowMultipleTab),
404 }), 406 }),
405 407
406 - renderSwitchItem('左侧菜单', { 408 + renderSwitchItem(t('sidebar'), {
407 handler: (e) => { 409 handler: (e) => {
408 baseHandler(HandlerEnum.MENU_SHOW_SIDEBAR, e); 410 baseHandler(HandlerEnum.MENU_SHOW_SIDEBAR, e);
409 }, 411 },
410 def: unref(getShowMenu), 412 def: unref(getShowMenu),
411 disabled: unref(getIsHorizontal), 413 disabled: unref(getIsHorizontal),
412 }), 414 }),
413 - renderSwitchItem('顶栏', { 415 + renderSwitchItem(t('header'), {
414 handler: (e) => { 416 handler: (e) => {
415 baseHandler(HandlerEnum.HEADER_SHOW, e); 417 baseHandler(HandlerEnum.HEADER_SHOW, e);
416 }, 418 },
@@ -422,25 +424,25 @@ export default defineComponent({ @@ -422,25 +424,25 @@ export default defineComponent({
422 }, 424 },
423 def: unref(getShowLogo), 425 def: unref(getShowLogo),
424 }), 426 }),
425 - renderSwitchItem('页脚', { 427 + renderSwitchItem(t('footer'), {
426 handler: (e) => { 428 handler: (e) => {
427 baseHandler(HandlerEnum.SHOW_FOOTER, e); 429 baseHandler(HandlerEnum.SHOW_FOOTER, e);
428 }, 430 },
429 def: unref(getShowFooter), 431 def: unref(getShowFooter),
430 }), 432 }),
431 - renderSwitchItem('全屏内容', { 433 + renderSwitchItem(t('fullContent'), {
432 handler: (e) => { 434 handler: (e) => {
433 baseHandler(HandlerEnum.FULL_CONTENT, e); 435 baseHandler(HandlerEnum.FULL_CONTENT, e);
434 }, 436 },
435 def: unref(getFullContent), 437 def: unref(getFullContent),
436 }), 438 }),
437 - renderSwitchItem('灰色模式', { 439 + renderSwitchItem(t('grayMode'), {
438 handler: (e) => { 440 handler: (e) => {
439 baseHandler(HandlerEnum.GRAY_MODE, e); 441 baseHandler(HandlerEnum.GRAY_MODE, e);
440 }, 442 },
441 def: unref(getGrayMode), 443 def: unref(getGrayMode),
442 }), 444 }),
443 - renderSwitchItem('色弱模式', { 445 + renderSwitchItem(t('colorWeak'), {
444 handler: (e) => { 446 handler: (e) => {
445 baseHandler(HandlerEnum.COLOR_WEAK, e); 447 baseHandler(HandlerEnum.COLOR_WEAK, e);
446 }, 448 },
@@ -452,13 +454,13 @@ export default defineComponent({ @@ -452,13 +454,13 @@ export default defineComponent({
452 function renderTransition() { 454 function renderTransition() {
453 return ( 455 return (
454 <> 456 <>
455 - {renderSwitchItem('顶部进度条', { 457 + {renderSwitchItem(t('progress'), {
456 handler: (e) => { 458 handler: (e) => {
457 baseHandler(HandlerEnum.OPEN_PROGRESS, e); 459 baseHandler(HandlerEnum.OPEN_PROGRESS, e);
458 }, 460 },
459 def: unref(getOpenNProgress), 461 def: unref(getOpenNProgress),
460 })} 462 })}
461 - {renderSwitchItem('切换loading', { 463 + {renderSwitchItem(t('switchLoading'), {
462 handler: (e) => { 464 handler: (e) => {
463 baseHandler(HandlerEnum.OPEN_PAGE_LOADING, e); 465 baseHandler(HandlerEnum.OPEN_PAGE_LOADING, e);
464 }, 466 },
@@ -466,14 +468,14 @@ export default defineComponent({ @@ -466,14 +468,14 @@ export default defineComponent({
466 disabled: !unref(getEnableTransition), 468 disabled: !unref(getEnableTransition),
467 })} 469 })}
468 470
469 - {renderSwitchItem('切换动画', { 471 + {renderSwitchItem(t('switchAnimation'), {
470 handler: (e) => { 472 handler: (e) => {
471 baseHandler(HandlerEnum.OPEN_ROUTE_TRANSITION, e); 473 baseHandler(HandlerEnum.OPEN_ROUTE_TRANSITION, e);
472 }, 474 },
473 def: unref(getEnableTransition), 475 def: unref(getEnableTransition),
474 })} 476 })}
475 477
476 - {renderSelectItem('动画类型', { 478 + {renderSelectItem(t('animationType'), {
477 handler: (e) => { 479 handler: (e) => {
478 baseHandler(HandlerEnum.ROUTER_TRANSITION, e); 480 baseHandler(HandlerEnum.ROUTER_TRANSITION, e);
479 }, 481 },
@@ -495,7 +497,7 @@ export default defineComponent({ @@ -495,7 +497,7 @@ export default defineComponent({
495 {...opt} 497 {...opt}
496 disabled={disabled} 498 disabled={disabled}
497 size="small" 499 size="small"
498 - style={{ width: '120px' }} 500 + style={{ width: '126px' }}
499 onChange={(e) => { 501 onChange={(e) => {
500 handler && handler(e); 502 handler && handler(e);
501 }} 503 }}
@@ -517,26 +519,26 @@ export default defineComponent({ @@ -517,26 +519,26 @@ export default defineComponent({
517 onChange={(e: any) => { 519 onChange={(e: any) => {
518 handler && handler(e); 520 handler && handler(e);
519 }} 521 }}
520 - checkedChildren="开"  
521 - unCheckedChildren="关" 522 + checkedChildren={t('on')}
  523 + unCheckedChildren={t('off')}
522 /> 524 />
523 </div> 525 </div>
524 ); 526 );
525 } 527 }
526 528
527 return () => ( 529 return () => (
528 - <BasicDrawer {...attrs} title="项目配置" width={300} wrapClassName="setting-drawer"> 530 + <BasicDrawer {...attrs} title={t('drawerTitle')} width={330} wrapClassName="setting-drawer">
529 {{ 531 {{
530 default: () => ( 532 default: () => (
531 <> 533 <>
532 - <Divider>{() => '导航栏模式'}</Divider> 534 + <Divider>{() => t('navMode')}</Divider>
533 {renderSidebar()} 535 {renderSidebar()}
534 {renderTheme()} 536 {renderTheme()}
535 - <Divider>{() => '界面功能'}</Divider> 537 + <Divider>{() => t('interfaceFunction')}</Divider>
536 {renderFeatures()} 538 {renderFeatures()}
537 - <Divider>{() => '界面显示'}</Divider> 539 + <Divider>{() => t('interfaceDisplay')}</Divider>
538 {renderContent()} 540 {renderContent()}
539 - <Divider>{() => '切换动画'}</Divider> 541 + <Divider>{() => t('animation')}</Divider>
540 {renderTransition()} 542 {renderTransition()}
541 <Divider /> 543 <Divider />
542 <FooterButton /> 544 <FooterButton />
src/layouts/default/setting/enum.ts
1 -import { ContentEnum, RouterTransitionEnum, ThemeEnum } from '/@/enums/appEnum'; 1 +import { ContentEnum, RouterTransitionEnum } from '/@/enums/appEnum';
2 import { MenuModeEnum, MenuTypeEnum, TopMenuAlignEnum, TriggerEnum } from '/@/enums/menuEnum'; 2 import { MenuModeEnum, MenuTypeEnum, TopMenuAlignEnum, TriggerEnum } from '/@/enums/menuEnum';
3 3
4 import mixImg from '/@/assets/images/layout/menu-mix.svg'; 4 import mixImg from '/@/assets/images/layout/menu-mix.svg';
5 import sidebarImg from '/@/assets/images/layout/menu-sidebar.svg'; 5 import sidebarImg from '/@/assets/images/layout/menu-sidebar.svg';
6 import menuTopImg from '/@/assets/images/layout/menu-top.svg'; 6 import menuTopImg from '/@/assets/images/layout/menu-top.svg';
  7 +import { useI18n } from '/@/hooks/web/useI18n';
  8 +
  9 +const { t } = useI18n('layout.setting');
7 10
8 export enum HandlerEnum { 11 export enum HandlerEnum {
9 CHANGE_LAYOUT, 12 CHANGE_LAYOUT,
@@ -45,55 +48,44 @@ export enum HandlerEnum { @@ -45,55 +48,44 @@ export enum HandlerEnum {
45 OPEN_ROUTE_TRANSITION, 48 OPEN_ROUTE_TRANSITION,
46 } 49 }
47 50
48 -export const themeOptions = [  
49 - {  
50 - value: ThemeEnum.LIGHT,  
51 - label: '亮色',  
52 - },  
53 - {  
54 - value: ThemeEnum.DARK,  
55 - label: '暗色',  
56 - },  
57 -];  
58 -  
59 export const contentModeOptions = [ 51 export const contentModeOptions = [
60 { 52 {
61 value: ContentEnum.FULL, 53 value: ContentEnum.FULL,
62 - label: '流式', 54 + label: t('contentModeFull'),
63 }, 55 },
64 { 56 {
65 value: ContentEnum.FIXED, 57 value: ContentEnum.FIXED,
66 - label: '定宽', 58 + label: t('contentModeFixed'),
67 }, 59 },
68 ]; 60 ];
69 61
70 export const topMenuAlignOptions = [ 62 export const topMenuAlignOptions = [
71 { 63 {
72 value: TopMenuAlignEnum.CENTER, 64 value: TopMenuAlignEnum.CENTER,
73 - label: '居中', 65 + label: t('topMenuAlignRight'),
74 }, 66 },
75 { 67 {
76 value: TopMenuAlignEnum.START, 68 value: TopMenuAlignEnum.START,
77 - label: '居左', 69 + label: t('topMenuAlignLeft'),
78 }, 70 },
79 { 71 {
80 value: TopMenuAlignEnum.END, 72 value: TopMenuAlignEnum.END,
81 - label: '居右', 73 + label: t('topMenuAlignCenter'),
82 }, 74 },
83 ]; 75 ];
84 76
85 export const menuTriggerOptions = [ 77 export const menuTriggerOptions = [
86 { 78 {
87 value: TriggerEnum.NONE, 79 value: TriggerEnum.NONE,
88 - label: '不显示', 80 + label: t('menuTriggerNone'),
89 }, 81 },
90 { 82 {
91 value: TriggerEnum.FOOTER, 83 value: TriggerEnum.FOOTER,
92 - label: '底部', 84 + label: t('menuTriggerBottom'),
93 }, 85 },
94 { 86 {
95 value: TriggerEnum.HEADER, 87 value: TriggerEnum.HEADER,
96 - label: '顶部', 88 + label: t('menuTriggerTop'),
97 }, 89 },
98 ]; 90 ];
99 91
@@ -112,20 +104,20 @@ export const routerTransitionOptions = [ @@ -112,20 +104,20 @@ export const routerTransitionOptions = [
112 104
113 export const menuTypeList = [ 105 export const menuTypeList = [
114 { 106 {
115 - title: '左侧菜单模式', 107 + title: t('menuTypeSidebar'),
116 mode: MenuModeEnum.INLINE, 108 mode: MenuModeEnum.INLINE,
117 type: MenuTypeEnum.SIDEBAR, 109 type: MenuTypeEnum.SIDEBAR,
118 src: sidebarImg, 110 src: sidebarImg,
119 }, 111 },
120 { 112 {
121 - title: '混合模式', 113 + title: t('menuTypeMix'),
122 mode: MenuModeEnum.INLINE, 114 mode: MenuModeEnum.INLINE,
123 type: MenuTypeEnum.MIX, 115 type: MenuTypeEnum.MIX,
124 src: mixImg, 116 src: mixImg,
125 }, 117 },
126 118
127 { 119 {
128 - title: '顶部菜单模式', 120 + title: t('menuTypeTopMenu'),
129 mode: MenuModeEnum.HORIZONTAL, 121 mode: MenuModeEnum.HORIZONTAL,
130 type: MenuTypeEnum.TOP_MENU, 122 type: MenuTypeEnum.TOP_MENU,
131 src: menuTopImg, 123 src: menuTopImg,
src/layouts/default/sider/index.tsx
1 import './index.less'; 1 import './index.less';
2 2
3 -import { computed, defineComponent, ref, unref, watch, nextTick } from 'vue'; 3 +import { computed, defineComponent, ref, unref, watch, nextTick, CSSProperties } from 'vue';
4 4
5 import { Layout } from 'ant-design-vue'; 5 import { Layout } from 'ant-design-vue';
6 import LayoutMenu from '../menu'; 6 import LayoutMenu from '../menu';
@@ -91,17 +91,19 @@ export default defineComponent({ @@ -91,17 +91,19 @@ export default defineComponent({
91 } 91 }
92 ); 92 );
93 93
94 - const getHiddenDomStyle = computed(() => {  
95 - const width = `${unref(getRealWidth)}px`;  
96 - return {  
97 - width: width,  
98 - overflow: 'hidden',  
99 - flex: `0 0 ${width}`,  
100 - 'max-width': width,  
101 - 'min-width': width,  
102 - transition: 'all 0.2s',  
103 - };  
104 - }); 94 + const getHiddenDomStyle = computed(
  95 + (): CSSProperties => {
  96 + const width = `${unref(getRealWidth)}px`;
  97 + return {
  98 + width: width,
  99 + overflow: 'hidden',
  100 + flex: `0 0 ${width}`,
  101 + maxWidth: width,
  102 + minWidth: width,
  103 + transition: 'all 0.2s',
  104 + };
  105 + }
  106 + );
105 107
106 function renderDefault() { 108 function renderDefault() {
107 return ( 109 return (
src/locales/lang/en/layout/footer.ts 0 → 100644
  1 +export default {
  2 + onlinePreview: 'Preview',
  3 + onlineDocument: 'Document',
  4 +};
src/locales/lang/en/layout/header.ts 0 → 100644
  1 +export default {
  2 + // user dropdown
  3 + dropdownItemDoc: 'Document',
  4 + dropdownItemLoginOut: 'Login Out',
  5 +
  6 + tooltipErrorLog: 'Error log',
  7 + tooltipLock: 'Lock screen',
  8 + tooltipNotify: 'Notification',
  9 + tooltipRedo: 'Refresh',
  10 + tooltipEntryFull: 'Full Screen',
  11 + tooltipExitFull: 'Exit Full Screen',
  12 +
  13 + // lock
  14 + lockScreenPassword: 'Lock screen password',
  15 + lockScreen: 'Lock screen',
  16 + lockScreenBtn: 'Locking',
  17 + notLockScreenPassword: 'No password lock screen',
  18 +};
src/locales/lang/en/layout/multipleTab.ts 0 → 100644
  1 +export default {
  2 + redo: 'Refresh',
  3 + close: 'Close',
  4 + closeLeft: 'Close Left',
  5 + closeRight: 'Close Right',
  6 + closeOther: 'Close Other',
  7 + closeAll: 'Close All',
  8 + putAway: 'PutAway',
  9 + unfold: 'Unfold',
  10 +};
src/locales/lang/en/layout/setting.ts 0 → 100644
  1 +export default {
  2 + // content mode
  3 + contentModeFull: 'Full',
  4 + contentModeFixed: 'Fixed width',
  5 + // topMenu align
  6 + topMenuAlignLeft: 'Left',
  7 + topMenuAlignRight: 'Center',
  8 + topMenuAlignCenter: 'Right',
  9 + // menu trigger
  10 + menuTriggerNone: 'Not Show',
  11 + menuTriggerBottom: 'Bottom',
  12 + menuTriggerTop: 'Top',
  13 + // menu type
  14 + menuTypeSidebar: 'Left menu mode',
  15 + menuTypeMix: 'Mixed mode',
  16 + menuTypeTopMenu: 'Top menu mode',
  17 +
  18 + on: 'On',
  19 + off: 'Off',
  20 + minute: 'Minute',
  21 +
  22 + operatingTitle: 'Successful!',
  23 + operatingContent:
  24 + 'The copy is successful, please go to src/settings/projectSetting.ts to modify the configuration!',
  25 + resetSuccess: 'Successfully reset!',
  26 +
  27 + copyBtn: 'Copy',
  28 + resetBtn: 'Reset',
  29 + clearBtn: 'Clear cache and to the login page',
  30 +
  31 + drawerTitle: 'Configuration',
  32 +
  33 + navMode: 'Navigation mode',
  34 + interfaceFunction: 'Interface function',
  35 + interfaceDisplay: 'Interface display',
  36 + animation: 'Animation',
  37 + splitMenu: 'Split menu',
  38 +
  39 + headerTheme: 'Header theme',
  40 + sidebarTheme: 'Menu theme',
  41 +
  42 + menuDrag: 'Drag Sidebar',
  43 + menuSearch: 'Sidebar search',
  44 + menuAccordion: 'Sidebar accordion',
  45 + menuCollapse: 'Collapse menu',
  46 + collapseMenuDisplayName: 'Collapse menu display name',
  47 + topMenuLayout: 'Top menu layout',
  48 + menuCollapseButton: 'Menu collapse button',
  49 + contentMode: 'Content area width',
  50 + expandedMenuWidth: 'Expanded menu width',
  51 +
  52 + breadcrumb: 'Breadcrumbs',
  53 + breadcrumbIcon: 'Breadcrumbs Icon',
  54 + tabs: 'Tabs',
  55 + tabsQuickBtn: 'Tabs quick button',
  56 + sidebar: 'Sidebar',
  57 + header: 'Header',
  58 + footer: 'Footer',
  59 + fullContent: 'Full content',
  60 + grayMode: 'Gray mode',
  61 + colorWeak: 'Color Weak Mode',
  62 +
  63 + progress: 'Progress',
  64 + switchLoading: 'Switch Loading',
  65 + switchAnimation: 'Switch animation',
  66 + animationType: 'Animation type',
  67 +
  68 + autoScreenLock: 'Auto screen lock',
  69 + notAutoScreenLock: 'Not auto lock',
  70 +
  71 + fixedHeader: 'Fixed header',
  72 + fixedSideBar: 'Fixed Sidebar',
  73 +};
src/locales/lang/zh_CN/layout/footer.ts 0 → 100644
  1 +export default {
  2 + onlinePreview: '在线预览',
  3 + onlineDocument: '在线文档',
  4 +};
src/locales/lang/zh_CN/layout/header.ts 0 → 100644
  1 +export default {
  2 + // user dropdown
  3 + dropdownItemDoc: '文档',
  4 + dropdownItemLoginOut: '退出系统',
  5 +
  6 + // tooltip
  7 + tooltipErrorLog: '错误日志',
  8 + tooltipLock: '锁定屏幕',
  9 + tooltipNotify: '消息通知',
  10 + tooltipRedo: '刷新',
  11 + tooltipEntryFull: '全屏',
  12 + tooltipExitFull: '退出全屏',
  13 +
  14 + // lock
  15 + lockScreenPassword: '锁屏密码',
  16 + lockScreen: '锁定屏幕',
  17 + lockScreenBtn: '锁定',
  18 + notLockScreenPassword: '不设置密码锁屏',
  19 +};
src/locales/lang/zh_CN/layout/multipleTab.ts 0 → 100644
  1 +export default {
  2 + redo: '刷新',
  3 + close: '关闭',
  4 + closeLeft: '关闭左侧',
  5 + closeRight: '关闭右侧',
  6 + closeOther: '关闭其他',
  7 + closeAll: '关闭全部',
  8 + putAway: '收起',
  9 + unfold: '展开',
  10 +};
src/locales/lang/zh_CN/layout/setting.ts 0 → 100644
  1 +export default {
  2 + // content mode
  3 + contentModeFull: '流式',
  4 + contentModeFixed: '定宽',
  5 + // topMenu align
  6 + topMenuAlignLeft: '居左',
  7 + topMenuAlignRight: '居中',
  8 + topMenuAlignCenter: '居右',
  9 + // menu trigger
  10 + menuTriggerNone: '不显示',
  11 + menuTriggerBottom: '底部',
  12 + menuTriggerTop: '顶部',
  13 + // menu type
  14 + menuTypeSidebar: '左侧菜单模式',
  15 + menuTypeMix: '混合模式',
  16 + menuTypeTopMenu: '顶部菜单模式',
  17 +
  18 + on: '开',
  19 + off: '关',
  20 + minute: '分钟',
  21 +
  22 + operatingTitle: '操作成功',
  23 + operatingContent: '复制成功,请到 src/settings/projectSetting.ts 中修改配置!',
  24 + resetSuccess: '重置成功!',
  25 +
  26 + copyBtn: '拷贝',
  27 + resetBtn: '重置',
  28 + clearBtn: '清空缓存并返回登录页',
  29 +
  30 + drawerTitle: '项目配置',
  31 +
  32 + navMode: '导航栏模式',
  33 + interfaceFunction: '界面功能',
  34 + interfaceDisplay: '界面显示',
  35 + animation: '动画',
  36 + splitMenu: '分割菜单',
  37 +
  38 + headerTheme: '顶栏主题',
  39 + sidebarTheme: '菜单主题',
  40 +
  41 + menuDrag: '侧边菜单拖拽',
  42 + menuSearch: '侧边菜单搜索',
  43 + menuAccordion: '侧边菜单手风琴模式',
  44 + menuCollapse: '折叠菜单',
  45 + collapseMenuDisplayName: '折叠菜单显示名称',
  46 + topMenuLayout: '顶部菜单布局',
  47 + menuCollapseButton: '菜单折叠按钮',
  48 + contentMode: '内容区域宽度',
  49 + expandedMenuWidth: '菜单展开宽度',
  50 +
  51 + breadcrumb: '面包屑',
  52 + breadcrumbIcon: '面包屑图标',
  53 + tabs: '标签页',
  54 + tabsQuickBtn: '标签页快捷按钮',
  55 + sidebar: '左侧菜单',
  56 + header: '顶栏',
  57 + footer: '页脚',
  58 + fullContent: '全屏内容',
  59 + grayMode: '灰色模式',
  60 + colorWeak: '色弱模式',
  61 +
  62 + progress: '顶部进度条',
  63 + switchLoading: '切换loading',
  64 + switchAnimation: '切换动画',
  65 + animationType: '动画类型',
  66 +
  67 + autoScreenLock: '自动锁屏',
  68 + notAutoScreenLock: '不自动锁屏',
  69 +
  70 + fixedHeader: '固定header',
  71 + fixedSideBar: '固定Sidebar',
  72 +};
src/settings/projectSetting.ts
@@ -41,6 +41,7 @@ const setting: ProjectConfig = { @@ -41,6 +41,7 @@ const setting: ProjectConfig = {
41 41
42 // locale setting 42 // locale setting
43 locale: { 43 locale: {
  44 + show: true,
44 // Locale 45 // Locale
45 lang: 'zh_CN', 46 lang: 'zh_CN',
46 // Default locale 47 // Default locale
src/types/config.d.ts
@@ -51,6 +51,7 @@ export interface HeaderSetting { @@ -51,6 +51,7 @@ export interface HeaderSetting {
51 } 51 }
52 52
53 export interface LocaleSetting { 53 export interface LocaleSetting {
  54 + show: boolean;
54 // Current language 55 // Current language
55 lang: LocaleType; 56 lang: LocaleType;
56 // default language 57 // default language
src/views/sys/error-log/DetailModal.vue
1 <template> 1 <template>
2 - <BasicModal :width="800" :title="t('sys.errorLog.tableActionDesc')" v-bind="$attrs"> 2 + <BasicModal :width="800" :title="t('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
10 import { BasicModal } from '/@/components/Modal/index'; 9 import { BasicModal } from '/@/components/Modal/index';
11 import { ErrorInfo } from '/@/store/modules/error'; 10 import { ErrorInfo } from '/@/store/modules/error';
12 import { Description, useDescription } from '/@/components/Description/index'; 11 import { Description, useDescription } from '/@/components/Description/index';
  12 + import { useI18n } from '/@/hooks/web/useI18n';
13 13
14 import { getDescSchema } from './data'; 14 import { getDescSchema } from './data';
15 15
@@ -23,7 +23,7 @@ @@ -23,7 +23,7 @@
23 }, 23 },
24 }, 24 },
25 setup() { 25 setup() {
26 - const { t } = useI18n(); 26 + const { t } = useI18n('sys.errorLog');
27 const [register] = useDescription({ 27 const [register] = useDescription({
28 column: 2, 28 column: 2,
29 schema: getDescSchema(), 29 schema: getDescSchema(),
src/views/sys/error-log/data.tsx
1 import { Tag } from 'ant-design-vue'; 1 import { Tag } from 'ant-design-vue';
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 +import { useI18n } from '/@/hooks/web/useI18n';
4 5
5 -import { useExternalI18n } from '/@/hooks/web/useLocale';  
6 -  
7 -const { t } = useExternalI18n(); 6 +const { t } = useI18n('sys.errorLog');
8 7
9 export function getColumns(): BasicColumn[] { 8 export function getColumns(): BasicColumn[] {
10 return [ 9 return [
11 { 10 {
12 dataIndex: 'type', 11 dataIndex: 'type',
13 - title: t('sys.errorLog.tableColumnType'), 12 + title: t('tableColumnType'),
14 width: 80, 13 width: 80,
15 customRender: ({ text }) => { 14 customRender: ({ text }) => {
16 const color = 15 const color =
@@ -33,12 +32,12 @@ export function getColumns(): BasicColumn[] { @@ -33,12 +32,12 @@ export function getColumns(): BasicColumn[] {
33 }, 32 },
34 { 33 {
35 dataIndex: 'time', 34 dataIndex: 'time',
36 - title: t('sys.errorLog.tableColumnDate'), 35 + title: t('tableColumnDate'),
37 width: 160, 36 width: 160,
38 }, 37 },
39 { 38 {
40 dataIndex: 'file', 39 dataIndex: 'file',
41 - title: t('sys.errorLog.tableColumnFile'), 40 + title: t('tableColumnFile'),
42 width: 200, 41 width: 200,
43 }, 42 },
44 { 43 {
@@ -48,12 +47,12 @@ export function getColumns(): BasicColumn[] { @@ -48,12 +47,12 @@ export function getColumns(): BasicColumn[] {
48 }, 47 },
49 { 48 {
50 dataIndex: 'message', 49 dataIndex: 'message',
51 - title: t('sys.errorLog.tableColumnMsg'), 50 + title: t('tableColumnMsg'),
52 width: 300, 51 width: 300,
53 }, 52 },
54 { 53 {
55 dataIndex: 'stack', 54 dataIndex: 'stack',
56 - title: t('sys.errorLog.tableColumnStackMsg'), 55 + title: t('tableColumnStackMsg'),
57 width: 300, 56 width: 300,
58 }, 57 },
59 ]; 58 ];
src/views/sys/error-log/index.vue
@@ -35,7 +35,7 @@ @@ -35,7 +35,7 @@
35 35
36 import { useModal } from '/@/components/Modal/index'; 36 import { useModal } from '/@/components/Modal/index';
37 import { useMessage } from '/@/hooks/web/useMessage'; 37 import { useMessage } from '/@/hooks/web/useMessage';
38 - import { useI18n } from 'vue-i18n'; 38 + import { useI18n } from '/@/hooks/web/useI18n';
39 39
40 import { errorStore, ErrorInfo } from '/@/store/modules/error'; 40 import { errorStore, ErrorInfo } from '/@/store/modules/error';
41 41
@@ -53,7 +53,7 @@ @@ -53,7 +53,7 @@
53 const rowInfoRef = ref<ErrorInfo>(); 53 const rowInfoRef = ref<ErrorInfo>();
54 const imgListRef = ref<string[]>([]); 54 const imgListRef = ref<string[]>([]);
55 55
56 - const { t } = useI18n(); 56 + const { t } = useI18n('sys.errorLog');
57 57
58 const [register, { setTableData }] = useTable({ 58 const [register, { setTableData }] = useTable({
59 title: t('sys.errorLog.tableTitle'), 59 title: t('sys.errorLog.tableTitle'),
@@ -80,7 +80,7 @@ @@ -80,7 +80,7 @@
80 ); 80 );
81 const { createMessage } = useMessage(); 81 const { createMessage } = useMessage();
82 if (isDevMode()) { 82 if (isDevMode()) {
83 - createMessage.info(t('sys.errorLog.enableMessage')); 83 + createMessage.info(t('enableMessage'));
84 } 84 }
85 // 查看详情 85 // 查看详情
86 function handleDetail(row: ErrorInfo) { 86 function handleDetail(row: ErrorInfo) {
src/views/sys/exception/Exception.tsx
  1 +import './exception.less';
  2 +
1 import type { PropType } from 'vue'; 3 import type { PropType } from 'vue';
2 4
3 import { Result, Button } from 'ant-design-vue'; 5 import { Result, Button } from 'ant-design-vue';
@@ -12,9 +14,8 @@ import { useRoute } from &#39;vue-router&#39;; @@ -12,9 +14,8 @@ import { useRoute } from &#39;vue-router&#39;;
12 14
13 import { useGo, useRedo } from '/@/hooks/web/usePage'; 15 import { useGo, useRedo } from '/@/hooks/web/usePage';
14 import { PageEnum } from '/@/enums/pageEnum'; 16 import { PageEnum } from '/@/enums/pageEnum';
15 -import { useI18n } from 'vue-i18n'; 17 +import { useI18n } from '/@/hooks/web/useI18n';
16 18
17 -import './exception.less';  
18 interface MapValue { 19 interface MapValue {
19 title: string; 20 title: string;
20 subTitle: string; 21 subTitle: string;
@@ -52,7 +53,7 @@ export default defineComponent({ @@ -52,7 +53,7 @@ export default defineComponent({
52 const { query } = useRoute(); 53 const { query } = useRoute();
53 const go = useGo(); 54 const go = useGo();
54 const redo = useRedo(); 55 const redo = useRedo();
55 - const { t } = useI18n(); 56 + const { t } = useI18n('sys.exception');
56 57
57 const getStatus = computed(() => { 58 const getStatus = computed(() => {
58 const { status: routeStatus } = query; 59 const { status: routeStatus } = query;
@@ -66,13 +67,13 @@ export default defineComponent({ @@ -66,13 +67,13 @@ export default defineComponent({
66 } 67 }
67 ); 68 );
68 69
69 - const backLoginI18n = t('sys.exception.backLogin');  
70 - const backHomeI18n = t('sys.exception.backHome'); 70 + const backLoginI18n = t('backLogin');
  71 + const backHomeI18n = t('backHome');
71 72
72 unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_ACCESS, { 73 unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_ACCESS, {
73 title: '403', 74 title: '403',
74 status: `${ExceptionEnum.PAGE_NOT_ACCESS}`, 75 status: `${ExceptionEnum.PAGE_NOT_ACCESS}`,
75 - subTitle: t('sys.exception.subTitle403'), 76 + subTitle: t('subTitle403'),
76 btnText: props.full ? backLoginI18n : backHomeI18n, 77 btnText: props.full ? backLoginI18n : backHomeI18n,
77 handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()), 78 handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()),
78 }); 79 });
@@ -80,7 +81,7 @@ export default defineComponent({ @@ -80,7 +81,7 @@ export default defineComponent({
80 unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_FOUND, { 81 unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_FOUND, {
81 title: '404', 82 title: '404',
82 status: `${ExceptionEnum.PAGE_NOT_FOUND}`, 83 status: `${ExceptionEnum.PAGE_NOT_FOUND}`,
83 - subTitle: t('sys.exception.subTitle404'), 84 + subTitle: t('subTitle404'),
84 btnText: props.full ? backLoginI18n : backHomeI18n, 85 btnText: props.full ? backLoginI18n : backHomeI18n,
85 handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()), 86 handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()),
86 }); 87 });
@@ -88,22 +89,22 @@ export default defineComponent({ @@ -88,22 +89,22 @@ export default defineComponent({
88 unref(statusMapRef).set(ExceptionEnum.ERROR, { 89 unref(statusMapRef).set(ExceptionEnum.ERROR, {
89 title: '500', 90 title: '500',
90 status: `${ExceptionEnum.ERROR}`, 91 status: `${ExceptionEnum.ERROR}`,
91 - subTitle: t('sys.exception.subTitle500'), 92 + subTitle: t('subTitle500'),
92 btnText: backHomeI18n, 93 btnText: backHomeI18n,
93 handler: () => go(), 94 handler: () => go(),
94 }); 95 });
95 96
96 unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_DATA, { 97 unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_DATA, {
97 - title: t('sys.exception.noDataTitle'), 98 + title: t('noDataTitle'),
98 subTitle: '', 99 subTitle: '',
99 - btnText: t('sys.exception.redo'), 100 + btnText: t('redo'),
100 handler: () => redo(), 101 handler: () => redo(),
101 icon: notDataImg, 102 icon: notDataImg,
102 }); 103 });
103 104
104 unref(statusMapRef).set(ExceptionEnum.NET_WORK_ERROR, { 105 unref(statusMapRef).set(ExceptionEnum.NET_WORK_ERROR, {
105 - title: t('sys.exception.networkErrorTitle'),  
106 - subTitle: t('sys.exception.networkErrorSubTitle'), 106 + title: t('networkErrorTitle'),
  107 + subTitle: t('networkErrorSubTitle'),
107 btnText: 'Refresh', 108 btnText: 'Refresh',
108 handler: () => redo(), 109 handler: () => redo(),
109 icon: netWorkImg, 110 icon: netWorkImg,
src/views/sys/lock/index.vue
@@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
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="t('sys.lock.alert')" banner /> 9 + <Alert v-if="errMsgRef" type="error" :message="t('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 {{ t('sys.lock.backToLogin') }} 12 {{ t('sys.lock.backToLogin') }}
@@ -26,8 +26,7 @@ @@ -26,8 +26,7 @@
26 26
27 import { userStore } from '/@/store/modules/user'; 27 import { userStore } from '/@/store/modules/user';
28 import { appStore } from '/@/store/modules/app'; 28 import { appStore } from '/@/store/modules/app';
29 -  
30 - import { useI18n } from 'vue-i18n'; 29 + import { useI18n } from '/@/hooks/web/useI18n';
31 30
32 export default defineComponent({ 31 export default defineComponent({
33 name: 'LockPage', 32 name: 'LockPage',
@@ -37,7 +36,7 @@ @@ -37,7 +36,7 @@
37 const loadingRef = ref(false); 36 const loadingRef = ref(false);
38 const errMsgRef = ref(false); 37 const errMsgRef = ref(false);
39 38
40 - const { t } = useI18n(); 39 + const { t } = useI18n('sys.lock');
41 const [register, { validateFields }] = useForm({ 40 const [register, { validateFields }] = useForm({
42 showActionButtonGroup: false, 41 showActionButtonGroup: false,
43 schemas: [ 42 schemas: [
@@ -47,7 +46,7 @@ @@ -47,7 +46,7 @@
47 component: 'InputPassword', 46 component: 'InputPassword',
48 componentProps: { 47 componentProps: {
49 style: { width: '100%' }, 48 style: { width: '100%' },
50 - placeholder: t('sys.lock.placeholder'), 49 + placeholder: t('placeholder'),
51 }, 50 },
52 rules: [{ required: true }], 51 rules: [{ required: true }],
53 }, 52 },
src/views/sys/login/Login.vue
@@ -4,7 +4,7 @@ @@ -4,7 +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 + <AppLocalePicker v-if="showLocale" class="login-form__locale" />
8 <header> 8 <header>
9 <img :src="logo" class="mr-4" /> 9 <img :src="logo" class="mr-4" />
10 <h1>{{ title }}</h1> 10 <h1>{{ title }}</h1>
@@ -64,23 +64,23 @@ @@ -64,23 +64,23 @@
64 import { Checkbox } from 'ant-design-vue'; 64 import { Checkbox } from 'ant-design-vue';
65 65
66 import Button from '/@/components/Button/index.vue'; 66 import Button from '/@/components/Button/index.vue';
67 - import { AppLocalPicker } from '/@/components/Application'; 67 + import { AppLocalePicker } from '/@/components/Application';
68 // import { BasicDragVerify, DragVerifyActionType } from '/@/components/Verify/index'; 68 // import { BasicDragVerify, DragVerifyActionType } from '/@/components/Verify/index';
69 69
70 import { userStore } from '/@/store/modules/user'; 70 import { userStore } from '/@/store/modules/user';
71 - import { useI18n } from 'vue-i18n';  
72 71
73 // import { appStore } from '/@/store/modules/app'; 72 // import { appStore } from '/@/store/modules/app';
74 import { useMessage } from '/@/hooks/web/useMessage'; 73 import { useMessage } from '/@/hooks/web/useMessage';
75 - import { useGlobSetting } from '/@/hooks/setting'; 74 + import { useGlobSetting, useProjectSetting } from '/@/hooks/setting';
76 import logo from '/@/assets/images/logo.png'; 75 import logo from '/@/assets/images/logo.png';
  76 + import { useI18n } from '/@/hooks/web/useI18n';
77 77
78 export default defineComponent({ 78 export default defineComponent({
79 components: { 79 components: {
80 // BasicDragVerify, 80 // BasicDragVerify,
81 AButton: Button, 81 AButton: Button,
82 ACheckbox: Checkbox, 82 ACheckbox: Checkbox,
83 - AppLocalPicker, 83 + AppLocalePicker,
84 }, 84 },
85 setup() { 85 setup() {
86 const formRef = ref<any>(null); 86 const formRef = ref<any>(null);
@@ -88,8 +88,9 @@ @@ -88,8 +88,9 @@
88 // const verifyRef = ref<RefInstanceType<DragVerifyActionType>>(null); 88 // const verifyRef = ref<RefInstanceType<DragVerifyActionType>>(null);
89 89
90 const globSetting = useGlobSetting(); 90 const globSetting = useGlobSetting();
  91 + const { locale } = useProjectSetting();
91 const { notification } = useMessage(); 92 const { notification } = useMessage();
92 - const { t } = useI18n(); 93 + const { t } = useI18n('sys.login');
93 94
94 // const openLoginVerifyRef = computed(() => appStore.getProjectConfig.openLoginVerify); 95 // const openLoginVerifyRef = computed(() => appStore.getProjectConfig.openLoginVerify);
95 96
@@ -103,10 +104,8 @@ @@ -103,10 +104,8 @@
103 }); 104 });
104 105
105 const formRules = reactive({ 106 const formRules = reactive({
106 - account: [{ required: true, message: t('sys.login.accountPlaceholder'), trigger: 'blur' }],  
107 - password: [  
108 - { required: true, message: t('sys.login.passwordPlaceholder'), trigger: 'blur' },  
109 - ], 107 + account: [{ required: true, message: t('accountPlaceholder'), trigger: 'blur' }],
  108 + password: [{ required: true, message: t('passwordPlaceholder'), trigger: 'blur' }],
110 // verify: unref(openLoginVerifyRef) ? [{ required: true, message: '请通过验证码校验' }] : [], 109 // verify: unref(openLoginVerifyRef) ? [{ required: true, message: '请通过验证码校验' }] : [],
111 }); 110 });
112 111
@@ -131,8 +130,8 @@ @@ -131,8 +130,8 @@
131 ); 130 );
132 if (userInfo) { 131 if (userInfo) {
133 notification.success({ 132 notification.success({
134 - message: t('sys.login.loginSuccessTitle'),  
135 - description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realName}`, 133 + message: t('loginSuccessTitle'),
  134 + description: `${t('loginSuccessDesc')}: ${userInfo.realName}`,
136 duration: 3, 135 duration: 3,
137 }); 136 });
138 } 137 }
@@ -154,6 +153,7 @@ @@ -154,6 +153,7 @@
154 title: globSetting && globSetting.title, 153 title: globSetting && globSetting.title,
155 logo, 154 logo,
156 t, 155 t,
  156 + showLocale: locale.show,
157 }; 157 };
158 }, 158 },
159 }); 159 });