feat: 路由调整

This commit is contained in:
Mozzie 2023-09-07 16:42:34 +08:00
parent c522de39ae
commit 098f90d746
16 changed files with 134 additions and 99 deletions

View File

@ -21,7 +21,8 @@
"@tavi/i18n": "^1.5.0", "@tavi/i18n": "^1.5.0",
"@tavi/util": "1.0.0", "@tavi/util": "1.0.0",
"js-cookie": "3.0.5", "js-cookie": "3.0.5",
"three": "0.156.1" "three": "0.156.1",
"path-to-regexp": "6.2.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.21.8", "@babel/core": "^7.21.8",

View File

@ -1,13 +1,14 @@
import { Outlet } from "react-router"; import { Outlet, useLocation } from "react-router";
interface LayoutProps { interface LayoutProps {
children?: JSX.Element; children?: JSX.Element;
} }
export const Layout = (props: LayoutProps) => { export const Layout = (props: LayoutProps) => {
const location = useLocation();
return ( return (
<div> <div>
<header>12222</header> <header> {location.pathname}</header>
<Outlet /> <Outlet />
</div> </div>
); );

View File

@ -25,3 +25,5 @@ export const theme: ThemeConfig = {
* @enum "zh-CN" | 'en' | 'en-US' | 'zh' * @enum "zh-CN" | 'en' | 'en-US' | 'zh'
*/ */
export const defaultLang = "zh-CN"; export const defaultLang = "zh-CN";

View File

@ -4,8 +4,6 @@ import { FormFields, LoginForm } from "./LoginForm";
import "./index.less"; import "./index.less";
import { useDomain } from "@/hook/useDomain"; import { useDomain } from "@/hook/useDomain";
import { useTranslation } from "@tavi/i18n"; import { useTranslation } from "@tavi/i18n";
import { Observer, observer } from "mobx-react-lite";
import { UserService } from "@@/domain/User/UserService";
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
import { message } from "antd"; import { message } from "antd";
@ -13,14 +11,6 @@ interface LoginProps {
children?: JSX.Element; children?: JSX.Element;
} }
// const TestComponent: React.FC<{ domainService: UserService }> = observer(
// ({ domainService }) => (
// <div style={{ color: "#fff" }}>
// <p>name: {domainService.user.isLoggedIn ? "登录" : "未登录"}</p>
// </div>
// )
// );
export const Login = (props: LoginProps) => { export const Login = (props: LoginProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const navigate = useNavigate(); const navigate = useNavigate();
@ -55,7 +45,6 @@ export const Login = (props: LoginProps) => {
<Logo isClicked={false} /> <Logo isClicked={false} />
<LanguageSelect /> <LanguageSelect />
</header> </header>
{/* <TestComponent domainService={userDomainService} /> */}
<LoginForm <LoginForm
styles={{ width: "100%" }} styles={{ width: "100%" }}
onFormChange={(v) => userDomainService.updateLoginForm(v)} onFormChange={(v) => userDomainService.updateLoginForm(v)}

View File

@ -1,47 +1,29 @@
import { AuthFailedReplacePath } from "@/constant"; import { AuthFailedReplacePath } from "@/constant";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
import { useEffect } from "react"; import { pathToRegexp } from "path-to-regexp";
import { useDomain } from "@/hook/useDomain"; import { useDomain } from "@/hook/useDomain";
import { message } from "antd";
interface GuardProps { interface RouteGuardProps {
element: JSX.Element; children?: React.ReactNode;
auth?: boolean; ignorePaths: string[];
title?: string;
} }
/** export const RouteGuard = (props: RouteGuardProps) => {
* const { children, ignorePaths } = props;
*/ const { userDomainService } = useDomain();
export const Guard = (props: GuardProps) => { const { user } = userDomainService;
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
const { userDomainService } = useDomain();
const [messageApi, contextHolder] = message.useMessage();
const { isLoggedIn } = userDomainService.user;
useEffect(() => { const ignore = ignorePaths.some((p) =>
if (props.auth && !isLoggedIn) { pathToRegexp(p).test(location.pathname)
userDomainService.userAuth().then((result: any) => { );
const { success, msg } = result;
if (!success) { if (!ignore && !user.isLoggedIn) {
messageApi.error(msg); userDomainService.userAuth().then(({ success }) => {
navigate(AuthFailedReplacePath); if (!success) navigate(AuthFailedReplacePath);
}
}); });
} }
return () => {};
}, [navigate]);
useEffect(() => { return children;
if (props?.title) document.title = props?.title;
return () => {};
}, [location.pathname]);
return (
<>
{contextHolder}
{props.element}
</>
);
}; };

View File

@ -1,4 +1,44 @@
import { routesConfig } from "./router.config"; import { baseRoutes } from "./router.config";
import { useRoutes } from "react-router"; import { Route, RouteObject, Routes, useLocation } from "react-router-dom";
import { RouteGuard } from "./AuthGuard";
import { pathToRegexp } from "path-to-regexp";
import { defaultTitle } from "@/constant";
export const RouterElements = () => useRoutes(routesConfig); // export const RouterElements = () => useRoutes(routesConfig);
export type ExpandRouteProps = {
title?: string;
};
export const RouterElements = () => {
const location = useLocation();
console.log(location.pathname);
/**
* document.title
*/
const currentRoute = [...baseRoutes].find((r) =>
pathToRegexp(location.pathname).test(r.path!)
);
document.title = currentRoute?.title ?? defaultTitle;
/**
* children
*/
const generateRoutes = (routes: (RouteObject & ExpandRouteProps)[]) =>
routes.map((r) => (
<Route key={r.path} path={r.path} element={r.element}>
{r.children && generateRoutes(r.children)}
</Route>
));
return (
<RouteGuard ignorePaths={[]}>
<Routes>
{generateRoutes(baseRoutes)}
<Route key="notfound" path="*" element={<span>404</span>} />
</Routes>
</RouteGuard>
);
};

View File

@ -5,17 +5,22 @@ import { RootViewer } from "../modules/Root/Viewer/Root";
import { PeripheralViewer } from "../modules/Peripheral"; import { PeripheralViewer } from "../modules/Peripheral";
import { Dashboard } from "@/modules/Dashboard"; import { Dashboard } from "@/modules/Dashboard";
import { ReportFullVersion } from "@/modules/Report/Full"; import { ReportFullVersion } from "@/modules/Report/Full";
import { Guard } from "./AuthGuard";
import { Layout } from "@/components/Layout"; import { Layout } from "@/components/Layout";
import { ExpandRouteProps } from ".";
export const routesConfig: RouteObject[] = [ /**
*
*/
export const baseRoutes: (RouteObject & ExpandRouteProps)[] = [
{ {
path: "login", path: "/login",
element: <Guard element={<Login />} title="CVPILOT Viewer" />, element: <Login />,
title: "登录 - CVPILOT Viewer",
}, },
{ {
path: "/", path: "/",
element: <Guard element={<Layout />} auth />, element: <Layout />,
title: "CVPILOT Viewer",
children: [ children: [
{ {
path: "/", path: "/",
@ -23,28 +28,24 @@ export const routesConfig: RouteObject[] = [
}, },
{ {
path: "dash", path: "dash",
element: <Guard element={<Dashboard />} title="仪表盘" />, element: <Dashboard />,
}, },
{ {
path: "list", path: "list",
element: <Guard element={<PatientList />} title="患者列表" />, element: <PatientList />,
}, },
{ {
path: "root/viewer", path: "root/viewer",
element: <Guard element={<RootViewer />} title="根部分析" />, element: <RootViewer />,
}, },
{ {
path: "root/report/full", path: "root/report/full",
element: <Guard element={<ReportFullVersion />} title="完整报告" />, element: <ReportFullVersion />,
}, },
{ {
path: "peripheral/viewer", path: "peripheral/viewer",
element: <Guard element={<PeripheralViewer />} title="外周分析" />, element: <PeripheralViewer />,
}, },
], ],
}, },
{
path: "*",
element: <span>404</span>,
},
]; ];

View File

@ -5,8 +5,7 @@ import { User } from "./entities/User";
export class RbacRepository { export class RbacRepository {
async saveRole(role: Role) { async saveRole(role: Role) {
const { code } = await Apis.saveRole(role); return await Apis.saveRole(role);
return code === "ok";
} }
async updateRole(role: Role) { async updateRole(role: Role) {
@ -43,8 +42,8 @@ export class RbacRepository {
} }
async saveUser(user: User) { async saveUser(user: User) {
const { code } = await Apis.saveUser(user); const { code, data, msg } = await Apis.saveUser(user);
return code === "ok"; return { code, data, msg };
} }
async updateUser(user: Omit<User, "roles"> & { roles: number[] }) { async updateUser(user: Omit<User, "roles"> & { roles: number[] }) {

View File

@ -37,11 +37,14 @@ export class RbacService {
* *
*/ */
async addRole(role: Role) { async addRole(role: Role) {
const { code, msg } = await this.rbacRepository.saveRole(role);
if (code === 0) {
this.roleList = [ this.roleList = [
...this.roleList, ...this.roleList,
{ ...role, isEnabled: true, permissions: [] }, { ...role, isEnabled: true, permissions: [] },
]; ];
return await this.rbacRepository.saveRole(role); }
return { code, msg };
} }
/** /**
@ -115,8 +118,14 @@ export class RbacService {
phoneNumber, phoneNumber,
createTime: new Date().toLocaleString(), createTime: new Date().toLocaleString(),
}; };
this.userList = [...this.userList, user]; const { code, data, msg } = await this.rbacRepository.saveUser({
return await this.rbacRepository.saveUser({ ...user, password }); ...user,
password,
});
if (code === 0) {
this.userList = [...this.userList, data as User];
}
return { data, msg, code };
} }
/** /**

View File

@ -26,8 +26,9 @@ export const Role = (props: RoleProps) => {
const onModalConfirm = async (fields: fieldsType) => { const onModalConfirm = async (fields: fieldsType) => {
setModalVisible(false); setModalVisible(false);
const ok = await rbacDomainService.addRole({ ...fields }); const { code, msg } = await rbacDomainService.addRole({ ...fields });
messageApi.info(ok ? "ok" : "failed"); code === 0 ? messageApi.success(msg) : messageApi.error(msg);
rbacDomainService.findAllRoleWithPermissions();
}; };
const RoleListComponent: React.FC<{ domainService: RbacService }> = observer( const RoleListComponent: React.FC<{ domainService: RbacService }> = observer(

View File

@ -25,13 +25,18 @@ export const CreateUserForm = (props: CreateUserFormProps) => {
const onConfirmCreateUser = async (fields: CreateUserFormFields) => { const onConfirmCreateUser = async (fields: CreateUserFormFields) => {
const { roleIds, username, password, phoneNumber } = fields; const { roleIds, username, password, phoneNumber } = fields;
const success = await rbacDomainService.saveUser({ const { code, data, msg } = await rbacDomainService.saveUser({
roleIds, roleIds,
username, username,
password, password,
phoneNumber, phoneNumber,
}); });
if (success) messageApi.success(`用户: ${username} 创建成功`); if (code === 0) {
messageApi.success(msg);
rbacDomainService.findAllRoleWithPermissions();
} else {
messageApi.error(msg);
}
}; };
return ( return (

View File

@ -36,7 +36,7 @@ export const RouterElements = observer(() => {
const currentRoute = [...currentRoutes, ...baseRoutes].find((r) => const currentRoute = [...currentRoutes, ...baseRoutes].find((r) =>
pathToRegexp(r.path!).test(location.pathname) pathToRegexp(r.path!).test(location.pathname)
); );
if (currentRoute) document.title = currentRoute.title || defaultDocumentTitle; document.title = currentRoute?.title ?? defaultDocumentTitle;
/** /**
* children * children

View File

@ -53,10 +53,10 @@ export class RbacService {
async createRole(payload: Role) { async createRole(payload: Role) {
const { name, alias, description } = payload; const { name, alias, description } = payload;
const exsit = await this.roleRepository.findOne({ where: { name } }); const exist = await this.roleRepository.findOne({ where: { name } });
if (exsit) return { message: '用户已存在' }; if (exist) return { message: '角色已存在', success: false };
const result = await this.roleRepository.save({ name, alias, description }); const result = await this.roleRepository.save({ name, alias, description });
return result; return { success: true, result, message: '角色创建成功' };
} }
async findAllRole() { async findAllRole() {

View File

@ -43,14 +43,15 @@ export class UserService {
}, },
}); });
// 如果username存在 // 如果username存在
if (user) return false; if (user) return { success: false, msg: '用户名已存在' };
const cipher = await this.bcryptService.hashPassword(password); const cipher = await this.bcryptService.hashPassword(password);
return await this.userRepository.save({ const userCreated = await this.userRepository.save({
username, username,
password: cipher, password: cipher,
phoneNumber, phoneNumber,
roles, roles,
}); });
return { success: true, msg: '用户创建成功', data: userCreated };
} }
async update(fields: User) { async update(fields: User) {

View File

@ -24,11 +24,12 @@ export class AdminController {
@Post('role/create') @Post('role/create')
async createRole(@Body() createRoleDto: CreateRoleDto) { async createRole(@Body() createRoleDto: CreateRoleDto) {
const pattern = { cmd: 'cert.create.role' }; const { success, result, message } = await firstValueFrom(
const result = await firstValueFrom( this.client.send({ cmd: 'cert.create.role' }, createRoleDto),
this.client.send(pattern, createRoleDto),
); );
return { code: 'ok', data: result }; return success
? { code: 0, data: result, msg: message }
: { code: 1, msg: message };
} }
@Post('role/remove') @Post('role/remove')
@ -87,17 +88,17 @@ export class AdminController {
@Post('user/create') @Post('user/create')
async createUser(@Body() createUserDto: CreateUserDto) { async createUser(@Body() createUserDto: CreateUserDto) {
const pattern = { cmd: 'cert.user.create' }; const { success, msg, data } = await firstValueFrom(
const payload = createUserDto; this.client.send({ cmd: 'cert.user.create' }, createUserDto),
const result = await firstValueFrom(this.client.send(pattern, payload)); );
return { code: 'ok', data: result }; return success ? { code: 0, data, msg } : { code: 1, msg };
} }
@Get('user/find/all') @Get('user/find/all')
async userSelect() { async userSelect() {
const pattern = { cmd: 'cert.find.all.user' }; const result = await firstValueFrom(
const payload = []; this.client.send({ cmd: 'cert.find.all.user' }, []),
const result = await firstValueFrom(this.client.send(pattern, payload)); );
return { code: 'ok', data: result }; return { code: 'ok', data: result };
} }

View File

@ -34,6 +34,9 @@ importers:
mobx-react-lite: mobx-react-lite:
specifier: 3.4.3 specifier: 3.4.3
version: 3.4.3(mobx@6.9.0)(react-dom@18.2.0)(react@18.2.0) version: 3.4.3(mobx@6.9.0)(react-dom@18.2.0)(react@18.2.0)
path-to-regexp:
specifier: 6.2.1
version: 6.2.1
react: react:
specifier: 18.2.0 specifier: 18.2.0
version: 18.2.0 version: 18.2.0