提交 e5f8ce3f 编写于 作者: V vben

feat: multi-language layout

上级 cedba37e
...@@ -6,7 +6,7 @@ function createFakeUserList() { ...@@ -6,7 +6,7 @@ function createFakeUserList() {
{ {
userId: '1', userId: '1',
username: 'vben', username: 'vben',
realName: 'Vben', realName: 'Vben Admin',
desc: 'manager', desc: 'manager',
password: '123456', password: '123456',
token: 'fakeToken1', token: 'fakeToken1',
......
import AppLocalPicker from './src/AppLocalPicker.vue'; import AppLocalePicker from './src/AppLocalePicker.vue';
import AppPageFooter from './src/AppPageFooter.vue'; import AppPageFooter from './src/AppPageFooter.vue';
import AppLogo from './src/AppLogo.vue'; import AppLogo from './src/AppLogo.vue';
import { withInstall } from '../util'; import { withInstall } from '../util';
export { AppLocalPicker, AppPageFooter, AppLogo }; export { AppLocalePicker, AppPageFooter, AppLogo };
export default withInstall(AppLocalPicker, AppPageFooter, AppLogo); export default withInstall(AppLocalePicker, AppPageFooter, AppLogo);
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
:dropMenuList="localeList" :dropMenuList="localeList"
:selectedKeys="selectedKeys" :selectedKeys="selectedKeys"
@menuEvent="handleMenuEvent" @menuEvent="handleMenuEvent"
overlayClassName="app-locale-picker-overlay"
> >
<span class="app-local-picker"> <span class="app-local-picker">
<GlobalOutlined class="app-local-picker__icon" /> <GlobalOutlined class="app-local-picker__icon" />
...@@ -30,8 +31,12 @@ ...@@ -30,8 +31,12 @@
type: Boolean, type: Boolean,
default: true, default: true,
}, },
reload: {
type: Boolean,
default: false,
},
}, },
setup() { setup(props) {
const { localeList } = useLocaleSetting(); const { localeList } = useLocaleSetting();
const selectedKeys = ref<string[]>([]); const selectedKeys = ref<string[]>([]);
...@@ -50,6 +55,7 @@ ...@@ -50,6 +55,7 @@
function toggleLocale(lang: LocaleType | string) { function toggleLocale(lang: LocaleType | string) {
changeLocale(lang as LocaleType); changeLocale(lang as LocaleType);
selectedKeys.value = [lang as string]; selectedKeys.value = [lang as string];
props.reload && location.reload();
} }
function handleMenuEvent(menu: DropMenu) { function handleMenuEvent(menu: DropMenu) {
...@@ -61,7 +67,13 @@ ...@@ -61,7 +67,13 @@
}); });
</script> </script>
<style lang="less" scoped> <style lang="less">
.app-locale-picker-overlay {
.ant-dropdown-menu-item {
min-width: 160px;
}
}
.app-local-picker { .app-local-picker {
display: flex; display: flex;
align-items: center; align-items: center;
......
import type { Trigger } from './types';
import { defineComponent, computed, unref } from 'vue'; import { defineComponent, computed, unref } from 'vue';
import { Dropdown, Menu, Divider } from 'ant-design-vue'; import { Dropdown, Menu } from 'ant-design-vue';
import Icon from '/@/components/Icon/index'; import Icon from '/@/components/Icon/index';
import { basicDropdownProps } from './props'; import { basicDropdownProps } from './props';
import { getSlot } from '/@/utils/helper/tsxHelper'; import { getSlot } from '/@/utils/helper/tsxHelper';
import { Trigger } from './types';
export default defineComponent({ export default defineComponent({
name: 'Dropdown', name: 'Dropdown',
...@@ -24,7 +25,7 @@ export default defineComponent({ ...@@ -24,7 +25,7 @@ export default defineComponent({
<Menu onClick={handleClickMenu} selectedKeys={props.selectedKeys}> <Menu onClick={handleClickMenu} selectedKeys={props.selectedKeys}>
{() => ( {() => (
<> <>
{unref(getMenuList).map((item, index) => { {unref(getMenuList).map((item) => {
const { disabled, icon, text, divider, event } = item; const { disabled, icon, text, divider, event } = item;
return [ return [
<Menu.Item key={`${event}`} disabled={disabled}> <Menu.Item key={`${event}`} disabled={disabled}>
...@@ -35,7 +36,8 @@ export default defineComponent({ ...@@ -35,7 +36,8 @@ export default defineComponent({
</> </>
)} )}
</Menu.Item>, </Menu.Item>,
divider && <Divider key={`d-${index}`} />, // @ts-ignore
divider && <Menu.Divider key={`d-${event}`} />,
]; ];
})} })}
</> </>
......
...@@ -13,20 +13,17 @@ ...@@ -13,20 +13,17 @@
} }
} }
// .ant-form-item-label {
// text-align: unset;
// }
// ================================= // =================================
// ==============descriptions======= // ==============descriptions=======
// ================================= // =================================
.ant-descriptions-bordered .ant-descriptions-item-label { // .ant-descriptions-bordered .ant-descriptions-item-label {
background-color: @background-color-light; // background-color: @background-color-light;
} // }
// .ant-descriptions .ant-descriptions-item-content {
// color: @text-color-call-out;
// }
.ant-descriptions .ant-descriptions-item-content {
color: @text-color-call-out;
}
// ================================= // =================================
// ==============modal message====== // ==============modal message======
// ================================= // =================================
...@@ -46,68 +43,6 @@ ...@@ -46,68 +43,6 @@
color: @primary-color !important; color: @primary-color !important;
} }
.ant-modal-mask {
background-color: rgba(0, 0, 0, 0.2);
}
// =================================
// ==============menu===============
// =================================
.ant-menu-item {
&-selected {
a {
color: @primary-color;
&:hover {
color: @primary-color;
}
}
}
}
// =================================
// ==============dropdown===========
// =================================
.ant-dropdown {
.ant-divider {
margin: 4px 0;
}
&-menu-item {
line-height: 30px;
color: @text-color-call-out;
&:hover {
color: inherit;
background-color: @border-color-shallow-light;
}
}
}
// =================================
// ==============back-top===========
// =================================
.ant-back-top {
right: 50px;
bottom: 60px;
}
// =================================
// ==============calendar===========
// =================================
.ant-calendar-picker {
width: 100%;
}
// =================================
// ==============tooltip============
// =================================
.ant-tooltip {
&-inner {
padding: 6px 16px;
line-height: 20px;
color: @white;
background: @text-color-base;
border-radius: 4px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
}
// ================================= // =================================
// ==============form=============== // ==============form===============
// ================================= // =================================
......
...@@ -5,24 +5,9 @@ ...@@ -5,24 +5,9 @@
.ant-input { .ant-input {
&-number { &-number {
min-width: 110px; min-width: 110px;
border-color: @border-color-shallow-dark;
} }
} }
.ant-input-affix-wrapper:hover .ant-input:not(.ant-input-disabled) {
border-color: @info-color;
}
.ant-input-disabled,
.ant-select-disabled .ant-select-selection,
.ant-cascader-picker-label {
color: @text-color-base !important;
}
.ant-input-disabled {
background-color: @background-color-light;
}
.ant-input-affix-wrapper .ant-input-suffix { .ant-input-affix-wrapper .ant-input-suffix {
right: 9px; right: 9px;
} }
......
...@@ -13,6 +13,9 @@ ...@@ -13,6 +13,9 @@
} }
@white: #fff; @white: #fff;
@content-bg: #f0f2f5;
@info-color: @primary-color; @info-color: @primary-color;
@basic-mask-color: fade(@white, 30%); @basic-mask-color: fade(@white, 30%);
...@@ -24,7 +27,7 @@ ...@@ -24,7 +27,7 @@
@iconify-bg-color: #5551; @iconify-bg-color: #5551;
// ================================= // =================================
// ==============border-color============ // ==============border-color=======
// ================================= // =================================
// Dark-dark // Dark-dark
......
...@@ -54,8 +54,7 @@ input::-ms-reveal { ...@@ -54,8 +54,7 @@ input::-ms-reveal {
} }
body { body {
// font-family: 'Microsoft YaHei,微软雅黑,Arial,sans-serif,Helvetica Neue,Helvetica,Pingfang SC,Hiragino Sans GB'; 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';
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';
font-style: normal; font-style: normal;
font-weight: normal; font-weight: normal;
line-height: 1.428571429; // 20/14 line-height: 1.428571429; // 20/14
...@@ -159,17 +158,3 @@ embed, ...@@ -159,17 +158,3 @@ embed,
object { object {
vertical-align: baseline !important; vertical-align: baseline !important;
} }
#app {
width: 100%;
height: 100%;
}
.ant-layout {
background: #f0f2f5;
// &-content {
// position: relative;
// overflow: hidden;
// }
}
...@@ -16,33 +16,33 @@ ...@@ -16,33 +16,33 @@
color: @color; color: @color;
} }
} }
// 文本截断 // Text truncation
.text-truncate() { .text-truncate() {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
/* 强制不换行 */ /* Force no line break */
.word-nowrap() { .word-nowrap() {
word-wrap: normal; word-wrap: normal;
white-space: nowrap; white-space: nowrap;
} }
/* 强制换行 */ /* Force line break */
.break-all() { .break-all() {
word-break: break-all; word-break: break-all;
word-wrap: break-word; word-wrap: break-word;
white-space: normal; white-space: normal;
} }
// 禁止选中 // Prohibit selection
.unselect() { .unselect() {
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
} }
/* 适用于webkit内核和移动端 */ /* Suitable for webkit core and mobile */
.ellipsis-multiple(@num: 1) { .ellipsis-multiple(@num: 1) {
display: -webkit-box; display: -webkit-box;
overflow: hidden; overflow: hidden;
......
#app {
width: 100%;
height: 100%;
}
.app-svg-loading { .app-svg-loading {
position: relative; position: relative;
width: auto; width: auto;
} }
// =================================
// ==============scrollbar==========
// =================================
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 6px; width: 6px;
height: 6px; height: 6px;
......
@import 'var/link';
@import './mixins/reset-text.less';
@import 'color/index';
.reset() {
html,
body {
width: 100%;
height: 100%;
&.color-weak {
filter: invert(80%);
}
&.gray-mode {
filter: grayscale(100%);
filter: progid:dximagetransform.microsoft.basicimage(grayscale=1);
}
}
input::-ms-clear,
input::-ms-reveal {
display: none;
}
body {
.reset-text();
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 0;
margin-bottom: 0.5em;
font-weight: 500;
color: @heading-color;
}
ul,
ol {
list-style: none;
}
li {
list-style-type: none;
}
img {
vertical-align: top;
border: 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
a:focus,
a:active {
outline: none;
}
i,
em {
font-style: normal;
}
div:focus {
outline: none;
}
a {
color: @link-color;
text-decoration: @link-decoration;
cursor: pointer;
background-color: transparent; // remove the gray background on active links in IE 10.
outline: none;
transition: color 0.3s;
-webkit-text-decoration-skip: objects; // remove gaps in links underline in iOS 8+ and Safari 8+.
&:hover {
color: @link-hover-color;
}
&:active {
color: @link-active-color;
}
&:active,
&:hover {
text-decoration: @link-hover-decoration;
outline: 0;
}
&[disabled] {
color: @disabled-color;
pointer-events: none;
cursor: not-allowed;
}
}
}
.transition-default() { .transition-default() {
&-enter-active, &-enter-active,
&-leave-active { &-leave-active {
transition: 0.1s cubic-bezier(0.25, 0.8, 0.5, 1) !important; transition: 0.3s cubic-bezier(0.25, 0.8, 0.5, 1) !important;
} }
&-move { &-move {
transition: transform 0.2s; transition: transform 0.4s;
} }
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
/* fade-slide */ /* fade-slide */
.fade-slide-leave-active, .fade-slide-leave-active,
.fade-slide-enter-active { .fade-slide-enter-active {
transition: all 0.2s; transition: all 0.3s;
} }
.fade-slide-enter-from { .fade-slide-enter-from {
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
// //
@side-drag-z-index: 200; @side-drag-z-index: 200;
@page-loading-z-index: 10000; @page-loading-z-index: 10000;
// left-menu // left-menu
......
...@@ -19,10 +19,20 @@ export function useLocaleSetting() { ...@@ -19,10 +19,20 @@ export function useLocaleSetting() {
// get Fallback Locales // get Fallback Locales
const getFallbackLocale = computed((): string => unref(getLocale).fallback); const getFallbackLocale = computed((): string => unref(getLocale).fallback);
const getShowLocale = computed(() => unref(getLocale).show);
// Set locale configuration // Set locale configuration
function setLocale(locale: Partial<LocaleSetting>): void { function setLocale(locale: Partial<LocaleSetting>): void {
appStore.commitProjectConfigState({ locale }); appStore.commitProjectConfigState({ locale });
} }
return { getLocale, getLang, localeList, setLocale, getAvailableLocales, getFallbackLocale }; return {
getLocale,
getLang,
localeList,
setLocale,
getShowLocale,
getAvailableLocales,
getFallbackLocale,
};
} }
import { getI18n } from '/@/setup/i18n';
export function useI18n(namespace?: string) {
const { t, ...methods } = getI18n().global;
function getKey(key: string) {
if (!namespace) {
return key;
}
if (key.startsWith(namespace)) {
return key;
}
return `${namespace}.${key}`;
}
return {
...methods,
t: (key: string, ...arg: Parameters<typeof t>) => {
return t(getKey(key), ...arg);
},
};
}
...@@ -65,10 +65,3 @@ export function useLocale() { ...@@ -65,10 +65,3 @@ export function useLocale() {
antConfigLocale: antConfigLocaleRef, antConfigLocale: antConfigLocaleRef,
}; };
} }
/**
* For non-setup setting
*/
export function useExternalI18n() {
return getI18n().global;
}
...@@ -8,18 +8,21 @@ import { GithubFilled } from '@ant-design/icons-vue'; ...@@ -8,18 +8,21 @@ import { GithubFilled } from '@ant-design/icons-vue';
import { DOC_URL, GITHUB_URL, SITE_URL } from '/@/settings/siteSetting'; import { DOC_URL, GITHUB_URL, SITE_URL } from '/@/settings/siteSetting';
import { openWindow } from '/@/utils'; import { openWindow } from '/@/utils';
import { useI18n } from '/@/hooks/web/useI18n';
export default defineComponent({ export default defineComponent({
name: 'LayoutContent', name: 'LayoutContent',
setup() { setup() {
const { t } = useI18n('layout.footer');
return () => { return () => {
return ( return (
<Layout.Footer class="layout-footer"> <Layout.Footer class="layout-footer">
{() => ( {() => (
<> <>
<div class="layout-footer__links"> <div class="layout-footer__links">
<a onClick={() => openWindow(SITE_URL)}>在线预览</a> <a onClick={() => openWindow(SITE_URL)}>{t('onlinePreview')}</a>
<GithubFilled onClick={() => openWindow(GITHUB_URL)} class="github" /> <GithubFilled onClick={() => openWindow(GITHUB_URL)} class="github" />
<a onClick={() => openWindow(DOC_URL)}>在线文档</a> <a onClick={() => openWindow(DOC_URL)}>{t('onlineDocument')}</a>
</div> </div>
<div>Copyright &copy;2020 Vben Admin</div> <div>Copyright &copy;2020 Vben Admin</div>
</> </>
......
import './index.less'; import './index.less';
import type { FunctionalComponent } from 'vue'; import type { FunctionalComponent } from 'vue';
import type { Component } from '/@/components/types';
import { defineComponent, unref, computed, ref, nextTick } from 'vue'; import { defineComponent, unref, computed, ref, nextTick } from 'vue';
...@@ -27,6 +28,7 @@ import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'; ...@@ -27,6 +28,7 @@ import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'; import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { useRootSetting } from '/@/hooks/setting/useRootSetting'; import { useRootSetting } from '/@/hooks/setting/useRootSetting';
import { useLocaleSetting } from '/@/hooks/setting/useLocaleSetting';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
...@@ -34,7 +36,8 @@ import { errorStore } from '/@/store/modules/error'; ...@@ -34,7 +36,8 @@ import { errorStore } from '/@/store/modules/error';
import { PageEnum } from '/@/enums/pageEnum'; import { PageEnum } from '/@/enums/pageEnum';
import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum'; import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
import { Component } from '/@/components/types'; import { AppLocalePicker } from '/@/components/Application';
import { useI18n } from '/@/hooks/web/useI18n';
interface TooltipItemProps { interface TooltipItemProps {
title: string; title: string;
...@@ -65,9 +68,11 @@ export default defineComponent({ ...@@ -65,9 +68,11 @@ export default defineComponent({
const logoWidthRef = ref(200); const logoWidthRef = ref(200);
const logoRef = ref<ComponentRef>(null); const logoRef = ref<ComponentRef>(null);
const { refreshPage } = useTabs(); const { refreshPage } = useTabs();
const { t } = useI18n('layout.header');
const { getShowTopMenu, getShowHeaderTrigger, getSplit, getTopMenuAlign } = useMenuSetting(); const { getShowTopMenu, getShowHeaderTrigger, getSplit, getTopMenuAlign } = useMenuSetting();
const { getShowLocale } = useLocaleSetting();
const { getUseErrorHandle, getShowBreadCrumbIcon } = useRootSetting(); const { getUseErrorHandle, getShowBreadCrumbIcon } = useRootSetting();
const { const {
...@@ -160,8 +165,8 @@ export default defineComponent({ ...@@ -160,8 +165,8 @@ export default defineComponent({
function renderActionDefault(Comp: Component | any, event: Fn) { function renderActionDefault(Comp: Component | any, event: Fn) {
return ( return (
<div class={`layout-header__action-item`} onClick={event}> <div class="layout-header__action-item" onClick={event}>
<Comp class={`layout-header__action-icon`} /> <Comp class="layout-header__action-icon" />
</div> </div>
); );
} }
...@@ -170,7 +175,7 @@ export default defineComponent({ ...@@ -170,7 +175,7 @@ export default defineComponent({
return ( return (
<div class={`layout-header__action`}> <div class={`layout-header__action`}>
{unref(getUseErrorHandle) && ( {unref(getUseErrorHandle) && (
<TooltipItem title="错误日志"> <TooltipItem title={t('layout.header.tooltipErrorLog')}>
{() => ( {() => (
<Badge <Badge
count={errorStore.getErrorListCountState} count={errorStore.getErrorListCountState}
...@@ -185,23 +190,31 @@ export default defineComponent({ ...@@ -185,23 +190,31 @@ export default defineComponent({
)} )}
{unref(getUseLockPage) && ( {unref(getUseLockPage) && (
<TooltipItem title="锁定屏幕"> <TooltipItem title={t('layout.header.tooltipLock')}>
{() => renderActionDefault(LockOutlined, handleLockPage)} {() => renderActionDefault(LockOutlined, handleLockPage)}
</TooltipItem> </TooltipItem>
)} )}
{unref(getShowNotice) && ( {unref(getShowNotice) && (
<TooltipItem title="消息通知">{() => <NoticeAction />}</TooltipItem> <TooltipItem title={t('layout.header.tooltipNotify')}>
{() => <NoticeAction />}
</TooltipItem>
)} )}
{unref(getShowRedo) && ( {unref(getShowRedo) && (
<TooltipItem title="刷新"> <TooltipItem title={t('layout.header.tooltipRedo')}>
{() => renderActionDefault(RedoOutlined, refreshPage)} {() => renderActionDefault(RedoOutlined, refreshPage)}
</TooltipItem> </TooltipItem>
)} )}
{unref(getShowFullScreen) && ( {unref(getShowFullScreen) && (
<TooltipItem title={unref(isFullscreenRef) ? '退出全屏' : '全屏'}> <TooltipItem
title={
unref(isFullscreenRef)
? t('layout.header.tooltipExitFull')
: t('layout.header.tooltipEntryFull')
}
>
{() => { {() => {
const Icon = !unref(isFullscreenRef) ? ( const Icon = !unref(isFullscreenRef) ? (
<FullscreenOutlined /> <FullscreenOutlined />
...@@ -212,7 +225,14 @@ export default defineComponent({ ...@@ -212,7 +225,14 @@ export default defineComponent({
}} }}
</TooltipItem> </TooltipItem>
)} )}
<UserDropdown class={`layout-header__user-dropdown`} /> <UserDropdown class="layout-header__user-dropdown" />
{unref(getShowLocale) && (
<AppLocalePicker
reload={true}
showText={false}
class="layout-header__action-item locale"
/>
)}
</div> </div>
); );
} }
......
// components // components
import { Dropdown, Menu, Divider } from 'ant-design-vue'; import { Dropdown, Menu } from 'ant-design-vue';
import { defineComponent, computed, unref } from 'vue'; import { defineComponent, computed, unref } from 'vue';
...@@ -16,6 +16,7 @@ import { openWindow } from '/@/utils'; ...@@ -16,6 +16,7 @@ import { openWindow } from '/@/utils';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'; import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { FunctionalComponent } from 'vue'; import { FunctionalComponent } from 'vue';
import { useI18n } from '/@/hooks/web/useI18n';
type MenuEvent = 'loginOut' | 'doc'; type MenuEvent = 'loginOut' | 'doc';
interface MenuItemProps { interface MenuItemProps {
...@@ -43,6 +44,7 @@ const MenuItem: FunctionalComponent<MenuItemProps> = (props) => { ...@@ -43,6 +44,7 @@ const MenuItem: FunctionalComponent<MenuItemProps> = (props) => {
export default defineComponent({ export default defineComponent({
name: 'UserDropdown', name: 'UserDropdown',
setup() { setup() {
const { t } = useI18n('layout.header');
const { getShowDoc } = useHeaderSetting(); const { getShowDoc } = useHeaderSetting();
const getUserInfo = computed(() => { const getUserInfo = computed(() => {
...@@ -89,9 +91,14 @@ export default defineComponent({ ...@@ -89,9 +91,14 @@ export default defineComponent({
<Menu onClick={handleMenuClick}> <Menu onClick={handleMenuClick}>
{() => ( {() => (
<> <>
{showDoc && <MenuItem key="doc" text="文档" icon="gg:loadbar-doc" />} {showDoc && <MenuItem key="doc" text={t('dropdownItemDoc')} icon="gg:loadbar-doc" />}
{showDoc && <Divider />} {/* @ts-ignore */}
<MenuItem key="loginOut" text="退出系统" icon="ant-design:poweroff-outlined" /> {showDoc && <Menu.Divider />}
<MenuItem
key="loginOut"
text={t('dropdownItemLoginOut')}
icon="ant-design:poweroff-outlined"
/>
</> </>
)} )}
</Menu> </Menu>
...@@ -100,7 +107,7 @@ export default defineComponent({ ...@@ -100,7 +107,7 @@ export default defineComponent({
return () => { return () => {
return ( return (
<Dropdown placement="bottomLeft"> <Dropdown placement="bottomLeft" overlayClassName="app-layout-header-user-dropdown-overlay">
{{ {{
default: () => renderSlotsDefault(), default: () => renderSlotsDefault(),
overlay: () => renderSlotOverlay(), overlay: () => renderSlotOverlay(),
......
...@@ -92,6 +92,11 @@ ...@@ -92,6 +92,11 @@
&:hover { &:hover {
background: @header-light-bg-hover-color; background: @header-light-bg-hover-color;
} }
&.locale {
padding: 0 10px;
color: rgba(0, 0, 0, 0.65);
}
} }
&-icon { &-icon {
...@@ -221,3 +226,9 @@ ...@@ -221,3 +226,9 @@
} }
} }
} }
.app-layout-header-user-dropdown-overlay {
.ant-dropdown-menu-item {
min-width: 160px;
}
}
...@@ -2,9 +2,10 @@ ...@@ -2,9 +2,10 @@
.default-layout { .default-layout {
display: flex; display: flex;
flex-direction: column;
width: 100%; width: 100%;
min-height: 100%; min-height: 100%;
background: @content-bg;
flex-direction: column;
> .ant-layout { > .ant-layout {
min-height: 100%; min-height: 100%;
......
...@@ -9,11 +9,13 @@ import headerImg from '/@/assets/images/header.jpg'; ...@@ -9,11 +9,13 @@ import headerImg from '/@/assets/images/header.jpg';
import { appStore } from '/@/store/modules/app'; import { appStore } from '/@/store/modules/app';
import { userStore } from '/@/store/modules/user'; import { userStore } from '/@/store/modules/user';
import { useI18n } from '/@/hooks/web/useI18n';
const prefixCls = 'lock-modal'; const prefixCls = 'lock-modal';
export default defineComponent({ export default defineComponent({
name: 'LockModal', name: 'LockModal',
setup(_, { attrs }) { setup(_, { attrs }) {
const { t } = useI18n('layout.header');
const [register, { closeModal }] = useModalInner(); const [register, { closeModal }] = useModalInner();
const [registerForm, { validateFields, resetFields }] = useForm({ const [registerForm, { validateFields, resetFields }] = useForm({
...@@ -21,7 +23,7 @@ export default defineComponent({ ...@@ -21,7 +23,7 @@ export default defineComponent({
schemas: [ schemas: [
{ {
field: 'password', field: 'password',
label: '锁屏密码', label: t('lockScreenPassword'),
component: 'InputPassword', component: 'InputPassword',
required: true, required: true,
}, },
...@@ -49,7 +51,13 @@ export default defineComponent({ ...@@ -49,7 +51,13 @@ export default defineComponent({
} }
return () => ( return () => (
<BasicModal footer={null} title="锁定屏幕" {...attrs} class={prefixCls} onRegister={register}> <BasicModal
footer={null}
title={t('lockScreen')}
{...attrs}
class={prefixCls}
onRegister={register}
>
{() => ( {() => (
<div class={`${prefixCls}__entry`}> <div class={`${prefixCls}__entry`}>
<div class={`${prefixCls}__header`}> <div class={`${prefixCls}__header`}>
...@@ -61,10 +69,10 @@ export default defineComponent({ ...@@ -61,10 +69,10 @@ export default defineComponent({
<div class={`${prefixCls}__footer`}> <div class={`${prefixCls}__footer`}>
<Button type="primary" block class="mt-2" onClick={lock}> <Button type="primary" block class="mt-2" onClick={lock}>
{() => '锁屏'} {() => t('lockScreenBtn')}
</Button> </Button>
<Button block class="mt-2" onClick={lock.bind(null, false)}> <Button block class="mt-2" onClick={lock.bind(null, false)}>
{() => ' 不设置密码锁屏'} {() => t('notLockScreenPassword')}
</Button> </Button>
</div> </div>
</div> </div>
......
...@@ -13,6 +13,7 @@ import { useTabDropdown } from './useTabDropdown'; ...@@ -13,6 +13,7 @@ import { useTabDropdown } from './useTabDropdown';
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'; import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'; import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
import { useI18n } from '/@/hooks/web/useI18n';
const ExtraContent: FunctionalComponent = () => { const ExtraContent: FunctionalComponent = () => {
return ( return (
...@@ -56,6 +57,7 @@ export default defineComponent({ ...@@ -56,6 +57,7 @@ export default defineComponent({
}, },
}, },
setup(props) { setup(props) {
const { t } = useI18n('layout.multipleTab');
const { getShowMenu } = useMenuSetting(); const { getShowMenu } = useMenuSetting();
const { getShowHeader } = useHeaderSetting(); const { getShowHeader } = useHeaderSetting();
const { getShowQuick } = useMultipleTabSetting(); const { getShowQuick } = useMultipleTabSetting();
...@@ -71,7 +73,10 @@ export default defineComponent({ ...@@ -71,7 +73,10 @@ export default defineComponent({
const { getDropMenuList, handleMenuEvent } = useTabDropdown(props as TabContentProps); const { getDropMenuList, handleMenuEvent } = useTabDropdown(props as TabContentProps);
return () => { return () => {
const scaleAction = getScaleAction(unref(getIsScale) ? '收起' : '展开', unref(getIsScale)); const scaleAction = getScaleAction(
unref(getIsScale) ? t('putAway') : t('unfold'),
unref(getIsScale)
);
const dropMenuList = unref(getDropMenuList) || []; const dropMenuList = unref(getDropMenuList) || [];
const isTab = unref(getIsTab); const isTab = unref(getIsTab);
......
...@@ -2,6 +2,10 @@ import { DropMenu } from '/@/components/Dropdown/index'; ...@@ -2,6 +2,10 @@ import { DropMenu } from '/@/components/Dropdown/index';
import { AppRouteRecordRaw } from '/@/router/types'; import { AppRouteRecordRaw } from '/@/router/types';
import type { TabItem } from '/@/store/modules/tab'; import type { TabItem } from '/@/store/modules/tab';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n('layout.multipleTab');
export enum TabContentEnum { export enum TabContentEnum {
TAB_TYPE, TAB_TYPE,
EXTRA_TYPE, EXTRA_TYPE,
...@@ -37,40 +41,40 @@ export function getActions() { ...@@ -37,40 +41,40 @@ export function getActions() {
const REFRESH_PAGE: DropMenu = { const REFRESH_PAGE: DropMenu = {
icon: 'ant-design:reload-outlined', icon: 'ant-design:reload-outlined',
event: MenuEventEnum.REFRESH_PAGE, event: MenuEventEnum.REFRESH_PAGE,
text: '刷新', text: t('redo'),
disabled: false, disabled: false,
}; };
const CLOSE_CURRENT: DropMenu = { const CLOSE_CURRENT: DropMenu = {
icon: 'ant-design:close-outlined', icon: 'ant-design:close-outlined',
event: MenuEventEnum.CLOSE_CURRENT, event: MenuEventEnum.CLOSE_CURRENT,
text: '关闭', text: t('close'),
disabled: false, disabled: false,
divider: true, divider: true,
}; };
const CLOSE_LEFT: DropMenu = { const CLOSE_LEFT: DropMenu = {
icon: 'ant-design:pic-left-outlined', icon: 'ant-design:pic-left-outlined',
event: MenuEventEnum.CLOSE_LEFT, event: MenuEventEnum.CLOSE_LEFT,
text: '关闭左侧', text: t('closeLeft'),
disabled: false, disabled: false,
divider: false, divider: false,
}; };
const CLOSE_RIGHT: DropMenu = { const CLOSE_RIGHT: DropMenu = {
icon: 'ant-design:pic-right-outlined', icon: 'ant-design:pic-right-outlined',
event: MenuEventEnum.CLOSE_RIGHT, event: MenuEventEnum.CLOSE_RIGHT,
text: '关闭右侧', text: t('closeRight'),
disabled: false, disabled: false,
divider: true, divider: true,
}; };
const CLOSE_OTHER: DropMenu = { const CLOSE_OTHER: DropMenu = {
icon: 'ant-design:pic-center-outlined', icon: 'ant-design:pic-center-outlined',
event: MenuEventEnum.CLOSE_OTHER, event: MenuEventEnum.CLOSE_OTHER,
text: '关闭其他', text: t('closeOther'),
disabled: false, disabled: false,
}; };
const CLOSE_ALL: DropMenu = { const CLOSE_ALL: DropMenu = {
icon: 'ant-design:line-outlined', icon: 'ant-design:line-outlined',
event: MenuEventEnum.CLOSE_ALL, event: MenuEventEnum.CLOSE_ALL,
text: '关闭全部', text: t('closeAll'),
disabled: false, disabled: false,
}; };
return [REFRESH_PAGE, CLOSE_CURRENT, CLOSE_LEFT, CLOSE_RIGHT, CLOSE_OTHER, CLOSE_ALL]; return [REFRESH_PAGE, CLOSE_CURRENT, CLOSE_LEFT, CLOSE_RIGHT, CLOSE_OTHER, CLOSE_ALL];
......
...@@ -18,6 +18,7 @@ import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; ...@@ -18,6 +18,7 @@ import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'; import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'; import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting'; import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
import { useI18n } from '/@/hooks/web/useI18n';
import { updateColorWeak, updateGrayMode } from '/@/setup/theme'; import { updateColorWeak, updateGrayMode } from '/@/setup/theme';
...@@ -55,6 +56,7 @@ interface ThemePickerProps { ...@@ -55,6 +56,7 @@ interface ThemePickerProps {
} }
const { createSuccessModal, createMessage } = useMessage(); const { createSuccessModal, createMessage } = useMessage();
const { t } = useI18n('layout.setting');
/** /**
* Menu type Picker comp * Menu type Picker comp
...@@ -120,8 +122,8 @@ const FooterButton: FunctionalComponent = () => { ...@@ -120,8 +122,8 @@ const FooterButton: FunctionalComponent = () => {
const { isSuccessRef } = useCopyToClipboard(JSON.stringify(unref(getRootSetting), null, 2)); const { isSuccessRef } = useCopyToClipboard(JSON.stringify(unref(getRootSetting), null, 2));
unref(isSuccessRef) && unref(isSuccessRef) &&
createSuccessModal({ createSuccessModal({
title: '操作成功', title: t('operatingTitle'),
content: '复制成功,请到 src/settings/projectSetting.ts 中修改配置!', content: t('operatingContent'),
}); });
} }
function handleResetSetting() { function handleResetSetting() {
...@@ -131,7 +133,7 @@ const FooterButton: FunctionalComponent = () => { ...@@ -131,7 +133,7 @@ const FooterButton: FunctionalComponent = () => {
// updateTheme(themeColor); // updateTheme(themeColor);
updateColorWeak(colorWeak); updateColorWeak(colorWeak);
updateGrayMode(grayMode); updateGrayMode(grayMode);
createMessage.success('重置成功!'); createMessage.success(t('resetSuccess'));
} catch (error) { } catch (error) {
createMessage.error(error); createMessage.error(error);
} }
...@@ -149,7 +151,7 @@ const FooterButton: FunctionalComponent = () => { ...@@ -149,7 +151,7 @@ const FooterButton: FunctionalComponent = () => {
{() => ( {() => (
<> <>
<CopyOutlined class="mr-2" /> <CopyOutlined class="mr-2" />
拷贝 {t('copyBtn')}
</> </>
)} )}
</Button> </Button>
...@@ -157,7 +159,7 @@ const FooterButton: FunctionalComponent = () => { ...@@ -157,7 +159,7 @@ const FooterButton: FunctionalComponent = () => {
{() => ( {() => (
<> <>
<RedoOutlined class="mr-2" /> <RedoOutlined class="mr-2" />
重置 {t('resetBtn')}
</> </>
)} )}
</Button> </Button>
...@@ -165,7 +167,7 @@ const FooterButton: FunctionalComponent = () => { ...@@ -165,7 +167,7 @@ const FooterButton: FunctionalComponent = () => {
{() => ( {() => (
<> <>
<RedoOutlined class="mr-2" /> <RedoOutlined class="mr-2" />
清空缓存并返回登录页 {t('clearBtn')}
</> </>
)} )}
</Button> </Button>
...@@ -224,7 +226,7 @@ export default defineComponent({ ...@@ -224,7 +226,7 @@ export default defineComponent({
return ( return (
<> <>
<MenuTypePicker /> <MenuTypePicker />
{renderSwitchItem('分割菜单', { {renderSwitchItem(t('splitMenu'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.MENU_SPLIT, e); baseHandler(HandlerEnum.MENU_SPLIT, e);
}, },
...@@ -238,7 +240,7 @@ export default defineComponent({ ...@@ -238,7 +240,7 @@ export default defineComponent({
function renderTheme() { function renderTheme() {
return ( return (
<> <>
<Divider>{() => '顶栏主题'}</Divider> <Divider>{() => t('headerTheme')}</Divider>
<ThemePicker <ThemePicker
colorList={HEADER_PRESET_BG_COLOR_LIST} colorList={HEADER_PRESET_BG_COLOR_LIST}
def={unref(getHeaderBgColor)} def={unref(getHeaderBgColor)}
...@@ -246,7 +248,7 @@ export default defineComponent({ ...@@ -246,7 +248,7 @@ export default defineComponent({
baseHandler(HandlerEnum.HEADER_THEME, e); baseHandler(HandlerEnum.HEADER_THEME, e);
}} }}
/> />
<Divider>{() => '菜单主题'}</Divider> <Divider>{() => t('sidebarTheme')}</Divider>
<ThemePicker <ThemePicker
colorList={SIDE_BAR_BG_COLOR_LIST} colorList={SIDE_BAR_BG_COLOR_LIST}
def={unref(getMenuBgColor)} def={unref(getMenuBgColor)}
...@@ -263,56 +265,56 @@ export default defineComponent({ ...@@ -263,56 +265,56 @@ export default defineComponent({
*/ */
function renderFeatures() { function renderFeatures() {
return [ return [
renderSwitchItem('侧边菜单拖拽', { renderSwitchItem(t('menuDrag'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.MENU_HAS_DRAG, e); baseHandler(HandlerEnum.MENU_HAS_DRAG, e);
}, },
def: unref(getCanDrag), def: unref(getCanDrag),
disabled: !unref(getShowMenuRef), disabled: !unref(getShowMenuRef),
}), }),
renderSwitchItem('侧边菜单搜索', { renderSwitchItem(t('menuSearch'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.MENU_SHOW_SEARCH, e); baseHandler(HandlerEnum.MENU_SHOW_SEARCH, e);
}, },
def: unref(getShowSearch), def: unref(getShowSearch),
disabled: !unref(getShowMenuRef), disabled: !unref(getShowMenuRef),
}), }),
renderSwitchItem('侧边菜单手风琴模式', { renderSwitchItem(t('menuAccordion'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.MENU_ACCORDION, e); baseHandler(HandlerEnum.MENU_ACCORDION, e);
}, },
def: unref(getAccordion), def: unref(getAccordion),
disabled: !unref(getShowMenuRef), disabled: !unref(getShowMenuRef),
}), }),
renderSwitchItem('折叠菜单', { renderSwitchItem(t('menuCollapse'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.MENU_COLLAPSED, e); baseHandler(HandlerEnum.MENU_COLLAPSED, e);
}, },
def: unref(getCollapsed), def: unref(getCollapsed),
disabled: !unref(getShowMenuRef), disabled: !unref(getShowMenuRef),
}), }),
renderSwitchItem('折叠菜单显示名称', { renderSwitchItem(t('collapseMenuDisplayName'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.MENU_COLLAPSED_SHOW_TITLE, e); baseHandler(HandlerEnum.MENU_COLLAPSED_SHOW_TITLE, e);
}, },
def: unref(getCollapsedShowTitle), def: unref(getCollapsedShowTitle),
disabled: !unref(getShowMenuRef) || !unref(getCollapsed), disabled: !unref(getShowMenuRef) || !unref(getCollapsed),
}), }),
renderSwitchItem('固定header', { renderSwitchItem(t('fixedHeader'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.HEADER_FIXED, e); baseHandler(HandlerEnum.HEADER_FIXED, e);
}, },
def: unref(getHeaderFixed), def: unref(getHeaderFixed),
disabled: !unref(getShowHeader), disabled: !unref(getShowHeader),
}), }),
renderSwitchItem('固定Siderbar', { renderSwitchItem(t('fixedSideBar'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.MENU_FIXED, e); baseHandler(HandlerEnum.MENU_FIXED, e);
}, },
def: unref(getMenuFixed), def: unref(getMenuFixed),
disabled: !unref(getShowMenuRef), disabled: !unref(getShowMenuRef),
}), }),
renderSelectItem('顶部菜单布局', { renderSelectItem(t('topMenuLayout'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.MENU_TOP_ALIGN, e); baseHandler(HandlerEnum.MENU_TOP_ALIGN, e);
}, },
...@@ -320,7 +322,7 @@ export default defineComponent({ ...@@ -320,7 +322,7 @@ export default defineComponent({
options: topMenuAlignOptions, options: topMenuAlignOptions,
disabled: !unref(getShowHeader) || (!unref(getIsTopMenu) && !unref(getSplit)), disabled: !unref(getShowHeader) || (!unref(getIsTopMenu) && !unref(getSplit)),
}), }),
renderSelectItem('菜单折叠按钮', { renderSelectItem(t('menuCollapseButton'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.MENU_TRIGGER, e); baseHandler(HandlerEnum.MENU_TRIGGER, e);
}, },
...@@ -329,7 +331,7 @@ export default defineComponent({ ...@@ -329,7 +331,7 @@ export default defineComponent({
options: menuTriggerOptions, options: menuTriggerOptions,
}), }),
renderSelectItem('内容区域宽度', { renderSelectItem(t('contentMode'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.CONTENT_MODE, e); baseHandler(HandlerEnum.CONTENT_MODE, e);
}, },
...@@ -337,9 +339,9 @@ export default defineComponent({ ...@@ -337,9 +339,9 @@ export default defineComponent({
options: contentModeOptions, options: contentModeOptions,
}), }),
<div class={`setting-drawer__cell-item`}> <div class={`setting-drawer__cell-item`}>
<span>自动锁屏</span> <span>{t('autoScreenLock')}</span>
<InputNumber <InputNumber
style="width:120px" style="width:126px"
size="small" size="small"
min={0} min={0}
onChange={(e: any) => { onChange={(e: any) => {
...@@ -348,16 +350,16 @@ export default defineComponent({ ...@@ -348,16 +350,16 @@ export default defineComponent({
defaultValue={appStore.getProjectConfig.lockTime} defaultValue={appStore.getProjectConfig.lockTime}
formatter={(value: string) => { formatter={(value: string) => {
if (parseInt(value) === 0) { if (parseInt(value) === 0) {
return '0(不自动锁屏)'; return `0(${t('notAutoScreenLock')})`;
} }
return `${value}分钟`; return `${value}${t('minute')}`;
}} }}
/> />
</div>, </div>,
<div class={`setting-drawer__cell-item`}> <div class={`setting-drawer__cell-item`}>
<span>菜单展开宽度</span> <span>{t('expandedMenuWidth')}</span>
<InputNumber <InputNumber
style="width:120px" style="width:126px"
size="small" size="small"
max={600} max={600}
min={100} min={100}
...@@ -375,27 +377,27 @@ export default defineComponent({ ...@@ -375,27 +377,27 @@ export default defineComponent({
function renderContent() { function renderContent() {
return [ return [
renderSwitchItem('面包屑', { renderSwitchItem(t('breadcrumb'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.SHOW_BREADCRUMB, e); baseHandler(HandlerEnum.SHOW_BREADCRUMB, e);
}, },
def: unref(getShowBreadCrumb), def: unref(getShowBreadCrumb),
disabled: !unref(getShowHeader), disabled: !unref(getShowHeader),
}), }),
renderSwitchItem('面包屑图标', { renderSwitchItem(t('breadcrumbIcon'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.SHOW_BREADCRUMB_ICON, e); baseHandler(HandlerEnum.SHOW_BREADCRUMB_ICON, e);
}, },
def: unref(getShowBreadCrumbIcon), def: unref(getShowBreadCrumbIcon),
disabled: !unref(getShowHeader), disabled: !unref(getShowHeader),
}), }),
renderSwitchItem('标签页', { renderSwitchItem(t('tabs'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.TABS_SHOW, e); baseHandler(HandlerEnum.TABS_SHOW, e);
}, },
def: unref(getShowMultipleTab), def: unref(getShowMultipleTab),
}), }),
renderSwitchItem('标签页快捷按钮', { renderSwitchItem(t('tabsQuickBtn'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.TABS_SHOW_QUICK, e); baseHandler(HandlerEnum.TABS_SHOW_QUICK, e);
}, },
...@@ -403,14 +405,14 @@ export default defineComponent({ ...@@ -403,14 +405,14 @@ export default defineComponent({
disabled: !unref(getShowMultipleTab), disabled: !unref(getShowMultipleTab),
}), }),
renderSwitchItem('左侧菜单', { renderSwitchItem(t('sidebar'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.MENU_SHOW_SIDEBAR, e); baseHandler(HandlerEnum.MENU_SHOW_SIDEBAR, e);
}, },
def: unref(getShowMenu), def: unref(getShowMenu),
disabled: unref(getIsHorizontal), disabled: unref(getIsHorizontal),
}), }),
renderSwitchItem('顶栏', { renderSwitchItem(t('header'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.HEADER_SHOW, e); baseHandler(HandlerEnum.HEADER_SHOW, e);
}, },
...@@ -422,25 +424,25 @@ export default defineComponent({ ...@@ -422,25 +424,25 @@ export default defineComponent({
}, },
def: unref(getShowLogo), def: unref(getShowLogo),
}), }),
renderSwitchItem('页脚', { renderSwitchItem(t('footer'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.SHOW_FOOTER, e); baseHandler(HandlerEnum.SHOW_FOOTER, e);
}, },
def: unref(getShowFooter), def: unref(getShowFooter),
}), }),
renderSwitchItem('全屏内容', { renderSwitchItem(t('fullContent'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.FULL_CONTENT, e); baseHandler(HandlerEnum.FULL_CONTENT, e);
}, },
def: unref(getFullContent), def: unref(getFullContent),
}), }),
renderSwitchItem('灰色模式', { renderSwitchItem(t('grayMode'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.GRAY_MODE, e); baseHandler(HandlerEnum.GRAY_MODE, e);
}, },
def: unref(getGrayMode), def: unref(getGrayMode),
}), }),
renderSwitchItem('色弱模式', { renderSwitchItem(t('colorWeak'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.COLOR_WEAK, e); baseHandler(HandlerEnum.COLOR_WEAK, e);
}, },
...@@ -452,13 +454,13 @@ export default defineComponent({ ...@@ -452,13 +454,13 @@ export default defineComponent({
function renderTransition() { function renderTransition() {
return ( return (
<> <>
{renderSwitchItem('顶部进度条', { {renderSwitchItem(t('progress'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.OPEN_PROGRESS, e); baseHandler(HandlerEnum.OPEN_PROGRESS, e);
}, },
def: unref(getOpenNProgress), def: unref(getOpenNProgress),
})} })}
{renderSwitchItem('切换loading', { {renderSwitchItem(t('switchLoading'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.OPEN_PAGE_LOADING, e); baseHandler(HandlerEnum.OPEN_PAGE_LOADING, e);
}, },
...@@ -466,14 +468,14 @@ export default defineComponent({ ...@@ -466,14 +468,14 @@ export default defineComponent({
disabled: !unref(getEnableTransition), disabled: !unref(getEnableTransition),
})} })}
{renderSwitchItem('切换动画', { {renderSwitchItem(t('switchAnimation'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.OPEN_ROUTE_TRANSITION, e); baseHandler(HandlerEnum.OPEN_ROUTE_TRANSITION, e);
}, },
def: unref(getEnableTransition), def: unref(getEnableTransition),
})} })}
{renderSelectItem('动画类型', { {renderSelectItem(t('animationType'), {
handler: (e) => { handler: (e) => {
baseHandler(HandlerEnum.ROUTER_TRANSITION, e); baseHandler(HandlerEnum.ROUTER_TRANSITION, e);
}, },
...@@ -495,7 +497,7 @@ export default defineComponent({ ...@@ -495,7 +497,7 @@ export default defineComponent({
{...opt} {...opt}
disabled={disabled} disabled={disabled}
size="small" size="small"
style={{ width: '120px' }} style={{ width: '126px' }}
onChange={(e) => { onChange={(e) => {
handler && handler(e); handler && handler(e);
}} }}
...@@ -517,26 +519,26 @@ export default defineComponent({ ...@@ -517,26 +519,26 @@ export default defineComponent({
onChange={(e: any) => { onChange={(e: any) => {
handler && handler(e); handler && handler(e);
}} }}
checkedChildren="开" checkedChildren={t('on')}
unCheckedChildren="关" unCheckedChildren={t('off')}
/> />
</div> </div>
); );
} }
return () => ( return () => (
<BasicDrawer {...attrs} title="项目配置" width={300} wrapClassName="setting-drawer"> <BasicDrawer {...attrs} title={t('drawerTitle')} width={330} wrapClassName="setting-drawer">
{{ {{
default: () => ( default: () => (
<> <>
<Divider>{() => '导航栏模式'}</Divider> <Divider>{() => t('navMode')}</Divider>
{renderSidebar()} {renderSidebar()}
{renderTheme()} {renderTheme()}
<Divider>{() => '界面功能'}</Divider> <Divider>{() => t('interfaceFunction')}</Divider>
{renderFeatures()} {renderFeatures()}
<Divider>{() => '界面显示'}</Divider> <Divider>{() => t('interfaceDisplay')}</Divider>
{renderContent()} {renderContent()}
<Divider>{() => '切换动画'}</Divider> <Divider>{() => t('animation')}</Divider>
{renderTransition()} {renderTransition()}
<Divider /> <Divider />
<FooterButton /> <FooterButton />
......
import { ContentEnum, RouterTransitionEnum, ThemeEnum } from '/@/enums/appEnum'; import { ContentEnum, RouterTransitionEnum } from '/@/enums/appEnum';
import { MenuModeEnum, MenuTypeEnum, TopMenuAlignEnum, TriggerEnum } from '/@/enums/menuEnum'; import { MenuModeEnum, MenuTypeEnum, TopMenuAlignEnum, TriggerEnum } from '/@/enums/menuEnum';
import mixImg from '/@/assets/images/layout/menu-mix.svg'; import mixImg from '/@/assets/images/layout/menu-mix.svg';
import sidebarImg from '/@/assets/images/layout/menu-sidebar.svg'; import sidebarImg from '/@/assets/images/layout/menu-sidebar.svg';
import menuTopImg from '/@/assets/images/layout/menu-top.svg'; import menuTopImg from '/@/assets/images/layout/menu-top.svg';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n('layout.setting');
export enum HandlerEnum { export enum HandlerEnum {
CHANGE_LAYOUT, CHANGE_LAYOUT,
...@@ -45,55 +48,44 @@ export enum HandlerEnum { ...@@ -45,55 +48,44 @@ export enum HandlerEnum {
OPEN_ROUTE_TRANSITION, OPEN_ROUTE_TRANSITION,
} }
export const themeOptions = [
{
value: ThemeEnum.LIGHT,
label: '亮色',
},
{
value: ThemeEnum.DARK,
label: '暗色',
},
];
export const contentModeOptions = [ export const contentModeOptions = [
{ {
value: ContentEnum.FULL, value: ContentEnum.FULL,
label: '流式', label: t('contentModeFull'),
}, },
{ {
value: ContentEnum.FIXED, value: ContentEnum.FIXED,
label: '定宽', label: t('contentModeFixed'),
}, },
]; ];
export const topMenuAlignOptions = [ export const topMenuAlignOptions = [
{ {
value: TopMenuAlignEnum.CENTER, value: TopMenuAlignEnum.CENTER,
label: '居中', label: t('topMenuAlignRight'),
}, },
{ {
value: TopMenuAlignEnum.START, value: TopMenuAlignEnum.START,
label: '居左', label: t('topMenuAlignLeft'),
}, },
{ {
value: TopMenuAlignEnum.END, value: TopMenuAlignEnum.END,
label: '居右', label: t('topMenuAlignCenter'),
}, },
]; ];
export const menuTriggerOptions = [ export const menuTriggerOptions = [
{ {
value: TriggerEnum.NONE, value: TriggerEnum.NONE,
label: '不显示', label: t('menuTriggerNone'),
}, },
{ {
value: TriggerEnum.FOOTER, value: TriggerEnum.FOOTER,
label: '底部', label: t('menuTriggerBottom'),
}, },
{ {
value: TriggerEnum.HEADER, value: TriggerEnum.HEADER,
label: '顶部', label: t('menuTriggerTop'),
}, },
]; ];
...@@ -112,20 +104,20 @@ export const routerTransitionOptions = [ ...@@ -112,20 +104,20 @@ export const routerTransitionOptions = [
export const menuTypeList = [ export const menuTypeList = [
{ {
title: '左侧菜单模式', title: t('menuTypeSidebar'),
mode: MenuModeEnum.INLINE, mode: MenuModeEnum.INLINE,
type: MenuTypeEnum.SIDEBAR, type: MenuTypeEnum.SIDEBAR,
src: sidebarImg, src: sidebarImg,
}, },
{ {
title: '混合模式', title: t('menuTypeMix'),
mode: MenuModeEnum.INLINE, mode: MenuModeEnum.INLINE,
type: MenuTypeEnum.MIX, type: MenuTypeEnum.MIX,
src: mixImg, src: mixImg,
}, },
{ {
title: '顶部菜单模式', title: t('menuTypeTopMenu'),
mode: MenuModeEnum.HORIZONTAL, mode: MenuModeEnum.HORIZONTAL,
type: MenuTypeEnum.TOP_MENU, type: MenuTypeEnum.TOP_MENU,
src: menuTopImg, src: menuTopImg,
......
import './index.less'; import './index.less';
import { computed, defineComponent, ref, unref, watch, nextTick } from 'vue'; import { computed, defineComponent, ref, unref, watch, nextTick, CSSProperties } from 'vue';
import { Layout } from 'ant-design-vue'; import { Layout } from 'ant-design-vue';
import LayoutMenu from '../menu'; import LayoutMenu from '../menu';
...@@ -91,17 +91,19 @@ export default defineComponent({ ...@@ -91,17 +91,19 @@ export default defineComponent({
} }
); );
const getHiddenDomStyle = computed(() => { const getHiddenDomStyle = computed(
const width = `${unref(getRealWidth)}px`; (): CSSProperties => {
return { const width = `${unref(getRealWidth)}px`;
width: width, return {
overflow: 'hidden', width: width,
flex: `0 0 ${width}`, overflow: 'hidden',
'max-width': width, flex: `0 0 ${width}`,
'min-width': width, maxWidth: width,
transition: 'all 0.2s', minWidth: width,
}; transition: 'all 0.2s',
}); };
}
);
function renderDefault() { function renderDefault() {
return ( return (
......
export default {
onlinePreview: 'Preview',
onlineDocument: 'Document',
};
export default {
// user dropdown
dropdownItemDoc: 'Document',
dropdownItemLoginOut: 'Login Out',
tooltipErrorLog: 'Error log',
tooltipLock: 'Lock screen',
tooltipNotify: 'Notification',
tooltipRedo: 'Refresh',
tooltipEntryFull: 'Full Screen',
tooltipExitFull: 'Exit Full Screen',
// lock
lockScreenPassword: 'Lock screen password',
lockScreen: 'Lock screen',
lockScreenBtn: 'Locking',
notLockScreenPassword: 'No password lock screen',
};
export default {
redo: 'Refresh',
close: 'Close',
closeLeft: 'Close Left',
closeRight: 'Close Right',
closeOther: 'Close Other',
closeAll: 'Close All',
putAway: 'PutAway',
unfold: 'Unfold',
};
export default {
// content mode
contentModeFull: 'Full',
contentModeFixed: 'Fixed width',
// topMenu align
topMenuAlignLeft: 'Left',
topMenuAlignRight: 'Center',
topMenuAlignCenter: 'Right',
// menu trigger
menuTriggerNone: 'Not Show',
menuTriggerBottom: 'Bottom',
menuTriggerTop: 'Top',
// menu type
menuTypeSidebar: 'Left menu mode',
menuTypeMix: 'Mixed mode',
menuTypeTopMenu: 'Top menu mode',
on: 'On',
off: 'Off',
minute: 'Minute',
operatingTitle: 'Successful!',
operatingContent:
'The copy is successful, please go to src/settings/projectSetting.ts to modify the configuration!',
resetSuccess: 'Successfully reset!',
copyBtn: 'Copy',
resetBtn: 'Reset',
clearBtn: 'Clear cache and to the login page',
drawerTitle: 'Configuration',
navMode: 'Navigation mode',
interfaceFunction: 'Interface function',
interfaceDisplay: 'Interface display',
animation: 'Animation',
splitMenu: 'Split menu',
headerTheme: 'Header theme',
sidebarTheme: 'Menu theme',
menuDrag: 'Drag Sidebar',
menuSearch: 'Sidebar search',
menuAccordion: 'Sidebar accordion',
menuCollapse: 'Collapse menu',
collapseMenuDisplayName: 'Collapse menu display name',
topMenuLayout: 'Top menu layout',
menuCollapseButton: 'Menu collapse button',
contentMode: 'Content area width',
expandedMenuWidth: 'Expanded menu width',
breadcrumb: 'Breadcrumbs',
breadcrumbIcon: 'Breadcrumbs Icon',
tabs: 'Tabs',
tabsQuickBtn: 'Tabs quick button',
sidebar: 'Sidebar',
header: 'Header',
footer: 'Footer',
fullContent: 'Full content',
grayMode: 'Gray mode',
colorWeak: 'Color Weak Mode',
progress: 'Progress',
switchLoading: 'Switch Loading',
switchAnimation: 'Switch animation',
animationType: 'Animation type',
autoScreenLock: 'Auto screen lock',
notAutoScreenLock: 'Not auto lock',
fixedHeader: 'Fixed header',
fixedSideBar: 'Fixed Sidebar',
};
export default {
onlinePreview: '在线预览',
onlineDocument: '在线文档',
};
export default {
// user dropdown
dropdownItemDoc: '文档',
dropdownItemLoginOut: '退出系统',
// tooltip
tooltipErrorLog: '错误日志',
tooltipLock: '锁定屏幕',
tooltipNotify: '消息通知',
tooltipRedo: '刷新',
tooltipEntryFull: '全屏',
tooltipExitFull: '退出全屏',
// lock
lockScreenPassword: '锁屏密码',
lockScreen: '锁定屏幕',
lockScreenBtn: '锁定',
notLockScreenPassword: '不设置密码锁屏',
};
export default {
redo: '刷新',
close: '关闭',
closeLeft: '关闭左侧',
closeRight: '关闭右侧',
closeOther: '关闭其他',
closeAll: '关闭全部',
putAway: '收起',
unfold: '展开',
};
export default {
// content mode
contentModeFull: '流式',
contentModeFixed: '定宽',
// topMenu align
topMenuAlignLeft: '居左',
topMenuAlignRight: '居中',
topMenuAlignCenter: '居右',
// menu trigger
menuTriggerNone: '不显示',
menuTriggerBottom: '底部',
menuTriggerTop: '顶部',
// menu type
menuTypeSidebar: '左侧菜单模式',
menuTypeMix: '混合模式',
menuTypeTopMenu: '顶部菜单模式',
on: '',
off: '',
minute: '分钟',
operatingTitle: '操作成功',
operatingContent: '复制成功,请到 src/settings/projectSetting.ts 中修改配置!',
resetSuccess: '重置成功!',
copyBtn: '拷贝',
resetBtn: '重置',
clearBtn: '清空缓存并返回登录页',
drawerTitle: '项目配置',
navMode: '导航栏模式',
interfaceFunction: '界面功能',
interfaceDisplay: '界面显示',
animation: '动画',
splitMenu: '分割菜单',
headerTheme: '顶栏主题',
sidebarTheme: '菜单主题',
menuDrag: '侧边菜单拖拽',
menuSearch: '侧边菜单搜索',
menuAccordion: '侧边菜单手风琴模式',
menuCollapse: '折叠菜单',
collapseMenuDisplayName: '折叠菜单显示名称',
topMenuLayout: '顶部菜单布局',
menuCollapseButton: '菜单折叠按钮',
contentMode: '内容区域宽度',
expandedMenuWidth: '菜单展开宽度',
breadcrumb: '面包屑',
breadcrumbIcon: '面包屑图标',
tabs: '标签页',
tabsQuickBtn: '标签页快捷按钮',
sidebar: '左侧菜单',
header: '顶栏',
footer: '页脚',
fullContent: '全屏内容',
grayMode: '灰色模式',
colorWeak: '色弱模式',
progress: '顶部进度条',
switchLoading: '切换loading',
switchAnimation: '切换动画',
animationType: '动画类型',
autoScreenLock: '自动锁屏',
notAutoScreenLock: '不自动锁屏',
fixedHeader: '固定header',
fixedSideBar: '固定Sidebar',
};
...@@ -41,6 +41,7 @@ const setting: ProjectConfig = { ...@@ -41,6 +41,7 @@ const setting: ProjectConfig = {
// locale setting // locale setting
locale: { locale: {
show: true,
// Locale // Locale
lang: 'zh_CN', lang: 'zh_CN',
// Default locale // Default locale
......
...@@ -51,6 +51,7 @@ export interface HeaderSetting { ...@@ -51,6 +51,7 @@ export interface HeaderSetting {
} }
export interface LocaleSetting { export interface LocaleSetting {
show: boolean;
// Current language // Current language
lang: LocaleType; lang: LocaleType;
// default language // default language
......
<template> <template>
<BasicModal :width="800" :title="t('sys.errorLog.tableActionDesc')" v-bind="$attrs"> <BasicModal :width="800" :title="t('tableActionDesc')" v-bind="$attrs">
<Description :data="info" @register="register" /> <Description :data="info" @register="register" />
</BasicModal> </BasicModal>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, PropType } from 'vue'; import { defineComponent, PropType } from 'vue';
import { useI18n } from 'vue-i18n';
import { BasicModal } from '/@/components/Modal/index'; import { BasicModal } from '/@/components/Modal/index';
import { ErrorInfo } from '/@/store/modules/error'; import { ErrorInfo } from '/@/store/modules/error';
import { Description, useDescription } from '/@/components/Description/index'; import { Description, useDescription } from '/@/components/Description/index';
import { useI18n } from '/@/hooks/web/useI18n';
import { getDescSchema } from './data'; import { getDescSchema } from './data';
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
}, },
}, },
setup() { setup() {
const { t } = useI18n(); const { t } = useI18n('sys.errorLog');
const [register] = useDescription({ const [register] = useDescription({
column: 2, column: 2,
schema: getDescSchema(), schema: getDescSchema(),
......
import { Tag } from 'ant-design-vue'; import { Tag } from 'ant-design-vue';
import { BasicColumn } from '/@/components/Table/index'; import { BasicColumn } from '/@/components/Table/index';
import { ErrorTypeEnum } from '/@/enums/exceptionEnum'; import { ErrorTypeEnum } from '/@/enums/exceptionEnum';
import { useI18n } from '/@/hooks/web/useI18n';
import { useExternalI18n } from '/@/hooks/web/useLocale'; const { t } = useI18n('sys.errorLog');
const { t } = useExternalI18n();
export function getColumns(): BasicColumn[] { export function getColumns(): BasicColumn[] {
return [ return [
{ {
dataIndex: 'type', dataIndex: 'type',
title: t('sys.errorLog.tableColumnType'), title: t('tableColumnType'),
width: 80, width: 80,
customRender: ({ text }) => { customRender: ({ text }) => {
const color = const color =
...@@ -33,12 +32,12 @@ export function getColumns(): BasicColumn[] { ...@@ -33,12 +32,12 @@ export function getColumns(): BasicColumn[] {
}, },
{ {
dataIndex: 'time', dataIndex: 'time',
title: t('sys.errorLog.tableColumnDate'), title: t('tableColumnDate'),
width: 160, width: 160,
}, },
{ {
dataIndex: 'file', dataIndex: 'file',
title: t('sys.errorLog.tableColumnFile'), title: t('tableColumnFile'),
width: 200, width: 200,
}, },
{ {
...@@ -48,12 +47,12 @@ export function getColumns(): BasicColumn[] { ...@@ -48,12 +47,12 @@ export function getColumns(): BasicColumn[] {
}, },
{ {
dataIndex: 'message', dataIndex: 'message',
title: t('sys.errorLog.tableColumnMsg'), title: t('tableColumnMsg'),
width: 300, width: 300,
}, },
{ {
dataIndex: 'stack', dataIndex: 'stack',
title: t('sys.errorLog.tableColumnStackMsg'), title: t('tableColumnStackMsg'),
width: 300, width: 300,
}, },
]; ];
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
import { useModal } from '/@/components/Modal/index'; import { useModal } from '/@/components/Modal/index';
import { useMessage } from '/@/hooks/web/useMessage'; import { useMessage } from '/@/hooks/web/useMessage';
import { useI18n } from 'vue-i18n'; import { useI18n } from '/@/hooks/web/useI18n';
import { errorStore, ErrorInfo } from '/@/store/modules/error'; import { errorStore, ErrorInfo } from '/@/store/modules/error';
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
const rowInfoRef = ref<ErrorInfo>(); const rowInfoRef = ref<ErrorInfo>();
const imgListRef = ref<string[]>([]); const imgListRef = ref<string[]>([]);
const { t } = useI18n(); const { t } = useI18n('sys.errorLog');
const [register, { setTableData }] = useTable({ const [register, { setTableData }] = useTable({
title: t('sys.errorLog.tableTitle'), title: t('sys.errorLog.tableTitle'),
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
); );
const { createMessage } = useMessage(); const { createMessage } = useMessage();
if (isDevMode()) { if (isDevMode()) {
createMessage.info(t('sys.errorLog.enableMessage')); createMessage.info(t('enableMessage'));
} }
// 查看详情 // 查看详情
function handleDetail(row: ErrorInfo) { function handleDetail(row: ErrorInfo) {
......
import './exception.less';
import type { PropType } from 'vue'; import type { PropType } from 'vue';
import { Result, Button } from 'ant-design-vue'; 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';
import { useGo, useRedo } from '/@/hooks/web/usePage'; import { useGo, useRedo } from '/@/hooks/web/usePage';
import { PageEnum } from '/@/enums/pageEnum'; import { PageEnum } from '/@/enums/pageEnum';
import { useI18n } from 'vue-i18n'; import { useI18n } from '/@/hooks/web/useI18n';
import './exception.less';
interface MapValue { interface MapValue {
title: string; title: string;
subTitle: string; subTitle: string;
...@@ -52,7 +53,7 @@ export default defineComponent({ ...@@ -52,7 +53,7 @@ export default defineComponent({
const { query } = useRoute(); const { query } = useRoute();
const go = useGo(); const go = useGo();
const redo = useRedo(); const redo = useRedo();
const { t } = useI18n(); const { t } = useI18n('sys.exception');
const getStatus = computed(() => { const getStatus = computed(() => {
const { status: routeStatus } = query; const { status: routeStatus } = query;
...@@ -66,13 +67,13 @@ export default defineComponent({ ...@@ -66,13 +67,13 @@ export default defineComponent({
} }
); );
const backLoginI18n = t('sys.exception.backLogin'); const backLoginI18n = t('backLogin');
const backHomeI18n = t('sys.exception.backHome'); const backHomeI18n = t('backHome');
unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_ACCESS, { unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_ACCESS, {
title: '403', title: '403',
status: `${ExceptionEnum.PAGE_NOT_ACCESS}`, status: `${ExceptionEnum.PAGE_NOT_ACCESS}`,
subTitle: t('sys.exception.subTitle403'), subTitle: t('subTitle403'),
btnText: props.full ? backLoginI18n : backHomeI18n, btnText: props.full ? backLoginI18n : backHomeI18n,
handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()), handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()),
}); });
...@@ -80,7 +81,7 @@ export default defineComponent({ ...@@ -80,7 +81,7 @@ export default defineComponent({
unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_FOUND, { unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_FOUND, {
title: '404', title: '404',
status: `${ExceptionEnum.PAGE_NOT_FOUND}`, status: `${ExceptionEnum.PAGE_NOT_FOUND}`,
subTitle: t('sys.exception.subTitle404'), subTitle: t('subTitle404'),
btnText: props.full ? backLoginI18n : backHomeI18n, btnText: props.full ? backLoginI18n : backHomeI18n,
handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()), handler: () => (props.full ? go(PageEnum.BASE_LOGIN) : go()),
}); });
...@@ -88,22 +89,22 @@ export default defineComponent({ ...@@ -88,22 +89,22 @@ export default defineComponent({
unref(statusMapRef).set(ExceptionEnum.ERROR, { unref(statusMapRef).set(ExceptionEnum.ERROR, {
title: '500', title: '500',
status: `${ExceptionEnum.ERROR}`, status: `${ExceptionEnum.ERROR}`,
subTitle: t('sys.exception.subTitle500'), subTitle: t('subTitle500'),
btnText: backHomeI18n, btnText: backHomeI18n,
handler: () => go(), handler: () => go(),
}); });
unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_DATA, { unref(statusMapRef).set(ExceptionEnum.PAGE_NOT_DATA, {
title: t('sys.exception.noDataTitle'), title: t('noDataTitle'),
subTitle: '', subTitle: '',
btnText: t('sys.exception.redo'), btnText: t('redo'),
handler: () => redo(), handler: () => redo(),
icon: notDataImg, icon: notDataImg,
}); });
unref(statusMapRef).set(ExceptionEnum.NET_WORK_ERROR, { unref(statusMapRef).set(ExceptionEnum.NET_WORK_ERROR, {
title: t('sys.exception.networkErrorTitle'), title: t('networkErrorTitle'),
subTitle: t('sys.exception.networkErrorSubTitle'), subTitle: t('networkErrorSubTitle'),
btnText: 'Refresh', btnText: 'Refresh',
handler: () => redo(), handler: () => redo(),
icon: netWorkImg, icon: netWorkImg,
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<p class="lock-page__header-name">{{ realName }}</p> <p class="lock-page__header-name">{{ realName }}</p>
</div> </div>
<BasicForm @register="register" v-if="!getIsNotPwd" /> <BasicForm @register="register" v-if="!getIsNotPwd" />
<Alert v-if="errMsgRef" type="error" :message="t('sys.lock.alert')" banner /> <Alert v-if="errMsgRef" type="error" :message="t('alert')" banner />
<div class="lock-page__footer"> <div class="lock-page__footer">
<a-button type="default" class="mt-2 mr-2" @click="goLogin" v-if="!getIsNotPwd"> <a-button type="default" class="mt-2 mr-2" @click="goLogin" v-if="!getIsNotPwd">
{{ t('sys.lock.backToLogin') }} {{ t('sys.lock.backToLogin') }}
...@@ -26,8 +26,7 @@ ...@@ -26,8 +26,7 @@
import { userStore } from '/@/store/modules/user'; import { userStore } from '/@/store/modules/user';
import { appStore } from '/@/store/modules/app'; import { appStore } from '/@/store/modules/app';
import { useI18n } from '/@/hooks/web/useI18n';
import { useI18n } from 'vue-i18n';
export default defineComponent({ export default defineComponent({
name: 'LockPage', name: 'LockPage',
...@@ -37,7 +36,7 @@ ...@@ -37,7 +36,7 @@
const loadingRef = ref(false); const loadingRef = ref(false);
const errMsgRef = ref(false); const errMsgRef = ref(false);
const { t } = useI18n(); const { t } = useI18n('sys.lock');
const [register, { validateFields }] = useForm({ const [register, { validateFields }] = useForm({
showActionButtonGroup: false, showActionButtonGroup: false,
schemas: [ schemas: [
...@@ -47,7 +46,7 @@ ...@@ -47,7 +46,7 @@
component: 'InputPassword', component: 'InputPassword',
componentProps: { componentProps: {
style: { width: '100%' }, style: { width: '100%' },
placeholder: t('sys.lock.placeholder'), placeholder: t('placeholder'),
}, },
rules: [{ required: true }], rules: [{ required: true }],
}, },
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<div class="login-form-wrap"> <div class="login-form-wrap">
<div class="login-form mx-6"> <div class="login-form mx-6">
<div class="login-form__content px-2 py-10"> <div class="login-form__content px-2 py-10">
<AppLocalPicker class="login-form__locale" /> <AppLocalePicker v-if="showLocale" class="login-form__locale" />
<header> <header>
<img :src="logo" class="mr-4" /> <img :src="logo" class="mr-4" />
<h1>{{ title }}</h1> <h1>{{ title }}</h1>
...@@ -64,23 +64,23 @@ ...@@ -64,23 +64,23 @@
import { Checkbox } from 'ant-design-vue'; import { Checkbox } from 'ant-design-vue';
import Button from '/@/components/Button/index.vue'; import Button from '/@/components/Button/index.vue';
import { AppLocalPicker } from '/@/components/Application'; import { AppLocalePicker } from '/@/components/Application';
// import { BasicDragVerify, DragVerifyActionType } from '/@/components/Verify/index'; // import { BasicDragVerify, DragVerifyActionType } from '/@/components/Verify/index';
import { userStore } from '/@/store/modules/user'; import { userStore } from '/@/store/modules/user';
import { useI18n } from 'vue-i18n';
// import { appStore } from '/@/store/modules/app'; // import { appStore } from '/@/store/modules/app';
import { useMessage } from '/@/hooks/web/useMessage'; import { useMessage } from '/@/hooks/web/useMessage';
import { useGlobSetting } from '/@/hooks/setting'; import { useGlobSetting, useProjectSetting } from '/@/hooks/setting';
import logo from '/@/assets/images/logo.png'; import logo from '/@/assets/images/logo.png';
import { useI18n } from '/@/hooks/web/useI18n';
export default defineComponent({ export default defineComponent({
components: { components: {
// BasicDragVerify, // BasicDragVerify,
AButton: Button, AButton: Button,
ACheckbox: Checkbox, ACheckbox: Checkbox,
AppLocalPicker, AppLocalePicker,
}, },
setup() { setup() {
const formRef = ref<any>(null); const formRef = ref<any>(null);
...@@ -88,8 +88,9 @@ ...@@ -88,8 +88,9 @@
// const verifyRef = ref<RefInstanceType<DragVerifyActionType>>(null); // const verifyRef = ref<RefInstanceType<DragVerifyActionType>>(null);
const globSetting = useGlobSetting(); const globSetting = useGlobSetting();
const { locale } = useProjectSetting();
const { notification } = useMessage(); const { notification } = useMessage();
const { t } = useI18n(); const { t } = useI18n('sys.login');
// const openLoginVerifyRef = computed(() => appStore.getProjectConfig.openLoginVerify); // const openLoginVerifyRef = computed(() => appStore.getProjectConfig.openLoginVerify);
...@@ -103,10 +104,8 @@ ...@@ -103,10 +104,8 @@
}); });
const formRules = reactive({ const formRules = reactive({
account: [{ required: true, message: t('sys.login.accountPlaceholder'), trigger: 'blur' }], account: [{ required: true, message: t('accountPlaceholder'), trigger: 'blur' }],
password: [ password: [{ required: true, message: t('passwordPlaceholder'), trigger: 'blur' }],
{ required: true, message: t('sys.login.passwordPlaceholder'), trigger: 'blur' },
],
// verify: unref(openLoginVerifyRef) ? [{ required: true, message: '请通过验证码校验' }] : [], // verify: unref(openLoginVerifyRef) ? [{ required: true, message: '请通过验证码校验' }] : [],
}); });
...@@ -131,8 +130,8 @@ ...@@ -131,8 +130,8 @@
); );
if (userInfo) { if (userInfo) {
notification.success({ notification.success({
message: t('sys.login.loginSuccessTitle'), message: t('loginSuccessTitle'),
description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realName}`, description: `${t('loginSuccessDesc')}: ${userInfo.realName}`,
duration: 3, duration: 3,
}); });
} }
...@@ -154,6 +153,7 @@ ...@@ -154,6 +153,7 @@
title: globSetting && globSetting.title, title: globSetting && globSetting.title,
logo, logo,
t, t,
showLocale: locale.show,
}; };
}, },
}); });
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册