Commit e5f8ce3fd8ec25c6fdb122867cd33e4e84a6f43f
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
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 '@ant-design/icons-vue'; | @@ -8,18 +8,21 @@ import { GithubFilled } from '@ant-design/icons-vue'; | ||
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 ©2020 Vben Admin</div> | 27 | <div>Copyright ©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 '/@/hooks/event/useWindowSizeFn'; | @@ -27,6 +28,7 @@ import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'; | ||
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 '/@/store/modules/error'; | @@ -34,7 +36,8 @@ import { errorStore } from '/@/store/modules/error'; | ||
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 '/@/utils'; | @@ -16,6 +16,7 @@ import { openWindow } from '/@/utils'; | ||
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<MenuItemProps> = (props) => { | @@ -43,6 +44,7 @@ const MenuItem: FunctionalComponent<MenuItemProps> = (props) => { | ||
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 '/@/assets/images/header.jpg'; | @@ -9,11 +9,13 @@ import headerImg from '/@/assets/images/header.jpg'; | ||
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 './useTabDropdown'; | @@ -13,6 +13,7 @@ import { useTabDropdown } from './useTabDropdown'; | ||
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 '/@/components/Dropdown/index'; | @@ -2,6 +2,10 @@ import { DropMenu } from '/@/components/Dropdown/index'; | ||
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 '/@/hooks/setting/useMenuSetting'; | @@ -18,6 +18,7 @@ import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; | ||
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 = () => { | @@ -120,8 +122,8 @@ const FooterButton: FunctionalComponent = () => { | ||
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 = () => { | @@ -131,7 +133,7 @@ const FooterButton: FunctionalComponent = () => { | ||
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 = () => { | @@ -149,7 +151,7 @@ const FooterButton: FunctionalComponent = () => { | ||
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 = () => { | @@ -157,7 +159,7 @@ const FooterButton: FunctionalComponent = () => { | ||
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 = () => { | @@ -165,7 +167,7 @@ const FooterButton: FunctionalComponent = () => { | ||
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
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
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
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
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
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 'vue-router'; | @@ -12,9 +14,8 @@ import { useRoute } from 'vue-router'; | ||
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 | }); |