瀏覽代碼

页面框架-

zhouna 4 年之前
父節點
當前提交
c9fc90ed2d

+ 16 - 0
.idea/ai-admin.iml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+  <component name="TemplatesService">
+    <option name="TEMPLATE_FOLDERS">
+      <list>
+        <option value="$MODULE_DIR$/node_modules/workbox-build/src/templates" />
+      </list>
+    </option>
+  </component>
+</module>

+ 6 - 0
.idea/compiler.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <option name="DEFAULT_COMPILER" value="Eclipse" />
+  </component>
+</project>

+ 6 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -0,0 +1,6 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="Eslint" enabled="true" level="ERROR" enabled_by_default="true" />
+  </profile>
+</component>

+ 10 - 0
.idea/misc.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="JavaScriptSettings">
+    <option name="languageLevel" value="JSX" />
+  </component>
+  <component name="Kotlin2JsCompilerArguments">
+    <option name="sourceMapEmbedSources" />
+    <option name="sourceMapPrefix" />
+  </component>
+</project>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/ai-admin.iml" filepath="$PROJECT_DIR$/.idea/ai-admin.iml" />
+    </modules>
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="Git" />
+  </component>
+</project>

+ 44 - 0
craco.config.js

@@ -0,0 +1,44 @@
+/*******覆盖create-react-app默认配置******/
+
+const path = require('path');
+const resolve = dir => path.resolve(__dirname,dir);
+const CracoLessPlugin = require('craco-less');
+module.exports = {
+    webpack:{
+        alias:{
+            '@':resolve('src'),
+            '@common':resolve('src/common'),
+            '@components':resolve('src/components'),
+            '@utils':resolve('src/utils'),
+            '@image':resolve('src/images'),
+        }
+    },
+    plugins: [
+        {
+            plugin: CracoLessPlugin,
+            options: {
+                lessLoaderOptions: {
+                    lessOptions: {
+                        modifyVars: {
+                            '@primary-color': '#1690FF',
+                            '@theme-bg-color':'#fff',
+                            '@link-color': '#1690FF', // 链接色
+                            '@success-color': '#52c41a', // 成功色
+                            '@warning-color': '#faad14', // 警告色
+                            '@error-color': '#f5222d', // 错误色
+                            '@font-size-base': '14px', // 主字号
+                            '@heading-color': '#1690FF', // 标题色
+                            '@text-color': '#333', // 主文本色
+                            '@text-color-secondary': '#666', // 次文本色
+                            '@disabled-color': 'rgba(0, 0, 0, 0.25)', // 失效色
+                            '@border-radius-base': '2px', // 组件/浮层圆角
+                            '@border-color-base': '#d9d9d9', // 边框色
+                            '@box-shadow-base':'0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08),0 9px 28px 8px rgba(0, 0, 0, 0.05)',
+                        },
+                        javascriptEnabled: true,
+                    },
+                },
+            },
+        },
+    ],
+};

文件差異過大導致無法顯示
+ 15933 - 0
package-lock.json


+ 14 - 4
package.json

@@ -1,20 +1,30 @@
 {
-  "name": "antd-demo",
+  "name": "ai-admin",
   "version": "0.1.0",
   "private": true,
   "dependencies": {
+    "@craco/craco": "^6.2.0",
+    "@reduxjs/toolkit": "^1.6.1",
     "@testing-library/jest-dom": "^5.11.4",
     "@testing-library/react": "^11.1.0",
     "@testing-library/user-event": "^12.1.10",
+    "antd": "^4.16.10",
+    "craco-less": "^1.18.0",
     "react": "^17.0.2",
     "react-dom": "^17.0.2",
+    "react-redux": "^7.2.4",
+    "react-router": "^5.2.0",
     "react-scripts": "4.0.3",
+    "redux": "^4.1.1",
+    "redux-devtools": "^3.7.0",
+    "redux-devtools-extension": "^2.13.9",
+    "redux-thunk": "^2.3.0",
     "web-vitals": "^1.0.1"
   },
   "scripts": {
-    "start": "react-scripts start",
-    "build": "react-scripts build",
-    "test": "react-scripts test",
+    "dev": "craco start",
+    "build": "craco build",
+    "test": "craco test",
     "eject": "react-scripts eject"
   },
   "eslintConfig": {

+ 1 - 1
public/index.html

@@ -24,7 +24,7 @@
       work correctly both with client-side routing and a non-root public URL.
       Learn how to configure a non-root public URL by running `npm run build`.
     -->
-    <title>React App</title>
+    <title>AI质控权限系统</title>
   </head>
   <body>
     <noscript>You need to enable JavaScript to run this app.</noscript>

+ 0 - 38
src/App.css

@@ -1,38 +0,0 @@
-.App {
-  text-align: center;
-}
-
-.App-logo {
-  height: 40vmin;
-  pointer-events: none;
-}
-
-@media (prefers-reduced-motion: no-preference) {
-  .App-logo {
-    animation: App-logo-spin infinite 20s linear;
-  }
-}
-
-.App-header {
-  background-color: #282c34;
-  min-height: 100vh;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-  font-size: calc(10px + 2vmin);
-  color: white;
-}
-
-.App-link {
-  color: #61dafb;
-}
-
-@keyframes App-logo-spin {
-  from {
-    transform: rotate(0deg);
-  }
-  to {
-    transform: rotate(360deg);
-  }
-}

+ 7 - 21
src/App.js

@@ -1,25 +1,11 @@
-import logo from './logo.svg';
-import './App.css';
+import React from 'react';
+import './App.less';
+import PageLayout from '@components/PageLayout';
 
-function App() {
-  return (
+const App = () => (
     <div className="App">
-      <header className="App-header">
-        <img src={logo} className="App-logo" alt="logo" />
-        <p>
-          Edit <code>src/App.js</code> and save to reload.
-        </p>
-        <a
-          className="App-link"
-          href="https://reactjs.org"
-          target="_blank"
-          rel="noopener noreferrer"
-        >
-          Learn React
-        </a>
-      </header>
+        <PageLayout></PageLayout>
     </div>
-  );
-}
+);
 
-export default App;
+export default App;

+ 14 - 0
src/App.less

@@ -0,0 +1,14 @@
+@import '~antd/dist/antd.less';
+@import "@common/common.less";
+
+.page-header{
+  background: @primary-color;
+  height: @header-height;
+}
+.page-sider{
+  height: calc(100vh - @header-height);
+  background: #fff;
+}
+.page-content{
+  height: calc(100vh - @header-height);
+}

+ 4 - 0
src/common/common.less

@@ -0,0 +1,4 @@
+@bg-color:#fff;  /**主题背景色**/
+@header-height:50px;  /***Header高度**/
+@table-th-color:#F2F4F6;  /***表头背景色***/
+@active-bg:#DEF1FF;   /***下拉项选中背景色***/

+ 46 - 0
src/components/AHeader/index.js

@@ -0,0 +1,46 @@
+import {Dropdown ,Menu} from 'antd';
+import logo from '@image/logo.png';
+import msg from '@image/msg.png';
+import me from '@image/me.png';
+import down from '@image/down.png';
+import {Component} from "react";
+
+const propTypes = {
+
+}
+const defaultProps = {};
+class AHeader extends Component{
+    render() {
+        const menu = (
+            <Menu>
+                <Menu.Item key="0">
+                    <a href="https://www.antgroup.com">个人中心</a>
+                </Menu.Item>
+                <Menu.Divider/>
+                <Menu.Item key="3">退出</Menu.Item>
+            </Menu>
+        );
+        return (
+            <>
+                <img src={logo} alt=""/>
+                <span>AI病案质控平台</span>
+                <div className="infos">
+                    <span className='time'></span>
+                    <img src={msg} alt=""/>
+                    <div className="user">
+                        <img src={me} alt=""/>
+                        <Dropdown overlay={menu} trigger={['click']}>
+                            <a className="ant-dropdown-link" onClick={e => e.preventDefault()}>
+                                用户名 <img src={down} alt=""/>
+                            </a>
+                        </Dropdown>
+                    </div>
+                </div>
+            </>
+        )
+    }
+}
+
+AHeader.propTypes = propTypes;
+AHeader.defaultProps = defaultProps;
+export default AHeader;

+ 3 - 0
src/components/AHeader/index.less

@@ -0,0 +1,3 @@
+.infos{
+  float: right;
+}

+ 49 - 0
src/components/AMenu/index.js

@@ -0,0 +1,49 @@
+import {Menu} from 'antd';
+import {Component} from "react";
+import { useDispatch,useSelector } from 'react-redux'
+import { add } from '../../store/reducers/tabPanes'
+import OrgManager from "../OrgManager";
+import RoleManager from "../RoleManager";
+
+const { SubMenu } = Menu;
+const propTypes = {};
+const defaultProps = {};
+
+const pageMap = {
+    '组织管理':<OrgManager />,
+    '角色管理':<RoleManager />
+}
+
+function AMenu (){
+        const dispatch = useDispatch();
+        const activeTab = useSelector(state => {
+            return state.tabPanes.activeTab
+        });
+        function changeMenu(val){
+            console.log(val)
+            dispatch(
+                add({ title: val.key, content: pageMap[val.key]||<OrgManager />, key:val.key },)
+            )
+        }
+        return (
+            <Menu
+                defaultSelectedKeys={['组织管理']}
+                defaultOpenKeys={['权限管理']}
+                mode="inline"
+                onClick={changeMenu}
+            >
+                <SubMenu key="权限管理" title="权限管理">
+                    <Menu.Item key="组织管理">组织管理</Menu.Item>
+                    <Menu.Item key="角色管理">角色管理</Menu.Item>
+                    <Menu.Item key="用户管理">用户管理</Menu.Item>
+                    <Menu.Item key="数据管理">数据管理{activeTab}</Menu.Item>
+                </SubMenu>
+                <SubMenu key="系统管理" title="系统管理">
+                    <Menu.Item key="功能管理">功能管理</Menu.Item>
+                </SubMenu>
+            </Menu>
+        )
+}
+AMenu.propTypes = propTypes;
+AMenu.defaultProps = defaultProps;
+export default AMenu;

+ 41 - 0
src/components/ATabs/index.js

@@ -0,0 +1,41 @@
+import React, { Component } from 'react';
+import { Tabs } from 'antd';
+import { useDispatch,useSelector } from 'react-redux'
+import { active } from '../../store/reducers/tabPanes'
+
+const { TabPane } = Tabs;
+const propTypes = {
+
+}
+const defaultProps = {};
+function ATabs(){
+    const panes =useSelector(state => {
+        return state.tabPanes.panes
+    });;
+    const dispatch = useDispatch();
+    const activeTab = useSelector(state => {
+        console.log(22,state)
+        return state.tabPanes.activeTab
+    });
+    function onChange(activeKey){
+        dispatch(active(activeKey))
+    }
+    return (
+        <Tabs
+            hideAdd
+            onChange={onChange}
+            type="editable-card"
+            activeKey={activeTab}
+        >
+            {panes.map(pane => (
+                <TabPane tab={pane.title} key={pane.key}>
+                    {pane.content}
+                </TabPane>
+            ))}
+        </Tabs>
+    )
+}
+
+ATabs.propTypes = propTypes;
+ATabs.defaultProps = defaultProps;
+export default ATabs;

+ 8 - 0
src/components/OrgManager/index.js

@@ -0,0 +1,8 @@
+function OrgManager(){
+
+    return (
+        <div>组织管理</div>
+    )
+}
+
+export default OrgManager;

+ 35 - 0
src/components/PageLayout/index.js

@@ -0,0 +1,35 @@
+import { Layout, Menu } from 'antd';
+import AHeader from '../AHeader'
+import AMenu from '../AMenu'
+import ATabs from '../ATabs'
+import {Component} from "react";
+
+const { Header, Content, Sider } = Layout;
+const propTypes = {
+
+}
+const defaultProps = {};
+
+class PageLayout extends Component{
+    render() {
+        return (
+            <Layout>
+                <Header className='page-header'>
+                    <AHeader></AHeader>
+                </Header>
+                <Layout>
+                    <Sider className='page-sider'>
+                        <AMenu></AMenu>
+                    </Sider>
+                    <Content className='page-content'>
+                        <ATabs></ATabs>
+                    </Content>
+                </Layout>
+            </Layout>
+        )
+    }
+}
+
+PageLayout.propTypes = propTypes;
+PageLayout.defaultProps = defaultProps;
+export default PageLayout;

+ 8 - 0
src/components/RoleManager/index.js

@@ -0,0 +1,8 @@
+function RoleManager(){
+
+    return (
+        <div>角色管理</div>
+    )
+}
+
+export default RoleManager;

二進制
src/images/down.png


二進制
src/images/logo.png


二進制
src/images/me.png


二進制
src/images/msg.png


+ 19 - 13
src/index.js

@@ -1,17 +1,23 @@
 import React from 'react';
-import ReactDOM from 'react-dom';
-import './index.css';
+import { render } from 'react-dom'
+import './index.less';
 import App from './App';
-import reportWebVitals from './reportWebVitals';
+import { Provider } from 'react-redux'
+import configureStore from './store/reducerExtras/configureStore'
 
-ReactDOM.render(
-  <React.StrictMode>
-    <App />
-  </React.StrictMode>,
-  document.getElementById('root')
-);
+const store = configureStore();
+
+const renderApp = () =>
+    render(
+        <Provider store={store}>
+            <App />
+        </Provider>,
+        document.getElementById('root')
+    )
+
+if (process.env.NODE_ENV !== 'production' && module.hot) {
+    module.hot.accept('./App', renderApp)
+}
+
+renderApp();
 
-// If you want to start measuring performance in your app, pass a function
-// to log results (for example: reportWebVitals(console.log))
-// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
-reportWebVitals();

src/index.css → src/index.less


文件差異過大導致無法顯示
+ 0 - 1
src/logo.svg


+ 0 - 0
src/store/actions/user.js


+ 22 - 0
src/store/reducerExtras/configureStore.js

@@ -0,0 +1,22 @@
+import { applyMiddleware, compose, createStore } from 'redux'
+import thunkMiddleware from 'redux-thunk'
+
+import monitorReducersEnhancer from './monitorReducers'
+import loggerMiddleware from './logger'
+import rootReducer from '../reducers/index'
+//const rootReducer = require('../index').default
+export default function configureStore(preloadedState) {
+    const middlewares = [loggerMiddleware, thunkMiddleware]
+    const middlewareEnhancer = applyMiddleware(...middlewares)
+
+    const enhancers = [middlewareEnhancer, monitorReducersEnhancer]
+    const composedEnhancers = compose(...enhancers)
+
+    const store = createStore(rootReducer, preloadedState, composedEnhancers)
+
+    if (process.env.NODE_ENV !== 'production' && module.hot) {
+        module.hot.accept('../reducers/index', () => store.replaceReducer(rootReducer))
+    }
+
+    return store
+}

+ 10 - 0
src/store/reducerExtras/logger.js

@@ -0,0 +1,10 @@
+const logger = store => next => action => {
+    console.group(action.type)
+    console.info('dispatching', action)
+    let result = next(action)
+    console.log('next state', store.getState())
+    console.groupEnd()
+    return result
+}
+
+export default logger

+ 19 - 0
src/store/reducerExtras/monitorReducers.js

@@ -0,0 +1,19 @@
+const round = number => Math.round(number * 100) / 100
+
+const monitorReducerEnhancer =
+    createStore => (reducer, initialState, enhancer) => {
+        const monitoredReducer = (state, action) => {
+            const start = performance.now()
+            const newState = reducer(state, action)
+            const end = performance.now()
+            const diff = round(end - start)
+
+            console.log('reducer process time:', diff)
+
+            return newState
+        };
+
+        return createStore(monitoredReducer, initialState, enhancer)
+    }
+
+export default monitorReducerEnhancer

+ 8 - 0
src/store/reducers/index.js

@@ -0,0 +1,8 @@
+import { combineReducers } from 'redux';
+import tabPanes from './tabPanes';
+
+const rootReducer = combineReducers({
+    tabPanes
+});
+
+export default rootReducer;

+ 27 - 0
src/store/reducers/tabPanes.js

@@ -0,0 +1,27 @@
+import { createSlice } from '@reduxjs/toolkit';
+
+export const slice = createSlice({
+    name: 'tabPanes',
+    initialState: {
+        activeTab: '',
+        panes:[{title:'111',content:'111',key:'111'}]
+    },
+    reducers: {
+        close: (state,action) => {          //关闭tab
+            state.activeTab = action.activeTab||'';
+            state.panes.slice(action.index,1);
+        },
+        add: (state,action) => {        //打开新tab
+            console.log(33,action)
+            state.panes.push(action.payload);
+            state.activeTab = action.payload.key;
+        },
+        active:(state,action) => {   console.log(action)       //切换tab
+            state.activeTab = action.payload;
+        },
+    },
+});
+
+export const { close, active, add} = slice.actions;
+
+export default slice.reducer;

+ 20 - 0
src/store/reducers/userSlice.js

@@ -0,0 +1,20 @@
+import { createSlice } from '@reduxjs/toolkit';
+
+export const slice = createSlice({
+    name: 'user',
+    initialState: {
+        userName: '',
+    },
+    reducers: {
+        login: state => {
+            state.userName = '用户1';
+        },
+        loginOut: state => {
+            state.userName = '';
+        },
+    },
+});
+
+export const { login, loginOut} = slice.actions;
+
+export default slice.reducer;