feat(all): 初始化

This commit is contained in:
NICE CODE BY DEV 2024-07-09 17:16:13 +08:00
parent e704045bfa
commit 54096d5ee7
25 changed files with 689 additions and 79 deletions

15
config/config.dev.ts Normal file
View File

@ -0,0 +1,15 @@
import { defineConfig } from '@umijs/max';
import routes from './routes/base';
export default defineConfig({
routes,
define: {
APP_ENV: process.env.NODE_ENV || 'development',
COMMON_URL: 'http://10.0.1.231:31300', // 基建服务
MATERIAL_URL: 'http://10.0.0.222',
CABINET_HOST: '/cabinet/',
VIDEO_HOST: '/video/',
ALGORITHM_HOST: '/algorithm/',
MATERIAL_HOST: '/material/'
},
});

View File

@ -1,6 +1,8 @@
import { defineConfig } from '@umijs/max';
import routes from './routes';
export default defineConfig({
routes,
define: {
APP_ENV: 'production',
CABINET_HOST: '/cabinet/',

15
config/config.test.ts Normal file
View File

@ -0,0 +1,15 @@
import { defineConfig } from '@umijs/max';
import routes from './routes';
export default defineConfig({
routes,
define: {
APP_ENV: 'test',
CABINET_HOST: '/cabinet/',
VIDEO_HOST: '/video/',
ALGORITHM_HOST: '/algorithm/',
MATERIAL_HOST: '/material/',
COMMON_URL: 'http://10.0.1.231:31300', // 基建服务
MATERIAL_URL: 'http://10.0.0.222',
},
});

View File

@ -1,5 +1,7 @@
import { defineConfig } from '@umijs/max';
import routes from './routes';
import pxtorem from 'postcss-pxtorem';
const rootFontSize = 80 // 设计稿尺寸32px = 1rem; @default 80
export default defineConfig({
favicons: ['/assets/logo.jpg'],
@ -15,10 +17,42 @@ export default defineConfig({
},
},
mfsu: false,
routes,
npmClient: 'pnpm',
define: {
APP_ENV: process.env.NODE_ENV || 'development',
COMMON_URL: 'http://10.0.0.204:30058', // 基建服务
alias: {
'@src': '/src',
'@components': '/src/components',
'@constants': '/src/constants',
'@common': '/src/common',
'@utils': '/src/utils',
'@public': '/public',
},
define: {
// ROUTES: routes,
// PLATFORM_TITLE: pkg.description,
ROOT_FONT_SIZE: rootFontSize,
APP_LIST: [
{
name: 'video', // 视频分析
entry: '//localhost:30088/',
},
{
name: 'cabinet', // 盒子管理
entry: '//localhost:30068/',
},
{
name: 'material', // 物料仓
entry: '//localhost:30098/',
},
{
name: 'algorithm', // 算法分析
entry: '//localhost:30078/',
},
]
},
extraPostCSSPlugins: [
pxtorem({
rootValue: rootFontSize,//结果为:设计稿元素尺寸/16比如元素宽320px,最终页面会换算成 20rem
propList: ['*'],
}),
]
});

44
config/routes/base.ts Normal file
View File

@ -0,0 +1,44 @@
const routes = [
{
path: '/',
redirect: 'material/home',
},
{
name: '测试页(开发环境)',
path: '/test',
routes: [
{
name: '性能测试',
path: '/test/demo',
component: '@/pages/test',
},
],
},
{
path: '/',
component: '@/layouts/BaseLayout/index.tsx',
routes: [
{
name: 'cabinet',
path: '/cabinet/*',
microApp: 'cabinet',
},
{
name: 'algorithm',
path: '/algorithm/*',
microApp: 'algorithm',
},
{
name: 'video',
path: '/video/*',
microApp: 'video',
},
],
},
{
name: '物料库',
path: '/material/*',
microApp: 'material',
},
];
export default routes;

View File

@ -1,28 +1,9 @@
const routes = [
{
name: 'home',
path: '/',
redirect: '/material/home',
},
{
name: 'cabinet',
path: '/cabinet/*',
microApp: 'cabinet',
},
{
name: 'algorithm',
path: '/algorithm/*',
microApp: 'algorithm',
},
{
name: 'video',
path: '/video/*',
microApp: 'video',
},
{
name: '物料库',
path: '/material/*',
microApp: 'material',
},
];
export default routes;
import BaseRoutes from './base'
const routes = BaseRoutes.concat([{
name: 'home',
path: '/',
redirect: '/material/home',
}])
export default routes

67
config/routes/types.d.ts vendored Normal file
View File

@ -0,0 +1,67 @@
export interface RouteProps {
icon: string;
// https://beta-pro.ant.design/docs/advanced-menu
// ---
// 新页面打开
target: '_blank';
// 不展示顶栏
headerRender: boolean;
// 不展示页脚
footerRender: boolean;
// 不展示菜单
menuRender: boolean;
// 不展示菜单顶栏
menuHeaderRender: boolean;
// 权限配置,需要与 plugin-access 插件配合使用
access: 'canRead';
// 隐藏子菜单
hideChildrenInMenu: boolean;
// 隐藏自己和子菜单
hideInMenu: boolean;
// 在面包屑中隐藏
hideInBreadcrumb: boolean;
// 子项往上提,仍旧展示,
flatMenu: boolean;
/**
* @name false
*/
headerRender?: boolean;
/**
* @name false
*/
footerRender?: boolean;
/**
* @name false
*/
menuRender?: boolean;
/**
* @name false
*/
menuHeaderRender?: boolean;
/**
* @name
**/
fixedHeader: boolean;
/**
* @name
*/
fixSiderbar: boolean;
/**
* @name theme for nav menu
* @name
*/
navTheme: 'dark' | 'light' | 'realDark' | undefined;
/**
* @name nav menu position: `side` or `top`
* @name
* @description side top菜单显示在顶部mix
*/
layout: 'side' | 'top' | 'mix';
/**
* @name mix
*/
headerTheme: 'dark' | 'light';
}

View File

@ -1,6 +1,6 @@
pnpm install
pnpm run build:master
pnpm run build:test
mkdir -p ./app/public/

3
global.d.ts vendored
View File

@ -1,5 +1,8 @@
declare const APP_ENV: string;
declare const APP_LIST: any[];
declare const COMMON_URL: string;
declare const MATERIAL_URL: string;
declare const VIDEO_HOST: string;
declare const ALGORITHM_HOST: string;
declare const MATERIAL_HOST: string;
declare const ROOT_FONT_SIZE: number;

View File

@ -4,6 +4,7 @@
"author": "dev <710328466@qq.com>",
"scripts": {
"build:master": "cross-env APP_ENV=production max build",
"build:test": "cross-env UMI_ENV=test max build",
"comp": "cross-env max g component",
"dev": "max dev",
"format": "prettier --cache --write .",
@ -14,10 +15,12 @@
"start": "npm run dev"
},
"dependencies": {
"@ant-design/cssinjs": "^1.21.0",
"@ant-design/icons": "^5.3.0",
"@ant-design/pro-components": "^2.6.49",
"@umijs/max": "^4.1.1",
"@zhst/func": "^0.8.1",
"@zhst/hooks": "^0.15.0",
"@zhst/request": "^0.12.1",
"@zhst/slave": "^0.7.1",
"antd": "^5.14.1",
@ -28,6 +31,7 @@
"@types/react-dom": "^18.2.19",
"husky": "^9.0.11",
"lint-staged": "^15.2.2",
"postcss-pxtorem": "^6.1.0",
"prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^3.2.4",
"prettier-plugin-packagejson": "^2.4.11",

View File

@ -20,46 +20,20 @@ export const useQiankunStateForSlave = useFatherAction;
*/
const hostname = location.port ? `${location.hostname}:${location.port}` : location.hostname
export const qiankun = {
apps: [
const initApp = (appList: any[]) => {
return appList.map(app => (
{
name: 'cabinet', // 盒子管理
entry:
APP_ENV === 'production'
? `//${hostname}/cabinet/`
: '//localhost:30088/',
name: app.name,
entry: APP_ENV === 'production' ? `//${hostname}/${app.name}/` : app.entry,
props: {},
singular: false,
credentials: true,
},
{
name: 'video', // AI 智能分析仓
entry:
APP_ENV === 'production'
? `//${hostname}/video/`
: '//localhost:30068/',
singular: false,
credentials: true,
},
{
name: 'algorithm', // AI 算法分析
entry:
APP_ENV === 'production'
? `//${hostname}/algorithm/`
: '//localhost:30078/',
singular: false,
credentials: true,
},
{
name: 'material', // 物料库
entry:
APP_ENV === 'production'
? `//${hostname}/material/`
: '//localhost:30098/',
singular: false,
credentials: true,
},
],
}
))
}
export const qiankun = {
apps: initApp(APP_LIST),
lifeCycles: {
// 所有子应用在挂载完成时,打印 props 信息
async afterMount() {

BIN
src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,4 +1,51 @@
* {
padding: 0;
margin: 0;
#logo {
justify-content: center;
}
#root-master .ant-pro-layout .ant-pro-layout-content {
padding: 0;
}
#root-master .ant-layout-header .ant-menu {
justify-content: center;
.ant-menu-item {
color: #191919;
}
}
#root-master .ant-layout-header .ant-pro-base-menu-horizontal-item-text {
color: #fff;
}
.ant-menu .ant-menu-item-only-child {
color: #191919!important;
}
#root-master .ant-pro-page-container {
.ant-page-header {
padding: 7px 0;
.ant-page-header-heading {
padding: 0 20px;
}
.ant-page-header-heading-title {
font-size: 14px;
line-height: 20px;
color: #191919;
}
}
.ant-layout-content {
padding: 0;
}
.ant-pro-page-container-children-container {
padding: 0;
margin: 0 20px 20px 20px;
}
}
.ant-menu-light.ant-menu-horizontal>.ant-menu-item,
.ant-menu-light.ant-menu-horizontal>.ant-menu-submenu {
border-radius: 0px;
}

View File

@ -0,0 +1,140 @@
import { RouteProps } from "config/routes/types";
const formatRoutes = ({ routes = [], prefix = null }) => {
return routes.map((route) => {
const { name, path, routes: children,...rest } = route;
return {
name,
path: route.routes?.length ? path : `/${prefix}${path}`,
routes: formatRoutes({ routes: children, prefix }),
...rest,
};
});
}
// ?------------ 视频模块路由 -----------------
const videoRoutes = [
{
name: '实时监控',
path: '/realTimeMonitor',
component: '@/pages/RealTimeMonitor',
},
{
name: '预警记录',
path: '/alarmManage',
routes: [
{
name: '预警记录',
path: '/alarmManage/AlarmRecord',
component: '@/pages/AlarmRecord',
},
{
name: '误报库',
path: '/alarmManage/errorLibrary',
component: '@/pages/errorLibrary',
},
]
},
{
name: '人流量统计',
path: '/trafficCount',
component: '@/pages/TrafficCount',
},
]
const algorithmRoutes = [
{
name: '算法管理',
path: '/algorithmManage/algorithmManage',
routes: [
{
name: '算法配置',
path: '/algorithmManage/algorithmConfig',
component: '@/pages/AlgorithmManage',
},
{
name: '时间模版',
path: '/algorithmManage/timeTemplate',
component: '@/pages/BoxManage/TimeTemplate',
},
],
},
{
name: '摄像头管理',
path: '/cameraManage',
component: '@/pages/cameraManage/index',
},
{
name: '系统配置',
path: '/systemConfig',
routes: [
// {
// name: '电子地图配置',
// path: '/systemConfig/mapConfig',
// component: '@/pages/SystemConfig/MapConfig',
// },
{
name: '修改密码',
path: '/systemConfig/editPassword',
component: '@/pages/SystemConfig/EditPassword',
},
{
name: '组织管理',
path: '/systemConfig/organizeManage',
component: '@/pages/SystemConfig/OrganizeManage',
},
{
name: '角色管理',
path: '/systemConfig/roleManage',
component: '@/pages/SystemConfig/RoleManage',
},
{
name: '用户管理',
path: '/systemConfig/userManage',
component: '@/pages/SystemConfig/UserManage',
},
],
},
]
const routes = [
{
name: '首页',
path: '/home',
hideInMenu: true,
component: '@/pages/home',
},
{
name: '登录',
path: '/login',
hideInMenu: true,
component: '@/pages/login',
},
{
name: '未找到页面',
path: '/*',
layout: false,
hideInMenu: true,
component: '@/pages/404',
},
{
name: '无权限页面',
path: '/403',
layout: false,
hideInMenu: true,
component: '@/pages/403',
},
{
name: '修改密码',
path: '/video/editPassword',
component: '@/pages/EditPassword',
hideInMenu: true,
},
...formatRoutes({ routes: videoRoutes, prefix: 'video' }),
...formatRoutes({ routes: algorithmRoutes, prefix: 'algorithm'})
];
export default routes;

View File

View File

@ -0,0 +1,131 @@
// import { SettingOutlined, ShopOutlined } from '@ant-design/icons';
import logo from '@/assets/logo.png';
import {
MicroAppLink,
Outlet,
history,
useLocation,
useModel,
} from '@umijs/max';
import { px2remTransformer, StyleProvider } from '@ant-design/cssinjs';
import { ProConfigProvider, ProLayout, ProSettings } from '@ant-design/pro-components';
import React, { useState } from 'react';
import slave from '@zhst/slave';
import routes from './defaultRoutes'
import styles from './index.less';
import { BankOutlined } from '@ant-design/icons';
import { Dropdown, App } from 'antd';
const Layout = (props) => {
const [settings] = useState<Partial<ProSettings> | undefined>({
layout: 'top',
});
const location = useLocation();
const [pathname, setPathname] = useState('')
const px2rem = px2remTransformer({
rootValue: ROOT_FONT_SIZE, // 32px = 1rem; @default 16
});
const { userInfo = {}, hasAuth } = useModel('user') || {};
console.log(userInfo)
return (
<div className={styles.layout}>
<App>
<StyleProvider transformers={[px2rem]} hashPriority='high'>
<ProConfigProvider hashed={false}>
<ProLayout
route={{
path: '/',
routes
}}
title="明眸智能分析系统"
logo={logo}
token={{
header: {
heightLayoutHeader: 60,
colorBgHeader: '#313c5d',
colorHeaderTitle: '#fff',
colorTextMenu: '#fff',
colorTextMenuSelected: '#fff',
colorTextMenuActive: '#fff',
colorBgMenuItemSelected: '#23ACB2',
colorBgMenuItemHover: '#23ACB2',
colorTextRightActionsItem: '#fff',
colorTextMenuSecondary: '#000',
},
}}
menu={{}}
menuProps={{
mode: 'horizontal',
}}
avatarProps={{
src: userInfo?.username || '-',
size: 'small',
title: userInfo?.username || '-',
render: (props, dom) => {
return (
<Dropdown
menu={{
items: [
{
key: 'changepassword',
label: '修改密码',
onClick: () => {
history.push('/algorithm/editPassword');
setPathname('/algorithm/editPassword')
},
},
{
key: 'logout',
label: <span style={{ color: 'red' }}>退</span>,
onClick: () => slave.logOut(`${COMMON_URL || location.origin}/material/login`),
},
],
}}
>
{dom}
</Dropdown>
);
},
}}
actionsRender={() => {
return [
// <Badge dot key="alarm">
// <IconFont icon="icon-xiaoxi" size={18} color="#fff" />
// </Badge>,
// <MicroAppLink name="algorithm" to="/" key="algorithm">
// <div style={{ cursor: 'pointer' }}>
// <BankOutlined
// style={{ fontSize: 18, color: '#fff', marginRight: 5 }}
// />
// AI算法仓平台
// </div>
// </MicroAppLink>
];
}}
location={{
pathname,
}}
menuItemRender={(item: { path: string }, dom) => (
<div
onClick={() => {
history.push(item.path || '/');
setPathname(item.path);
}}
>
{dom}
</div>
)}
{...settings}
>
<Outlet />
</ProLayout>
</ProConfigProvider>
</StyleProvider>
</App>
</div>
);
};
export default Layout;

View File

@ -1,13 +1,13 @@
import { SettingOutlined, ShopOutlined } from '@ant-design/icons';
// import { SettingOutlined, ShopOutlined } from '@ant-design/icons';
import { Outlet } from '@umijs/max';
import { FloatButton } from 'antd';
// import { FloatButton } from 'antd';
import React from 'react';
import styles from './index.less';
const Layout = () => {
return (
<div className={styles.layout}>
<FloatButton.Group
{/* <FloatButton.Group
trigger="click"
type="primary"
style={{ right: 32 }}
@ -24,7 +24,7 @@ const Layout = () => {
onClick={() => (location.href = 'http://10.0.0.204:30080')}
/>
<FloatButton tooltip="demo 展示" icon={<ShopOutlined />} />
</FloatButton.Group>
</FloatButton.Group> */}
<Outlet />
</div>
);

36
src/models/user.ts Normal file
View File

@ -0,0 +1,36 @@
// 全局共享数据
import userController from '../service/user';
import { get } from '@zhst/func';
import { useRequest } from '@zhst/hooks';
import { useState } from 'react';
const useUser = () => {
const [userInfo, setUserInfo] = useState(null);
const [userRights, setUserRights] = useState(null);
// @ts-ignore
const { run, loading: userLoading } = useRequest(async () => {
let res = await userController.postUserInfo();
let userRightsRes = await userController.getUserRights({
userId: res.userInfo.userId,
});
setUserRights(userRightsRes);
setUserInfo(res.userInfo);
});
// 判断用户是否具有某一模块的路由权限
const hasAuth = (key: string) => {
const funcs = get(userRights, 'functions')
? JSON.parse(get(userRights, 'functions'))
: [];
return funcs.some((item: string) => item === key);
};
return {
userInfo,
run,
userLoading,
hasAuth,
};
};
export default useUser;

View File

@ -1,6 +1,6 @@
import React from 'react';
export default function HomePage() {
export default function ErrorPage() {
return (
<div>
<h2>error</h2>

View File

@ -0,0 +1,4 @@
.ant-card-head {
position: relative;
z-index: 2;
}

14
src/pages/test/index.tsx Normal file
View File

@ -0,0 +1,14 @@
import { MicroAppWithMemoHistory } from '@umijs/max';
import { Card } from 'antd'
import React from 'react';
import './index.less'
export default function TestPage() {
return (
<Card
title="组件作为子应用引入"
>
<MicroAppWithMemoHistory name="video" url="/video/alarmRecord" />
</Card>
)
}

View File

@ -0,0 +1,30 @@
/* eslint-disable */
import { request } from '@umijs/max';
export async function postUserInfo(options?: { [key: string]: any }) {
return request<USER_API.Result_UserInfo_>('/v1/ma/BusinessApi/GetUserInfo', {
method: 'POST',
...(options || {}),
});
}
// 获取菜单
export async function postMenuList(options?: { [key: string]: any }) {
return request<USER_API.Response>('/v1/ma/BusinessApi/GetAlgorithmsNav', {
method: 'POST',
data: {},
...(options || {}),
});
}
// 获取当前用户路由权限
export async function getUserRights(
params: { userId: string },
options?: { [key: string]: any },
) {
return request<USER_API.Response>('/v1/ma/BusinessApi/GetUserRights', {
method: 'POST',
data: params,
...(options || {}),
});
}

View File

@ -0,0 +1,5 @@
/* eslint-disable */
import * as UserController from './UserController';
export default UserController

55
src/service/user/typings.d.ts vendored Normal file
View File

@ -0,0 +1,55 @@
/* eslint-disable */
// 该文件由 OneAPI 自动生成,请勿手动修改!
declare namespace USER_API {
interface PageInfo {
current?: number;
pageSize?: number;
total?: number;
list?: Array<Record<string, any>>;
}
interface PageInfo_UserInfo_ {
current?: number;
pageSize?: number;
total?: number;
list?: Array<UserInfo>;
}
interface Result {
success?: boolean;
errorMessage?: string;
data?: Record<string, any>;
}
interface Result_PageInfo_UserInfo__ {
success?: boolean;
errorMessage?: string;
data?: PageInfo_UserInfo_;
}
interface Response {
code: number;
data: Data;
message: string;
[property: string]: any;
}
interface Data {
navValue: string;
[property: string]: any;
}
interface Result_UserInfo_ {
success?: boolean;
errorMessage?: string;
data?: UserInfo;
}
interface UserInfo {
username?: string;
userId?: string;
[property: string]: any;
}
}

View File

@ -1,6 +1,15 @@
{
"compilerOptions": {
"jsx": "react"
"jsx": "react",
"paths": {
"@src/*": ["./src/*"],
"@public/*": ["./public/*"],
"@/*": ["./src/*"],
"@components/*": ["./src/components/*"],
"@constants/*": ["./src/constants/*"],
"@common/*": ["./src/common/*"],
"@utils/*": ["./src/utils/*"],
},
},
"extends": "./src/.umi/tsconfig.json"
}