diff --git a/src/layouts/Tabs/ContextMenu/index.less b/src/layouts/Tabs/ContextMenu/index.less
index 629082f..3bfa63d 100644
--- a/src/layouts/Tabs/ContextMenu/index.less
+++ b/src/layouts/Tabs/ContextMenu/index.less
@@ -1,8 +1,8 @@
.console-layout__context-menu {
.anticon {
- margin-right: 2px;
+ margin-inline-end: 2px;
}
svg {
- margin-right: 10px;
+ margin-inline-end: 10px;
}
-}
\ No newline at end of file
+}
diff --git a/src/layouts/Tabs/ContextMenu/index.tsx b/src/layouts/Tabs/ContextMenu/index.tsx
index 0549587..d9b0caf 100644
--- a/src/layouts/Tabs/ContextMenu/index.tsx
+++ b/src/layouts/Tabs/ContextMenu/index.tsx
@@ -1,7 +1,7 @@
import { Menu, Item, Separator, ItemParams } from 'react-contexify';
import { baseModel } from '@/models/base';
import { tabsModel } from '@/models/tabs';
-import { history } from '@/router';
+import router from '@/router';
import { useCloseTab } from '../useTab';
import { requestFullscreen } from '@/layouts/FullScreen/utils';
import { ClassName__ConsoleLayout_RightSideMain } from '@/layouts/ConsoleLayout/consts';
@@ -32,19 +32,19 @@ const ContextMenu: React.FC = () => {
function onClickCloseOther({ props }: ItemParams) {
tabsModel.removeOther(props.pathname);
- history.push(props.pathname);
+ router.push(props.pathname);
}
function onClickCloseRight({ props }: ItemParams) {
tabsModel.removeRight(props.pathname);
- history.push(props.pathname);
+ router.push(props.pathname);
}
function onClickCloseLeft({ props }: ItemParams) {
const removed = tabsModel.removeLeft(props.pathname);
// 如果右击的是当前tab的右侧,则跳转到被右击的tab
if (removed.some(({ key }) => key === location.pathname)) {
- history.push(props.pathname);
+ router.push(props.pathname);
}
}
diff --git a/src/layouts/Tabs/TabChrome/index.less b/src/layouts/Tabs/TabChrome/index.less
index 809bf7f..ab014b3 100644
--- a/src/layouts/Tabs/TabChrome/index.less
+++ b/src/layouts/Tabs/TabChrome/index.less
@@ -23,33 +23,45 @@
&.isActive {
position: relative;
background-color: var(--tab-bg-active-color);
- box-shadow: 0px 8px 0px 0px var(--tab-bg-active-color), 0 8px 0 0 var(--tab-bg-active-color);
+ box-shadow: 0px 8px 0px 0px var(--tab-bg-active-color),
+ 0 8px 0 0 var(--tab-bg-active-color);
border-radius: 10px 10px 0 0;
- margin-bottom: 7px;
+ margin-block-end: 7px;
- &:before, &:after {
+ &:before,
+ &:after {
position: absolute;
- bottom: -7px;
- content: '';
- width: 20px;
- height: 20px;
+ inset-block-end: -7px;
+ content: "";
+ inline-size: 20px;
+ block-size: 20px;
border-radius: 100%;
box-shadow: 0 0 0 40px var(--tab-bg-active-color);
}
&:before {
- left: -20px;
+ inset-inline-start: -20px;
clip-path: inset(50% 0 0 50%);
}
&:after {
- right: -20px;
+ inset-inline-end: -20px;
clip-path: inset(50% 50% 0 0);
}
}
}
+.ant-app-rtl .console-layout-tab.isActive {
+ &:before {
+ clip-path: inset(50% 50% 0 0);
+ }
+
+ &:after {
+ clip-path: inset(50% 0 0 50%);
+ }
+}
+
.console-layout-tab__label {
- margin-left: 6px;
+ margin-inline-start: 6px;
}
.console-layout-tab__icon {
@@ -57,12 +69,16 @@
align-items: center;
}
-.console-layout-tab__icon, .console-layout-tab__label, .console-layout-tab__close {
+.console-layout-tab__icon,
+.console-layout-tab__label,
+.console-layout-tab__close {
color: var(--tab-text-color);
}
.isActive {
- .console-layout-tab__icon, .console-layout-tab__label, .console-layout-tab__close {
+ .console-layout-tab__icon,
+ .console-layout-tab__label,
+ .console-layout-tab__close {
color: var(--console-antd-colorPrimary);
}
}
@@ -71,10 +87,10 @@
display: flex;
align-items: center;
justify-content: center;
- width: 18px;
- height: 18px;
+ inline-size: 18px;
+ block-size: 18px;
// padding: 2px;
- margin-left: 6px;
+ margin-inline-start: 6px;
&:hover {
border-radius: 50%;
cursor: pointer;
diff --git a/src/layouts/Tabs/index.less b/src/layouts/Tabs/index.less
index f256621..9c266b2 100644
--- a/src/layouts/Tabs/index.less
+++ b/src/layouts/Tabs/index.less
@@ -1,35 +1,35 @@
.console-layout-tabs {
display: flex;
align-items: center;
- width: calc(100% - 34px);
- padding-right: 8px;
+ inline-size: calc(100% - 34px);
+ padding-inline-end: 8px;
user-select: none;
- margin-left: 4px;
+ margin-inline-start: 4px;
&.CHROME {
.ant-tabs-top > .ant-tabs-nav {
&:before {
- border-bottom: none;
+ border-block-end: none;
}
}
}
.ant-tabs {
- width: 100%;
+ inline-size: 100%;
}
.ant-tabs-nav-list {
position: relative;
- padding-top: var(--layout-gutter)
+ padding-block-start: var(--layout-gutter);
}
.ant-tabs-nav {
- margin-bottom: 0;
+ margin-block-end: 0;
}
}
.console-layout-tabs__popup {
- .ant-tabs-dropdown-menu-item >span >div {
+ .ant-tabs-dropdown-menu-item > span > div {
display: flex;
align-items: center;
svg {
- margin-right: 4px;
+ margin-inline-end: 4px;
}
}
}
diff --git a/src/layouts/Tabs/index.tsx b/src/layouts/Tabs/index.tsx
index bb4c8ab..7638c7d 100644
--- a/src/layouts/Tabs/index.tsx
+++ b/src/layouts/Tabs/index.tsx
@@ -4,7 +4,6 @@ import useStore from '@/layouts/ConsoleLayout/store';
import { TabItem, tabsModel } from '@/models/tabs';
import { useModel } from '@zhangsai/model';
import { ItemType } from '../SideMenu/utils';
-import { history } from '@/router';
import { DndContext, DragEndEvent, PointerSensor, useSensor } from '@dnd-kit/core';
import { SortableContext, arrayMove, horizontalListSortingStrategy } from '@dnd-kit/sortable';
import TabChrome from './TabChrome';
@@ -58,7 +57,7 @@ const Tabs = () => {
const location = useLocation();
function onChange(activeKey: string) {
- history.push(activeKey);
+ router.push(activeKey);
}
function onEdit(
@@ -69,7 +68,7 @@ const Tabs = () => {
const isSelf = location.pathname === targetKey;
const nextTab = tabsModel.removeTab(targetKey as string, isSelf);
if (isSelf && nextTab) {
- history.push(nextTab.key);
+ router.push(nextTab.key);
}
}
}
diff --git a/src/layouts/Tabs/useTab.ts b/src/layouts/Tabs/useTab.ts
index 26c8d36..609213a 100644
--- a/src/layouts/Tabs/useTab.ts
+++ b/src/layouts/Tabs/useTab.ts
@@ -2,7 +2,6 @@ import useDraggable, { DraggableTabPaneProps } from './useDraggable';
import useStore from '@/layouts/ConsoleLayout/store';
import { useLocation } from 'react-router';
import { useContextMenu } from './ContextMenu/useContextMenu';
-import { history } from '@/router';
import { useModel } from '@zhangsai/model';
import { JSXElementConstructor, MouseEvent, ReactElement, useMemo, useCallback } from 'react';
import { omit } from '@/utils';
@@ -37,7 +36,7 @@ export default function useTab(props: Props) {
});
function onClickTab() {
- history.push(propsMenuKey);
+ router.push(propsMenuKey);
}
const closeTab = useCloseTab(propsMenuKey);
@@ -69,7 +68,7 @@ export function useCloseTab(menuKey?: string) {
if (!finallyMenuKey) return;
const nextTab = tabsModel.removeTab(finallyMenuKey, location.pathname === finallyMenuKey);
if (/** menuItem?.key === finallyMenuKey && */nextTab) {
- history.push(nextTab.key);
+ router.push(nextTab.key);
}
}, [location.pathname, menuKey]);
diff --git a/src/locales/fa/components.json b/src/locales/fa/components.json
new file mode 100644
index 0000000..cde75cf
--- /dev/null
+++ b/src/locales/fa/components.json
@@ -0,0 +1,3 @@
+{
+ "返回": "بازگشت"
+}
diff --git a/src/locales/fa/error.json b/src/locales/fa/error.json
new file mode 100644
index 0000000..c33a84e
--- /dev/null
+++ b/src/locales/fa/error.json
@@ -0,0 +1,5 @@
+{
+ "对不起,您没有访问权限": "Sorry, you don't have access",
+ "回到主页": "Back to home",
+ "对不起,您访问的页面不存在": "Sorry, the page you are visiting does not exist"
+}
\ No newline at end of file
diff --git a/src/locales/fa/http.json b/src/locales/fa/http.json
new file mode 100644
index 0000000..46ed167
--- /dev/null
+++ b/src/locales/fa/http.json
@@ -0,0 +1,3 @@
+{
+ "请检查网络": "شبکه خود را بررسی کنید"
+}
diff --git a/src/locales/fa/index.ts b/src/locales/fa/index.ts
new file mode 100644
index 0000000..a8441e6
--- /dev/null
+++ b/src/locales/fa/index.ts
@@ -0,0 +1,22 @@
+import menu from './menu.json';
+import layout from './layout.json';
+import login from './login.json';
+import grid from '@/pages/grid/locales/en/grid.json';
+import permission from '@/pages/permission/locales/en/permission.json';
+import router from '@/pages/router/locales/en/router.json';
+import tablePage from '@/pages/tablePage/locales/en/tablePage.json';
+import error from './error.json';
+
+const en = {
+ menu,
+ layout,
+ login,
+ grid,
+ permission,
+ router,
+ tablePage,
+ error,
+};
+
+export default en;
+
diff --git a/src/locales/fa/layout.json b/src/locales/fa/layout.json
new file mode 100644
index 0000000..6f2d0de
--- /dev/null
+++ b/src/locales/fa/layout.json
@@ -0,0 +1,11 @@
+{
+ "已登出": "Logout successfully",
+ "个人中心": "Profile",
+ "退出登录": "Logout",
+ "切换语言成功": "Switch to {{language}} successfully",
+ "语言": "Language",
+ "刷新页面": "Refresh",
+ "主题色": "Theme color",
+ "亮色": "Light mode",
+ "暗色": "Dark mode"
+}
diff --git a/src/locales/fa/login.json b/src/locales/fa/login.json
new file mode 100644
index 0000000..e07c934
--- /dev/null
+++ b/src/locales/fa/login.json
@@ -0,0 +1,10 @@
+{
+ "请输入帐号": "Please enter your account",
+ "请输入密码": "Please enter your password",
+ "记住我": "Remember me",
+ "忘记密码": "Forgot password",
+ "登录": "Login",
+ "或": "Or",
+ "注册": "Sign up",
+ "登录成功": "Login successful"
+}
diff --git a/src/locales/fa/menu.json b/src/locales/fa/menu.json
new file mode 100644
index 0000000..2efb59d
--- /dev/null
+++ b/src/locales/fa/menu.json
@@ -0,0 +1,37 @@
+{
+ "登录": "ورود",
+ "首页": "خانه",
+ "栅格布局": "جدول",
+ "个人中心": "پروفایل",
+ "权限": "دسترسی",
+ "路由权限": "دسترسی مسیر",
+ "局部权限": "دسترسی محلی",
+ "路由": "مسیر یابی",
+ "动态路由": "مسیر پویا",
+ "动态meta": "متا مسیر",
+ "搜索表格": "Table",
+ "常见表格": "General table",
+ "常见表格详情": "Table detail",
+ "滚动加载表格": "Scrolling table",
+ "滚动加载列表": "Scrolling list",
+ "额外参数": "Extra params",
+ "格式化搜索参数": "Format params",
+ "简单表格": "Simple table",
+ "弹窗内使用": "Table in Modal",
+ "自定义搜索按钮": "Custom btn",
+ "嵌套路由": "Nest",
+ "菜单1": "Menu1",
+ "菜单2": "Menu2",
+ "菜单2-1": "Menu2-1",
+ "菜单2-2": "Menu2-2",
+ "菜单2-2-1": "Menu2-2-1",
+ "菜单2-2-2": "Menu2-2-2",
+ "错误页": "Error",
+ "外链": "Link",
+ "单栏": "1 side",
+ "单栏示例": "Single layout example",
+ "独立布局": "0 side",
+ "本页面独立于默认布局": "This page is independent of the default layout",
+ "出错了": "Someting wrong",
+ "页面不存在": "Not found"
+}
diff --git a/src/locales/index.ts b/src/locales/index.ts
index 31c1c3b..d691b6f 100644
--- a/src/locales/index.ts
+++ b/src/locales/index.ts
@@ -11,9 +11,11 @@ export async function i18nInit() {
const en = (await import('./en')).default;
const zh_Hans = (await import('./zh-Hans')).default;
+ const fa = (await import('./fa')).default;
const resources = {
en,
+ fa,
['zh_Hans']: zh_Hans,
};
diff --git a/src/main.tsx b/src/main.tsx
index e07456d..394020e 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -9,6 +9,8 @@ import 'virtual:svg-icons-register';
import { defaultLightMode, setScrollStyle } from '@/utils/scrollStyle';
import '@ant-design/v5-patch-for-react-19';
+const basename = import.meta.env.VITE_BASENAME;
+
enableMapSet();
async function enableMocking() {
@@ -21,6 +23,9 @@ async function enableMocking() {
}
return;
},
+ serviceWorker: {
+ url: `${basename ?? ''}/mockServiceWorker.js`
+ }
});
}
@@ -34,7 +39,10 @@ const root = createRoot(document.getElementById('root')!);
enableMocking().then(async() => {
await i18nInit();
root.render(
-
+
diff --git a/src/models/withAuth/index.ts b/src/models/withAuth/index.ts
index 7c8354a..75265b0 100644
--- a/src/models/withAuth/index.ts
+++ b/src/models/withAuth/index.ts
@@ -2,7 +2,7 @@ import { Model, INITIAL_STATE } from '@zhangsai/model';
import { httpGetBaseInfo } from '@/services/withAuth';
import formatPermissions from './permissions';
import { lsGetToken, lsRemoveToken } from '@/utils/business/token';
-import router, { history } from '@/router';
+import router from '@/router';
import { httpPostLogout } from '@/services/login';
import i18n from '@/locales';
import { message } from '@/components/AntdProvider';
@@ -36,7 +36,7 @@ class WithAuth extends Model {
hasToken: false,
loading: false,
});
- history.push(`/login?reUrl=${window.location.href}`);
+ router.push(`/login?reUrl=${encodeURIComponent(router.pathname)}`);
return;
}
@@ -61,7 +61,7 @@ class WithAuth extends Model {
const routePath = router.getRoutePath(window.location.pathname);
const route = router.flattenRoutes.get(routePath);
if (route?.permission && !this.state.permissions[route.permission]) {
- history.push('/no-access');
+ router.push('/no-access');
}
}
/**
@@ -86,7 +86,7 @@ class WithAuth extends Model {
return httpPostLogout().then(() => {
this.destroy();
message.success(i18n.t('layout:已登出'));
- history.push('/login');
+ router.push('/login');
lsRemoveToken();
});
}
diff --git a/src/models/withAuth/permissions.ts b/src/models/withAuth/permissions.ts
index ea94e89..ae7ea19 100644
--- a/src/models/withAuth/permissions.ts
+++ b/src/models/withAuth/permissions.ts
@@ -7,6 +7,7 @@ function formatPermissions(permissions: string[]) {
return {
home: set.has('home'),
homeIndex: set.has('home:index'),
+ homeAlive: set.has('home:alive'),
homeGrid: set.has('home:grid'),
profile: set.has('profile'),
diff --git a/src/pages/alive/index.tsx b/src/pages/alive/index.tsx
new file mode 100644
index 0000000..a34db41
--- /dev/null
+++ b/src/pages/alive/index.tsx
@@ -0,0 +1,46 @@
+import { themeModel } from '@/models/theme';
+import { useModel } from '@zhangsai/model';
+import { InputNumber, Space } from 'antd';
+import { useState } from 'react';
+
+const Alive = () => {
+ const [count, setCount] = useState();
+ const [showAd, setShowAd] = useState(false);
+ const colorPrimary = useModel(themeModel, 'colorPrimary');
+
+ return (
+
+
+
+ 输入数字并滚动滚轮,切换到其他页面,然后再切换回来,看看数字和滚轮状态是否还保持原来:
+
+ 练习了 {
+ if (v) {
+ setCount(v);
+ }
+ }} /> 年半?
+
+
+
+
+ {count && (
+
+ )}
+
+ );
+}
+
+export default Alive;
diff --git a/src/pages/grid/index.less b/src/pages/grid/index.less
index 7ed1f6f..f708543 100644
--- a/src/pages/grid/index.less
+++ b/src/pages/grid/index.less
@@ -1,5 +1,5 @@
.console-grid__item {
- height: 150px;
+ block-size: 150px;
border-radius: 8px;
margin: 8px;
}
diff --git a/src/pages/login/LoginForm.tsx b/src/pages/login/LoginForm.tsx
index 86204ee..177d128 100644
--- a/src/pages/login/LoginForm.tsx
+++ b/src/pages/login/LoginForm.tsx
@@ -1,5 +1,5 @@
import { message } from '@/components/AntdProvider';
-import { history } from '@/router';
+import router from '@/router';
import { httpPostLogin } from '@/services/login';
import { lsSetToken } from '@/utils/business/token';
import { Button, Checkbox, Flex, Form, Input } from 'antd';
@@ -24,7 +24,7 @@ const LoginForm = () => {
lsSetToken(data.accessToken, data.refreshToken, data.expiration);
message.success(t_login('登录成功'));
const reUrl = window.location.search.replace(/^\?/, '').split('&').map(item => item.split('=')).find(([key]) => key === 'reUrl')?.[1];
- history.push(reUrl ?? '/home');
+ router.push(decodeURIComponent(reUrl || '') || '/home');
}).catch(() => {});
}).catch(() => {});
};
diff --git a/src/pages/noAccess/index.tsx b/src/pages/noAccess/index.tsx
index 75dad38..0fd487f 100644
--- a/src/pages/noAccess/index.tsx
+++ b/src/pages/noAccess/index.tsx
@@ -1,5 +1,5 @@
import { Button } from 'antd';
-import { history } from '@/router';
+import router from '@/router';
import { useTranslation } from 'react-i18next';
import SvgIcon from '@/components/SvgIcon';
import './index.less';
@@ -14,7 +14,7 @@ const NoAccess = () => {
{t_error('对不起,您没有访问权限')}
-
history.push('/home')}>{t_error('回到主页')}
+
router.push('/home')}>{t_error('回到主页')}
);
diff --git a/src/pages/notFound/index.tsx b/src/pages/notFound/index.tsx
index 2bd7324..1d96a52 100644
--- a/src/pages/notFound/index.tsx
+++ b/src/pages/notFound/index.tsx
@@ -1,5 +1,5 @@
import { Button } from 'antd';
-import { history } from '@/router';
+import router from '@/router';
import { useTranslation } from 'react-i18next';
import SvgIcon from '@/components/SvgIcon';
import './index.less';
@@ -15,7 +15,7 @@ const NotFound = () => {