Merge branch 'develop' of https://github.com/opengoofy/hippo4j into develop

pull/1470/head
MZR 2 years ago
commit ce69c6667a

12
node_modules/.yarn-integrity generated vendored

@ -0,0 +1,12 @@
{
"systemParams": "darwin-arm64-93",
"modulesFolders": [
"node_modules"
],
"flags": [],
"linkedModules": [],
"topLevelPatterns": [],
"lockfileEntries": {},
"files": [],
"artifacts": {}
}

@ -26,5 +26,7 @@ module.exports = {
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-non-null-assertion': 0,
'@typescript-eslint/no-var-requires': 0,
'import/no-anonymous-default-export': 0,
'jsx-a11y/anchor-is-valid': 0,
},
};

@ -1,3 +1,4 @@
/.git
node_modules
build
src/lib/*

@ -1,4 +1,3 @@
// craco.config.js
const CracoLessPlugin = require('craco-less');
const lessModuleRegex = /\.module\.less$/;
const path = require('path');
@ -33,20 +32,29 @@ module.exports = {
},
},
],
// style: {
// modules: {
// localIdentName: '[local]_[hash:base64:5]', // 可以自定义你的类名生成规则
// },
// },
webpack: {
alias: {
'@': resolve('src'),
},
},
devServer: {
port: 3001,
port: 3000,
headers: {
'Access-Control-Allow-Origin': '*',
},
proxy: {
'/hippo4j/v1/cs': {
target: 'http://console.hippo4j.cn:6691/hippo4j/v1/cs',
pathRewrite: { '^/hippo4j/v1/cs': '' },
changeOrigin: true,
secure: false,
onProxyReq: proxyReq => {
console.log(`Proxying request to: ${proxyReq.path}`);
},
onProxyRes: proxyRes => {
console.log(`Received response with status: ${proxyRes.statusCode}`);
},
},
},
},
};

@ -5,14 +5,17 @@
"dependencies": {
"@ahooksjs/use-url-state": "^3.5.1",
"@ant-design/icons": "^5.2.6",
"@tanem/react-nprogress": "^5.0.51",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"ahooks": "^3.7.8",
"antd": "^5.4.7",
"classnames": "^2.3.2",
"dayjs": "^1.11.9",
"i18next": "^23.5.1",
"i18next-browser-languagedetector": "^7.1.0",
"lodash": "^4.17.21",
"qs": "^6.11.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
@ -50,6 +53,7 @@
"@craco/craco": "^7.1.0",
"@types/http-errors": "^2.0.1",
"@types/jest": "^27.5.2",
"@types/lodash": "^4.14.198",
"@types/node": "^16.18.26",
"@types/react": "^18.2.6",
"@types/react-dom": "^18.2.4",
@ -66,6 +70,7 @@
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.2",
"http-proxy-middleware": "^2.0.6",
"husky": "^8.0.0",
"less-loader": "^11.1.0",
"lint-staged": "^13.2.2",

@ -1,8 +1,6 @@
import LayoutCom from './components/layout-com';
import { Routes, Route, Link } from 'react-router-dom';
import routeList from './route';
import Login from '@/page/login';
import { MenuProps } from 'antd';
import { useTran } from './hooks';
import { STR_MAP } from './config/i18n/locales/constants';
@ -23,9 +21,8 @@ const App = () => {
];
return (
<LayoutCom sideMenuList={sideMenuList} isSider={true} isHeader={true}>
<LayoutCom sideMenuList={sideMenuList}>
<Routes>
<Route path="/Login" Component={Login}></Route>
{routeList.map(item => (
<Route key={item.path} path={item.path} Component={item.component} />
))}

@ -5,7 +5,7 @@
.logo {
display: flex;
flex-direction: column;
width: 200px;
width: 50px;
img {
flex: 1;
object-fit: contain;

@ -2,13 +2,16 @@ import React, { useContext } from 'react';
import style from './index.module.less';
import { UserOutlined } from '@ant-design/icons';
import { Avatar, Button, Col, Dropdown, Row, Switch } from 'antd';
import { useThemeMode } from '@/hooks';
import { MyContext } from '@/context';
import IconFont from '@/components/icon';
import { LANG_NAME, MyStoreValues, THEME_NAME } from '@/typings';
import { useNavigate } from 'react-router-dom';
const HeaderChild = () => {
const { isDark, setIsDark } = useThemeMode();
const { lang, setLang } = useContext<any>(MyContext);
const { lang, themeName, setLang, setThemeName } = useContext<MyStoreValues>(MyContext);
const navigate = useNavigate();
// console.log('setLang:::', setLang);
// setLang && setLang(LANG_NAME.EN);
const items = [
{
@ -29,18 +32,14 @@ const HeaderChild = () => {
},
{
key: '3',
label: (
<a target="_blank" rel="noopener noreferrer" href="https://www.luohanacademy.com">
</a>
),
label: <a onClick={() => navigate('/login')}></a>,
},
];
return (
<div className={style['header-wrapper']}>
<div className={style['logo']}>
<img src="https://demo.knowstreaming.com/layout/assets/image/ks-logo.png" alt="" />
<div className={style['logo']} onClick={() => navigate('/home')}>
<img src="https://nageoffer.com/img/logo3.png" alt="" />
</div>
<div className={style['edit-container']}>
<Row gutter={[16, 16]}>
@ -51,18 +50,10 @@ const HeaderChild = () => {
</Dropdown>
</Col>
<Col>
{/* <Tag
onClick={() => {
lang === 'zh' ? setLang('en') : setLang('zh');
}}
style={{ cursor: 'pointer' }}
>
{lang === 'zh' ? 'zh' : 'en'}
</Tag> */}
<Button
type="link"
onClick={() => {
lang === 'zh' ? setLang('en') : setLang('zh');
lang === LANG_NAME.EN ? setLang && setLang(LANG_NAME.ZH) : setLang && setLang(LANG_NAME.EN);
}}
>
<IconFont type="icon-qiehuanyuyan"></IconFont>
@ -72,9 +63,9 @@ const HeaderChild = () => {
<Switch
checkedChildren={'🌞'}
unCheckedChildren={'🌛'}
defaultChecked={isDark}
defaultChecked={themeName === THEME_NAME.DARK}
onChange={e => {
setIsDark(e);
setThemeName && setThemeName(e ? THEME_NAME.DARK : THEME_NAME.DEFAULT);
}}
></Switch>
</Col>

@ -12,10 +12,14 @@
padding-top: 24px;
}
.content {
margin: 10px 10px 0px;
border-radius: 12px 12px 0 0;
flex: 1;
padding: 16px;
overflow-y: auto;
}
.pureContent {
border-radius: unset;
padding: 0;
}
}

@ -1,10 +1,10 @@
import { useState, useContext, ReactNode, useEffect } from 'react';
import { useState, useContext, ReactNode, useEffect, useMemo } from 'react';
import { DefaultTheme, ThemeContext } from 'styled-components';
import { Layout, Menu, MenuProps } from 'antd';
import HeaderChild from '../header';
import style from './index.module.less';
import { useLocation } from 'react-router-dom';
import { useThemeMode } from '@/hooks';
import classNames from 'classnames';
type MenuItem = Required<MenuProps>['items'][number];
const { Header, Sider, Content } = Layout;
@ -12,14 +12,11 @@ const { Header, Sider, Content } = Layout;
interface ILayoutCom {
children?: ReactNode;
sideMenuList: MenuItem[];
isSider?: boolean;
isHeader?: boolean;
}
const LayoutCom = (props: ILayoutCom) => {
const { sideMenuList, children, isSider = true, isHeader = true } = props;
const { sideMenuList, children } = props;
const myThemes: DefaultTheme = useContext<any>(ThemeContext);
const [currentKey, setCurrentKey] = useState<string>('');
const { isDark } = useThemeMode();
const location = useLocation();
useEffect(() => {
@ -32,7 +29,17 @@ const LayoutCom = (props: ILayoutCom) => {
useEffect(() => {
document.body.style.backgroundColor = myThemes.backgroundColor.bg1;
}, [isDark, myThemes]);
}, [myThemes]);
const isHeader = useMemo(() => {
const isHeader = location.pathname !== '/login';
return isHeader;
}, [location]);
const isSider = useMemo(() => {
const isSider = location.pathname !== '/login';
return isSider;
}, [location]);
return (
<main className={style.container} style={{ backgroundColor: myThemes.backgroundColor.bg1 }}>
@ -42,7 +49,11 @@ const LayoutCom = (props: ILayoutCom) => {
</Header>
)}
<Layout
style={{ backgroundColor: myThemes.backgroundColor.bg1, height: `calc(100vh - ${isHeader ? '64px' : 0})` }}
style={{
backgroundColor: myThemes.backgroundColor.bg1,
height: `calc(100vh - ${isHeader ? '64px' : '0px'})`,
margin: isHeader ? '10px 10px 0px' : '0px',
}}
>
{isSider && (
<Sider className={style.sider} style={{ backgroundColor: myThemes.backgroundColor.bg1 }} collapsible>
@ -50,7 +61,9 @@ const LayoutCom = (props: ILayoutCom) => {
</Sider>
)}
<Content
className={style.content}
className={classNames(style.content, {
[style.pureContent]: location.pathname === '/login',
})}
style={{
backgroundColor: myThemes.backgroundColor.bgContent,
height: `calc(100vh - ${isHeader ? '64px' : 0})`,

@ -1,12 +1,12 @@
import React, { useContext, useEffect, useState } from 'react';
import { DefaultTheme, ThemeProvider } from 'styled-components';
import { ConfigProvider, theme } from 'antd';
import { darkAlgorithm } from '../../config/theme/dark-algorithm';
import { defaultAlgorithm } from '../../config/theme/default-algnorithm';
import { lightDefaultTheme, darkDefaultTheme } from '../../config/theme';
import { MyContext, THEME_NAME } from '../../context';
import { MyContext } from '../../context';
import zhCN from 'antd/es/locale/zh_CN';
import { THEME_NAME } from '@/typings';
interface ThemeProps {
children: React.ReactNode;

@ -18,7 +18,7 @@ i18n
translation: en,
},
},
debug: true,
// debug: true,
fallbackLng: 'zh', // 默认语言
interpolation: {
escapeValue: false, // 不转义HTML标签

@ -1,7 +1,7 @@
import { DefaultTheme } from 'styled-components';
export const lightDefaultTheme: DefaultTheme = {
primary: '#0d68a8',
primary: '#1890ff',
baseColor: {
// 前两个是固定的,用于,有颜色按钮 字体颜色等固定不会变的颜色值
bc1: '#fff',

@ -7,31 +7,23 @@ import { darkDefaultTheme, lightDefaultTheme } from '@/config/theme';
import { defaultAlgorithm } from '@/config/theme/default-algnorithm';
import { darkAlgorithm } from '@/config/theme/dark-algorithm';
import { useTranslation } from 'react-i18next';
import { useLocalStorageState } from 'ahooks';
import { LANG_NAME, MyStoreValues, THEME_NAME } from '@/typings';
export enum THEME_NAME {
DEFAULT = 'default',
DARK = 'dark',
}
export enum LANG_NAME {
ZH = 'zh',
EN = 'en',
}
export const MyContext = createContext<{
themeName: string;
lang: LANG_NAME;
setThemeName: (name: THEME_NAME) => void;
setLang: (lang: LANG_NAME) => void;
} | null>(null);
export const MyContext = createContext<MyStoreValues>({});
export const MyStore: React.FC<{
children: ReactNode;
}> = ({ children }) => {
const [themeName, setThemeName] = useState<THEME_NAME>(THEME_NAME.DEFAULT);
const [lang, setLang] = useState<LANG_NAME>(LANG_NAME.ZH);
const [themeName, setThemeName] = useLocalStorageState<THEME_NAME>('current-mode', {
defaultValue: THEME_NAME.DEFAULT,
});
const [lang, setLang] = useLocalStorageState<LANG_NAME>('current-lang', {
defaultValue: LANG_NAME.ZH,
});
const [themes, setThemes] = useState(defaultAlgorithm);
const [myThemes, setMyThemes] = useState<DefaultTheme>(lightDefaultTheme);
const { i18n } = useTranslation();
const changeMode = (themeName: THEME_NAME) => {
@ -49,11 +41,10 @@ export const MyStore: React.FC<{
};
useEffect(() => {
changeMode(themeName);
changeMode(themeName as THEME_NAME);
}, [themeName]);
useEffect(() => {
// change lang
i18n.changeLanguage(lang);
}, [lang, i18n]);

@ -1,3 +1,2 @@
export * from './useThemeMode';
export * from './useTransLate';
export * from './useFormToUrl';

@ -1,14 +0,0 @@
import { useContext, useEffect } from 'react';
import { useLocalStorageState } from 'ahooks';
import { MyContext, THEME_NAME } from '@/context';
export const useThemeMode = (): { isDark: boolean | undefined; setIsDark: (isDark: boolean) => void } => {
const [isDark, setIsDark] = useLocalStorageState<boolean>('current-mode', { defaultValue: false });
const { setThemeName } = useContext<any>(MyContext);
useEffect(() => {
isDark ? setThemeName(THEME_NAME.DARK) : setThemeName(THEME_NAME.DEFAULT);
}, [isDark, setThemeName]);
return { isDark, setIsDark };
};

@ -0,0 +1,18 @@
import useUrlState from '@ahooksjs/use-url-state';
export const useUrlSet = (options: { form: any }) => {
const { form } = options;
const [state, setState] = useUrlState({});
const setUrl = () => {
const params = form.getFieldsValue();
Object.keys(params).forEach(key => {
if (!params[key]) {
params[key] = undefined;
}
});
setState({ ...params });
};
return { setUrl };
};

@ -1,16 +1,9 @@
import { Button, Calendar } from 'antd';
import dayjs from 'dayjs';
import request from '@/utils';
import { useTranslation } from 'react-i18next';
const Home = () => {
const { t } = useTranslation();
const fetchdata = (body: { duid: string }) => {
return request<{ phone: string }>('https://mock.xiaojukeji.com/mock/16635/am/marketing/mis/member/archive/phone', {
method: 'post',
body,
});
};
return (
<div style={{ color: 'red' }}>

@ -0,0 +1,5 @@
.tenant_wrapper {
.opreate_btn {
padding: 0px;
}
}

@ -0,0 +1,120 @@
import { useAntdTable } from 'ahooks';
import { Button, Form, Input, Row, Space, Table, Col } from 'antd';
import { SearchOutlined, EditOutlined } from '@ant-design/icons';
import React, { useState } from 'react';
import { fetchItemList } from './service';
import { useUrlSet } from '@/hooks/useUrlSet';
import style from './index.module.less';
const baseColumns = [
{
title: '序号',
dataIndex: 'index',
},
{
title: '租户',
dataIndex: 'tenantId',
},
{
title: '项目名称',
dataIndex: 'itemName',
},
{
title: '负责人',
dataIndex: 'owner',
},
{
title: '修改时间',
dataIndex: 'gmtModified',
},
];
const Tenant: React.FC = () => {
const [editVisible, setEditVisible] = useState(false);
const [type, setType] = useState('add');
const [form] = Form.useForm();
const { setUrl } = useUrlSet({ form });
const { tableProps, search } = useAntdTable(fetchItemList, { form });
// const {run: delete} = useRequest(fetchDeleteTenant, { manual: true });
const actions = (type: string, item?: any) => {
switch (type) {
case 'add':
setEditVisible(true);
break;
case 'edit':
setEditVisible(true);
break;
case 'delete':
// handleDelete();
break;
default:
break;
}
};
const handleSearch = () => {
setUrl();
search.submit();
};
// const handleDelete = (item: any) => {
// Modal.confirm({
// title: `此操作将删除${item.tenantName}, 是否继续?`,
// onOk: () => {
// search.submit();
// },
// });
// };
return (
<div className={style.tenant_wrapper}>
<Form form={form} wrapperCol={{ span: 23 }}>
<Row>
<Col span={6}>
<Form.Item name="note">
<Input placeholder="项目" />
</Form.Item>
</Col>
<Col span={18}>
<Space>
<Button onClick={() => handleSearch()} type="primary" icon={<SearchOutlined />}>
</Button>
<Button onClick={() => setEditVisible(true)} type="primary" icon={<EditOutlined />}>
</Button>
</Space>
</Col>
</Row>
<Row>
<Col span={6}></Col>
<Col span={18}></Col>
</Row>
</Form>
<Table
{...tableProps}
bordered
rowKey="index"
columns={[
...baseColumns,
{
title: '操作',
key: 'action',
render: (text: string, record: any) => {
return (
<Space>
<Button onClick={() => actions('edit', record)} type="link" className={style.opreate_btn}>
</Button>
<Button onClick={() => actions('edit', record)} type="link" className={style.opreate_btn}>
</Button>
</Space>
);
},
},
]}
/>
</div>
);
};
export default Tenant;

@ -0,0 +1,8 @@
import { lazy } from 'react';
import { IRouterList } from '@/typings';
const ItemManage = lazy(() => import('./index'));
const routerList: IRouterList[] = [{ path: '/item', component: () => <ItemManage /> }];
export default routerList;

@ -0,0 +1,75 @@
import request from '@/utils';
const fetchItemList = async (
pageProps: { current: number; pageSize: number },
formData: { tencent: string | number }
): Promise<{ total: number; list: Array<any> }> => {
const res: any = await request('/hippo4j/v1/cs/item/query/page', {
method: 'POST',
headers: {
Authorization:
'Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiI3LGJhb3hpbnlpX2FkbWluIiwiaXNzIjoiYWRtaW4iLCJleHAiOjE2OTUzOTg4NDksImlhdCI6MTY5NDc5NDA0OSwicm9sIjoiUk9MRV9BRE1JTiJ9.syRDshKpd-xETsSdeMPRtk956f4BJkPt4utVsUl4smgH71Woj8SUq4w2RX1YtGTC4aTZRJYdKOfkTqwK0g_dHQ',
cookie:
'Admin-Token=Bearer%20eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiI3LGJhb3hpbnlpX2FkbWluIiwiaXNzIjoiYWRtaW4iLCJleHAiOjE2OTUzOTg4NDksImlhdCI6MTY5NDc5NDA0OSwicm9sIjoiUk9MRV9BRE1JTiJ9.syRDshKpd-xETsSdeMPRtk956f4BJkPt4utVsUl4smgH71Woj8SUq4w2RX1YtGTC4aTZRJYdKOfkTqwK0g_dHQ; userName=baoxinyi_admin',
},
body: {
...formData,
current: pageProps.current,
size: pageProps.pageSize,
desc: true,
},
});
if (res && res.success) {
return {
total: res.data.total,
list: res.data.records.map((item: any, index: number) => ({ index: index + 1, ...item })),
};
}
throw new Error(res.msg || '服务器开小差啦~');
};
const fetchAddTenant = async (params: {
itemDesc: string; // 项目简介
itemId: string; // 项目
itemName: string; // 项目名称
owner: string; // 负责人
tenantId: string; // 租户
tenantDesc?: string;
tenantName?: string;
}) => {
const res = await request('/hippo4j/v1/cs/tenant/save', {
method: 'POST',
body: { ...params },
});
if (res && res.success) {
return res;
}
throw new Error(res.msg || '服务器开小差啦~');
};
const fetchDeleteItem = async (id: string) => {
const url = 'hippo4j/v1/cs/item/delete/prescription/' + id;
const res = await request(url, {
method: 'DELETE',
});
if (res && res.success) {
return res;
}
throw new Error(res.msg || '服务器开小差啦~');
};
const fetchUpdateItem = async (id: string) => {
const res = await request('/hippo4j/v1/cs/item/update', {
method: 'POST',
params: { id },
});
if (res && res.success) {
return res;
}
throw new Error(res.msg || '服务器开小差啦~');
};
export { fetchItemList, fetchAddTenant, fetchDeleteItem, fetchUpdateItem };

@ -0,0 +1,5 @@
.tenant_wrapper {
.opreate_btn {
padding: 0px;
}
}

@ -0,0 +1,120 @@
import { useAntdTable } from 'ahooks';
import { Button, Form, Input, Row, Space, Table, Col, Modal } from 'antd';
import { SearchOutlined, EditOutlined } from '@ant-design/icons';
import React, { useState } from 'react';
import { fetchTenantList } from './service';
import { useUrlSet } from '@/hooks/useUrlSet';
import style from './index.module.less';
const baseColumns = [
{
title: '序号',
dataIndex: 'id',
},
{
title: '租户',
dataIndex: 'tenantId',
},
{
title: '租户名称',
dataIndex: 'tenantName',
},
{
title: '负责人',
dataIndex: 'owner',
},
{
title: '修改时间',
dataIndex: 'gmtModified',
},
];
const Tenant: React.FC = () => {
const [editVisible, setEditVisible] = useState(false);
const [type, setType] = useState('add');
const [form] = Form.useForm();
const { setUrl } = useUrlSet({ form });
const { tableProps, search } = useAntdTable(fetchTenantList, { form });
// const {run: delete} = useRequest(fetchDeleteTenant, { manual: true });
const actions = (type: string, item?: any) => {
switch (type) {
case 'add':
setEditVisible(true);
break;
case 'edit':
setEditVisible(true);
break;
case 'delete':
// handleDelete();
break;
default:
break;
}
};
const handleSearch = () => {
setUrl();
search.submit();
};
// const handleDelete = (item: any) => {
// Modal.confirm({
// title: `此操作将删除${item.tenantName}, 是否继续?`,
// onOk: () => {
// search.submit();
// },
// });
// };
return (
<div className={style.tenant_wrapper}>
<Form form={form} wrapperCol={{ span: 23 }}>
<Row>
<Col span={6}>
<Form.Item name="note">
<Input placeholder="租户" />
</Form.Item>
</Col>
<Col span={18}>
<Space>
<Button onClick={() => handleSearch()} type="primary" icon={<SearchOutlined />}>
</Button>
<Button onClick={() => setEditVisible(true)} type="primary" icon={<EditOutlined />}>
</Button>
</Space>
</Col>
</Row>
<Row>
<Col span={6}></Col>
<Col span={18}></Col>
</Row>
</Form>
<Table
{...tableProps}
bordered
rowKey="id"
columns={[
...baseColumns,
{
title: '操作',
key: 'action',
render: (text: string, record: any) => {
return (
<Space>
<Button onClick={() => actions('edit', record)} type="link" className={style.opreate_btn}>
</Button>
<Button onClick={() => actions('edit', record)} type="link" className={style.opreate_btn}>
</Button>
</Space>
);
},
},
]}
/>
</div>
);
};
export default Tenant;

@ -0,0 +1,8 @@
import { lazy } from 'react';
import { IRouterList } from '@/typings';
const LogManage = lazy(() => import('./index'));
const routerList: IRouterList[] = [{ path: '/log', component: () => <LogManage /> }];
export default routerList;

@ -0,0 +1,79 @@
import request from '@/utils';
const fetchTenantList = async (
pageProps: { current: number; pageSize: number },
formData: { tencent: string | number }
): Promise<{ total: number; list: Array<any> }> => {
const res: any = await request('/hippo4j/v1/cs/tenant/query/page', {
method: 'POST',
headers: {
Authorization:
'Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiI3LGJhb3hpbnlpX2FkbWluIiwiaXNzIjoiYWRtaW4iLCJleHAiOjE2OTUzOTg4NDksImlhdCI6MTY5NDc5NDA0OSwicm9sIjoiUk9MRV9BRE1JTiJ9.syRDshKpd-xETsSdeMPRtk956f4BJkPt4utVsUl4smgH71Woj8SUq4w2RX1YtGTC4aTZRJYdKOfkTqwK0g_dHQ',
cookie:
'Admin-Token=Bearer%20eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiI3LGJhb3hpbnlpX2FkbWluIiwiaXNzIjoiYWRtaW4iLCJleHAiOjE2OTUzOTg4NDksImlhdCI6MTY5NDc5NDA0OSwicm9sIjoiUk9MRV9BRE1JTiJ9.syRDshKpd-xETsSdeMPRtk956f4BJkPt4utVsUl4smgH71Woj8SUq4w2RX1YtGTC4aTZRJYdKOfkTqwK0g_dHQ; userName=baoxinyi_admin',
},
body: {
...formData,
current: pageProps.current,
size: pageProps.pageSize,
desc: true,
},
});
if (res && res.success) {
return {
total: res.data.total,
list: res.data.records,
};
}
throw new Error(res.msg || '服务器开小差啦~');
};
const fetchAddTenant = async (id: string) => {
const res = await request('/hippo4j/v1/cs/tenant/save', {
method: 'POST',
params: { id },
});
if (res && res.success) {
return res;
}
throw new Error(res.msg || '服务器开小差啦~');
};
const fetchDeleteTenant = async (id: string) => {
const res = await request('/tenants', {
method: 'POST',
params: { id },
});
if (res && res.success) {
return res;
}
throw new Error(res.msg || '服务器开小差啦~');
};
const fetchUpdateTenant = async (id: string) => {
const res = await request('hippo4j/v1/cs/tenant/update', {
method: 'POST',
params: { id },
});
if (res && res.success) {
return res;
}
throw new Error(res.msg || '服务器开小差啦~');
};
const fetchTenantDetail = async (id: string) => {
const res = await request('/tenants', {
method: 'POST',
params: { id },
});
if (res && res.success) {
return res;
}
throw new Error(res.msg || '服务器开小差啦~');
};
export { fetchTenantList, fetchAddTenant, fetchDeleteTenant, fetchUpdateTenant, fetchTenantDetail };

@ -0,0 +1,37 @@
.login-wrapper {
display: grid;
grid-template-columns: 1fr 550px;
grid-template-rows: 1fr;
height: 100%;
.login-bgi {
background: url('https://gw.alipayobjects.com/zos/rmsportal/FfdJeJRQWjEeGTpqgBKj.png') no-repeat fixed center center;
background-size: contain;
}
.login-form-wrapper {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.img-wrapper {
width: 50px;
display: flex;
flex-direction: column;
img {
flex: 1;
object-fit: contain;
}
}
.tip {
margin-block-start: 12px;
margin-block-end: 36px;
}
.form-content {
width: 330px;
.login-edit {
display: flex;
justify-content: space-between;
align-items: center;
}
}
}
}

@ -1,6 +1,143 @@
import React from 'react';
import { useCallback, useMemo, useState } from 'react';
import { Typography, Tabs, TabsProps, Form, Input, Checkbox, Button, message } from 'antd';
import service from './service';
import { LockOutlined, UserOutlined } from '@ant-design/icons';
import style from './index.module.less';
import { useRequest } from 'ahooks';
import { setToken } from '@/utils';
import { useNavigate } from 'react-router-dom';
const { Paragraph } = Typography;
enum TABS_KEY {
LOGIN = 'login',
PHONE = 'phoneLogin',
}
const Login = () => {
return <></>;
const [form] = Form.useForm();
const navigate = useNavigate();
const { validateFields } = form;
const [remenberMe, setRemenberMe] = useState(0);
const { run, loading } = useRequest(service.fetchLogin, {
manual: true,
onSuccess: res => {
if (res) {
message.success('登陆成功');
navigate('/thread-poll/index');
setToken(res?.data);
}
},
});
const handleLogin = useCallback(() => {
validateFields()
.then(values => {
console.log('value:::', values, remenberMe);
run({
password: '1BsL68bUgS52alKirqFprU1QfWJyPFlb3dA2AzEMc6kMTpTHN1doEN4=',
rememberMe: 1,
tag: 'lw4xNmj6QuamOFsy',
username: 'baoxinyi_user',
});
})
.catch(err => console.log('err:::', err));
}, [remenberMe, validateFields, run]);
const formNode = useMemo(
() => (
<Form form={form}>
<Form.Item
name="username"
initialValue={'baoxinyi_user'}
rules={[
{
required: true,
message: '请输入用户名!',
},
]}
>
<Input
placeholder="用户名"
prefix={<UserOutlined className={'prefixIcon'} />}
size="large"
allowClear
></Input>
</Form.Item>
<Form.Item
name="password"
initialValue={'baoxinyi_user'}
rules={[
{
required: true,
message: '请输入密码!',
},
]}
>
<Input.Password
placeholder="密码"
prefix={<LockOutlined className={'prefixIcon'} />}
size="large"
allowClear
></Input.Password>
</Form.Item>
<Form.Item name="rememberMe">
<div className={style['login-edit']}>
<Checkbox
value={1}
checked
onChange={e => {
setRemenberMe(e.target.checked ? 1 : 0);
}}
>
</Checkbox>
<Button type="link"></Button>
</div>
</Form.Item>
<Form.Item>
<Button
htmlType="submit"
type="primary"
style={{ width: '100%' }}
size="large"
onClick={handleLogin}
loading={loading}
>
</Button>
</Form.Item>
</Form>
),
[form, loading, handleLogin]
);
const items: TabsProps['items'] = [
{
key: TABS_KEY.LOGIN,
label: '账号密码登陆',
children: formNode,
},
{
key: TABS_KEY.PHONE,
label: '手机号登陆',
children: formNode,
},
];
return (
<div className={style['login-wrapper']}>
<div className={style['login-bgi']}></div>
<div className={style['login-form-wrapper']}>
<div className={style['img-wrapper']}>
<img src="https://nageoffer.com/img/logo3.png" alt="" />
</div>
<Paragraph className={style['tip']}>线</Paragraph>
<div className={style['form-content']}>
<Tabs centered defaultActiveKey={TABS_KEY.LOGIN} items={items} />
</div>
</div>
</div>
);
};
export default Login;

@ -0,0 +1,6 @@
import { IRouterList } from '@/typings';
import Login from '.';
const routerList: IRouterList[] = [{ path: '/login', component: Login }];
export default routerList;

@ -0,0 +1,13 @@
import request from '@/utils';
const fetchLogin = async (body: any) => {
const { data } = await request<{ data: string; roles: string[] }>('/hippo4j/v1/cs/auth/login', {
method: 'POST',
body,
});
return data;
};
export default {
fetchLogin,
};

@ -0,0 +1,5 @@
.tenant_wrapper {
.opreate_btn {
padding: 0px;
}
}

@ -1,16 +1,20 @@
import { useAntdTable } from 'ahooks';
import { Button, Form, Input, Row, Space, Table, Col } from 'antd';
import React, { useState } from 'react';
import { useAntdTable } from 'ahooks';
import { Button, Form, Input, Row, Space, Table, Col, Modal } from 'antd';
import { SearchOutlined, EditOutlined } from '@ant-design/icons';
import { useUrlSet } from '@/hooks/useUrlSet';
import { fetchTenantList } from './service';
import style from './index.module.less';
const baseColumns = [
{
title: '序号',
dataIndex: 'num',
dataIndex: 'id',
},
{
title: '租户',
dataIndex: 'tenant',
dataIndex: 'tenantId',
},
{
title: '租户名称',
@ -18,53 +22,78 @@ const baseColumns = [
},
{
title: '负责人',
dataIndex: 'creator',
dataIndex: 'owner',
},
{
title: '修改时间',
dataIndex: 'data',
dataIndex: 'gmtModified',
},
];
const Tenant: React.FC = () => {
const [editVisible, setEditVisible] = useState(false);
const [type, setType] = useState('add');
const [form] = Form.useForm();
const { setUrl } = useUrlSet({ form });
const { tableProps, search } = useAntdTable(fetchTenantList, { form });
const actions = (type: string) => {
// const {run: delete} = useRequest(fetchDeleteTenant, { manual: true });
const actions = (type: string, item?: any) => {
switch (type) {
case 'create':
case 'add':
setEditVisible(true);
break;
case 'edit':
setEditVisible(true);
break;
case 'delete':
// handleDelete();
break;
default:
break;
}
};
const handleSearch = () => {
setUrl();
search.submit();
};
// const handleDelete = (item: any) => {
// Modal.confirm({
// title: `此操作将删除${item.tenantName}, 是否继续?`,
// onOk: () => {
// search.submit();
// },
// });
// };
return (
<div>
<Form>
<div className={style.tenant_wrapper}>
<Form form={form} wrapperCol={{ span: 23 }}>
<Row>
<Col span={6}>
<Form.Item name="note" rules={[{ required: true }]}>
<Form.Item name="note">
<Input placeholder="租户" />
</Form.Item>
</Col>
<Col span={18}>
<Space>
<Button onClick={() => search.submit()}></Button>
<Button onClick={() => setEditVisible(true)}></Button>
<Button onClick={() => handleSearch()} type="primary" icon={<SearchOutlined />}>
</Button>
<Button onClick={() => setEditVisible(true)} type="primary" icon={<EditOutlined />}>
</Button>
</Space>
</Col>
</Row>
<Row>
<Col span={6}></Col>
<Col span={18}></Col>
</Row>
</Form>
<Table
{...tableProps}
rowKey="num"
bordered
rowKey="id"
columns={[
...baseColumns,
{
@ -73,8 +102,12 @@ const Tenant: React.FC = () => {
render: (text: string, record: any) => {
return (
<Space>
<Button onClick={() => actions('edit')}></Button>
<Button onClick={() => actions('edit')}></Button>
<Button onClick={() => actions('edit', record)} type="link" className={style.opreate_btn}>
</Button>
<Button onClick={() => actions('edit', record)} type="link" className={style.opreate_btn}>
</Button>
</Space>
);
},

@ -3,44 +3,77 @@ import request from '@/utils';
const fetchTenantList = async (
pageProps: { current: number; pageSize: number },
formData: { tencent: string | number }
) => {
// mock request
return {
total: 3,
list: [
{
num: '1',
tenant: 'admin',
tenantName: 'admin',
creator: 'admin',
data: 'admin',
},
],
};
const res = await request('/tenants', {
): Promise<{ total: number; list: Array<any> }> => {
const res: any = await request('/hippo4j/v1/cs/tenant/query/page', {
method: 'POST',
params: {
headers: {
Authorization:
'Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiI3LGJhb3hpbnlpX2FkbWluIiwiaXNzIjoiYWRtaW4iLCJleHAiOjE2OTUzOTg4NDksImlhdCI6MTY5NDc5NDA0OSwicm9sIjoiUk9MRV9BRE1JTiJ9.syRDshKpd-xETsSdeMPRtk956f4BJkPt4utVsUl4smgH71Woj8SUq4w2RX1YtGTC4aTZRJYdKOfkTqwK0g_dHQ',
cookie:
'Admin-Token=Bearer%20eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiI3LGJhb3hpbnlpX2FkbWluIiwiaXNzIjoiYWRtaW4iLCJleHAiOjE2OTUzOTg4NDksImlhdCI6MTY5NDc5NDA0OSwicm9sIjoiUk9MRV9BRE1JTiJ9.syRDshKpd-xETsSdeMPRtk956f4BJkPt4utVsUl4smgH71Woj8SUq4w2RX1YtGTC4aTZRJYdKOfkTqwK0g_dHQ; userName=baoxinyi_admin',
},
body: {
...formData,
pageNum: pageProps.current,
pageSize: pageProps.pageSize,
current: pageProps.current,
size: pageProps.pageSize,
desc: true,
},
});
if (res && res.success) {
return {
total: 3,
list: [
{
num: '1',
tenant: 'admin',
tenantName: 'admin',
creator: 'admin',
data: 'admin',
},
],
total: res.data.total,
list: res.data.records,
};
}
throw new Error(res.msg || '接口异常');
throw new Error(res.msg || '服务器开小差啦~');
};
const fetchAddTenant = async (id: string) => {
const res = await request('/hippo4j/v1/cs/tenant/save', {
method: 'POST',
params: { id },
});
if (res && res.success) {
return res;
}
throw new Error(res.msg || '服务器开小差啦~');
};
const fetchDeleteTenant = async (id: string) => {
const res = await request('/tenants', {
method: 'POST',
params: { id },
});
if (res && res.success) {
return res;
}
throw new Error(res.msg || '服务器开小差啦~');
};
const fetchUpdateTenant = async (id: string) => {
const res = await request('hippo4j/v1/cs/tenant/update', {
method: 'POST',
params: { id },
});
if (res && res.success) {
return res;
}
throw new Error(res.msg || '服务器开小差啦~');
};
const fetchTenantDetail = async (id: string) => {
const res = await request('/tenants', {
method: 'POST',
params: { id },
});
if (res && res.success) {
return res;
}
throw new Error(res.msg || '服务器开小差啦~');
};
export { fetchTenantList };
export { fetchTenantList, fetchAddTenant, fetchDeleteTenant, fetchUpdateTenant, fetchTenantDetail };

@ -0,0 +1,5 @@
.tenant_wrapper {
.opreate_btn {
padding: 0px;
}
}

@ -0,0 +1,120 @@
import { useAntdTable } from 'ahooks';
import { Button, Form, Input, Row, Space, Table, Col } from 'antd';
import { SearchOutlined, EditOutlined } from '@ant-design/icons';
import React, { useState } from 'react';
import { fetchUserList } from './service';
import { useUrlSet } from '@/hooks/useUrlSet';
import style from './index.module.less';
const baseColumns = [
{
title: '序号',
dataIndex: 'index',
},
{
title: '用户名',
dataIndex: 'userName',
},
{
title: '角色',
dataIndex: 'role',
},
{
title: '创建时间',
dataIndex: 'gmtCreate',
},
{
title: '修改时间',
dataIndex: 'gmtModified',
},
];
const Tenant: React.FC = () => {
const [editVisible, setEditVisible] = useState(false);
const [type, setType] = useState('add');
const [form] = Form.useForm();
const { setUrl } = useUrlSet({ form });
const { tableProps, search } = useAntdTable(fetchUserList, { form });
// const {run: delete} = useRequest(fetchDeleteTenant, { manual: true });
const actions = (type: string, item?: any) => {
switch (type) {
case 'add':
setEditVisible(true);
break;
case 'edit':
setEditVisible(true);
break;
case 'delete':
// handleDelete();
break;
default:
break;
}
};
const handleSearch = () => {
setUrl();
search.submit();
};
// const handleDelete = (item: any) => {
// Modal.confirm({
// title: `此操作将删除${item.tenantName}, 是否继续?`,
// onOk: () => {
// search.submit();
// },
// });
// };
return (
<div className={style.tenant_wrapper}>
<Form form={form} wrapperCol={{ span: 23 }}>
<Row>
<Col span={6}>
<Form.Item name="note">
<Input placeholder="用户名" />
</Form.Item>
</Col>
<Col span={18}>
<Space>
<Button onClick={() => handleSearch()} type="primary" icon={<SearchOutlined />}>
</Button>
<Button onClick={() => setEditVisible(true)} type="primary" icon={<EditOutlined />}>
</Button>
</Space>
</Col>
</Row>
<Row>
<Col span={6}></Col>
<Col span={18}></Col>
</Row>
</Form>
<Table
{...tableProps}
bordered
rowKey="index"
columns={[
...baseColumns,
{
title: '操作',
key: 'action',
render: (text: string, record: any) => {
return (
<Space>
<Button onClick={() => actions('edit', record)} type="link" className={style.opreate_btn}>
</Button>
<Button onClick={() => actions('edit', record)} type="link" className={style.opreate_btn}>
</Button>
</Space>
);
},
},
]}
/>
</div>
);
};
export default Tenant;

@ -0,0 +1,8 @@
import { lazy } from 'react';
import { IRouterList } from '@/typings';
const UserManage = lazy(() => import('./index'));
const routerList: IRouterList[] = [{ path: '/user', component: () => <UserManage /> }];
export default routerList;

@ -0,0 +1,78 @@
import request from '@/utils';
const fetchUserList = async (
pageProps: { current: number; pageSize: number },
formData: { tencent: string | number }
): Promise<{ total: number; list: Array<any> }> => {
const res: any = await request('/hippo4j/v1/cs/auth/users/page', {
method: 'POST',
headers: {
Authorization:
'Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiI3LGJhb3hpbnlpX2FkbWluIiwiaXNzIjoiYWRtaW4iLCJleHAiOjE2OTUzOTg4NDksImlhdCI6MTY5NDc5NDA0OSwicm9sIjoiUk9MRV9BRE1JTiJ9.syRDshKpd-xETsSdeMPRtk956f4BJkPt4utVsUl4smgH71Woj8SUq4w2RX1YtGTC4aTZRJYdKOfkTqwK0g_dHQ',
cookie:
'Admin-Token=Bearer%20eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiI3LGJhb3hpbnlpX2FkbWluIiwiaXNzIjoiYWRtaW4iLCJleHAiOjE2OTUzOTg4NDksImlhdCI6MTY5NDc5NDA0OSwicm9sIjoiUk9MRV9BRE1JTiJ9.syRDshKpd-xETsSdeMPRtk956f4BJkPt4utVsUl4smgH71Woj8SUq4w2RX1YtGTC4aTZRJYdKOfkTqwK0g_dHQ; userName=baoxinyi_admin',
},
body: {
...formData,
current: pageProps.current,
size: pageProps.pageSize,
},
});
if (res && res.success) {
return {
total: res.data.total,
list: res.data.records.map((item: any, index: number) => ({ index: index + 1, ...item })),
};
}
throw new Error(res.msg || '服务器开小差啦~');
};
const fetchAddTenant = async (id: string) => {
const res = await request('/hippo4j/v1/cs/tenant/save', {
method: 'POST',
params: { id },
});
if (res && res.success) {
return res;
}
throw new Error(res.msg || '服务器开小差啦~');
};
const fetchDeleteTenant = async (id: string) => {
const res = await request('/tenants', {
method: 'POST',
params: { id },
});
if (res && res.success) {
return res;
}
throw new Error(res.msg || '服务器开小差啦~');
};
const fetchUpdateTenant = async (id: string) => {
const res = await request('hippo4j/v1/cs/tenant/update', {
method: 'POST',
params: { id },
});
if (res && res.success) {
return res;
}
throw new Error(res.msg || '服务器开小差啦~');
};
const fetchTenantDetail = async (id: string) => {
const res = await request('/tenants', {
method: 'POST',
params: { id },
});
if (res && res.success) {
return res;
}
throw new Error(res.msg || '服务器开小差啦~');
};
export { fetchUserList, fetchAddTenant, fetchDeleteTenant, fetchUpdateTenant, fetchTenantDetail };

@ -1,2 +1,3 @@
/// <reference types="react-scripts" />
declare module '*.less';
declare module 'crypto-browserify' {}

@ -3,6 +3,10 @@ import homeRouter from '@/page/home/router';
import aboutRouter from '@/page/about/router';
import ThreadPoolRouter from '@/page/thread-pool/router';
import tenantRouter from '@/page/tenant/router';
import LoginRouter from '@/page/login/router';
// import itemRouter from '@/page/item/router';
// import userRouter from '@/page/user/router';
// import logRouter from '@/page/log/router';
const routerList: IRouterList[] = [...homeRouter, ...aboutRouter, ...tenantRouter, ...ThreadPoolRouter];
const routerList: IRouterList[] = [...homeRouter, ...aboutRouter, ...tenantRouter, ...ThreadPoolRouter, ...LoginRouter];
export default routerList;

@ -1,6 +1,16 @@
import { ReactNode } from 'react';
import React from 'react';
export enum THEME_NAME {
DEFAULT = 'default',
DARK = 'dark',
}
export enum LANG_NAME {
ZH = 'zh',
EN = 'en',
}
export type IRouterList = {
path: string;
component: () => React.JSX.Element;
@ -11,3 +21,10 @@ export type IMenuList = {
key: string;
icon?: ReactNode;
};
export interface MyStoreValues {
themeName?: THEME_NAME | undefined;
lang?: LANG_NAME;
setThemeName?: (name: THEME_NAME) => void;
setLang?: (lang: LANG_NAME) => void;
}

@ -1,4 +1,44 @@
import Cookie from 'js-cookie';
// import { Buffer } from 'buffer';
// import crypto from 'crypto-browserify';
// /**
// * generate key
// * @returns {string} key(length 16)
// */
// export function genKey() {
// let chars = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
// let result = '';
// for (let i = 16; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
// return result;
// }
// /**
// * encode message
// * @param msg message
// * @param key key
// * @returns {string} encoded message
// */
// export function encrypt(msg: string, key: string) {
// try {
// let pwd = Buffer.from(key);
// let iv = (crypto as any).randomBytes(12);
// let cipher = (crypto as any).createCipheriv('aes-128-gcm', pwd, iv);
// let enc = cipher.update(msg, 'utf8', 'base64');
// enc += cipher.final('base64');
// let tags = cipher.getAuthTag();
// enc = Buffer.from(enc, 'base64') as any;
// let totalLength = iv.length + enc.length + tags.length;
// let bufferMsg = Buffer.concat([iv, enc as any, tags], totalLength);
// return bufferMsg.toString('base64');
// } catch (e) {
// console.log('Encrypt is error', e);
// return null;
// }
// }
import _ from 'lodash';
// is plain object
const TokenKey = 'Admin-Token';
const isPlainObject = (obj: { [key: string]: any }): boolean => {
let proto, Ctor;
if (!obj || typeof obj !== 'object') return false;
@ -8,4 +48,35 @@ const isPlainObject = (obj: { [key: string]: any }): boolean => {
return typeof Ctor === 'function' && Ctor === Object; // insure is new by Object or {}
};
export { isPlainObject };
const setToken = (token: string) => {
Cookie.set(TokenKey, token);
};
/**
* @description object value
* @param obj
* @returns
*/
const filterEmptyField = (obj: { [key: string]: any }) => {
return _.omitBy(obj, isEmpty);
};
/**
* @description
* @param value
* @returns
*/
const isNilValue = (value: any) => {
return value === undefined || value === '' || value === null || Number.isNaN(value);
};
/**
* @description /
* @param value
* @returns
*/
const isEmpty = (value: any) => {
return typeof value === 'object' ? _.isEmpty(value) : isNilValue(value);
};
export { isPlainObject, isEmpty, filterEmptyField, setToken };

@ -32,7 +32,7 @@ type Response<T = any> = {
code?: string | number;
};
let baseURL = 'http://127.0.0.1:9999';
let baseURL = '';
const inital: RequestOptions = {
method: 'GET',
@ -40,6 +40,8 @@ const inital: RequestOptions = {
body: null,
headers: {
'Content-Type': 'application/json',
Authorization:
'Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxMCxiYW94aW55aV91c2VyIiwiaXNzIjoiYWRtaW4iLCJleHAiOjE2OTU3MzAwNzYsImlhdCI6MTY5NTEyNTI3Niwicm9sIjoiUk9MRV9VU0VSIn0.4cWyhllP7u-aoRAIHs3nMggsgl4-LUCVBas8WE0FJYIe-YNS0wGf1_0RJq3TUGw00KmSaSRPKdoPgRTFqEphZA',
},
credentials: true,
responseType: 'JSON',
@ -104,6 +106,7 @@ function request<T>(url: string, config: RequestOptions): Promise<Response<T>> {
method = method.toUpperCase();
responseType = responseType.toUpperCase();
config = {
...config,
method,
credentials,
responseType,
@ -113,8 +116,10 @@ function request<T>(url: string, config: RequestOptions): Promise<Response<T>> {
} else {
config.body = null;
}
return fetch(url, config as any).then(function onfulfilled(response) {
let { status, statusText } = response;
console.log('status:::', status, response);
if (status >= 200 && status < 400) {
let result;
switch (responseType) {

@ -1196,7 +1196,7 @@
resolved "https://registry.npmmirror.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310"
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
"@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.16.7", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.19.4", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
"@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.16.7", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.19.4", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.15", "@babel/runtime@^7.22.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
version "7.22.15"
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.22.15.tgz#38f46494ccf6cf020bd4eed7124b425e83e523b8"
integrity sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==
@ -2060,6 +2060,14 @@
"@svgr/plugin-svgo" "^5.5.0"
loader-utils "^2.0.0"
"@tanem/react-nprogress@^5.0.51":
version "5.0.51"
resolved "https://registry.npmmirror.com/@tanem/react-nprogress/-/react-nprogress-5.0.51.tgz#6cbdb52a0a27ecf845f61d809ef6fd45b063662d"
integrity sha512-YxNUCpznuBVA+PhjEzFmxaa1czXgU+5Ojchw5JBK7DQS6SHIgNudpFohWpNBWMu2KWByGJ2OLH2OwbM/XyP18Q==
dependencies:
"@babel/runtime" "^7.22.15"
hoist-non-react-statics "^3.3.2"
"@testing-library/dom@^8.5.0":
version "8.20.1"
resolved "https://registry.npmmirror.com/@testing-library/dom/-/dom-8.20.1.tgz#2e52a32e46fc88369eef7eef634ac2a192decd9f"
@ -2332,6 +2340,11 @@
resolved "https://registry.npmmirror.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
"@types/lodash@^4.14.198":
version "4.14.198"
resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.198.tgz#4d27465257011aedc741a809f1269941fa2c5d4c"
integrity sha512-trNJ/vtMZYMLhfN45uLq4ShQSw0/S7xCTLLVM+WM1rmFpba/VS42jVUgaO3w/NOLiWR/09lnYk0yMaA/atdIsg==
"@types/mime@*":
version "3.0.1"
resolved "https://registry.npmmirror.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10"
@ -5598,6 +5611,13 @@ he@^1.2.0:
resolved "https://registry.npmmirror.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.npmmirror.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
dependencies:
react-is "^16.7.0"
hoopy@^0.1.4:
version "0.1.4"
resolved "https://registry.npmmirror.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d"
@ -5711,7 +5731,7 @@ http-proxy-agent@^4.0.1:
agent-base "6"
debug "4"
http-proxy-middleware@^2.0.3:
http-proxy-middleware@^2.0.3, http-proxy-middleware@^2.0.6:
version "2.0.6"
resolved "https://registry.npmmirror.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f"
integrity sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==
@ -8996,7 +9016,7 @@ react-i18next@^13.2.2:
"@babel/runtime" "^7.22.5"
html-parse-stringify "^3.0.1"
react-is@^16.12.0, react-is@^16.13.1:
react-is@^16.12.0, react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==

@ -1,76 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@babel/runtime@^7.21.0":
version "7.22.15"
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.22.15.tgz#38f46494ccf6cf020bd4eed7124b425e83e523b8"
integrity sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==
dependencies:
regenerator-runtime "^0.14.0"
"@types/js-cookie@^2.x.x":
version "2.2.7"
resolved "https://registry.npmmirror.com/@types/js-cookie/-/js-cookie-2.2.7.tgz#226a9e31680835a6188e887f3988e60c04d3f6a3"
integrity sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==
ahooks-v3-count@^1.0.0:
version "1.0.0"
resolved "https://registry.npmmirror.com/ahooks-v3-count/-/ahooks-v3-count-1.0.0.tgz#ddeb392e009ad6e748905b3cbf63a9fd8262ca80"
integrity sha512-V7uUvAwnimu6eh/PED4mCDjE7tokeZQLKlxg9lCTMPhN+NjsSbtdacByVlR1oluXQzD3MOw55wylDmQo4+S9ZQ==
ahooks@^3.7.8:
version "3.7.8"
resolved "https://registry.npmmirror.com/ahooks/-/ahooks-3.7.8.tgz#3fa3c491cd153e884a32b0c4192fc72cf84c4332"
integrity sha512-e/NMlQWoCjaUtncNFIZk3FG1ImSkV/JhScQSkTqnftakRwdfZWSw6zzoWSG9OMYqPNs2MguDYBUFFC6THelWXA==
dependencies:
"@babel/runtime" "^7.21.0"
"@types/js-cookie" "^2.x.x"
ahooks-v3-count "^1.0.0"
dayjs "^1.9.1"
intersection-observer "^0.12.0"
js-cookie "^2.x.x"
lodash "^4.17.21"
resize-observer-polyfill "^1.5.1"
screenfull "^5.0.0"
tslib "^2.4.1"
dayjs@^1.9.1:
version "1.11.9"
resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.9.tgz#9ca491933fadd0a60a2c19f6c237c03517d71d1a"
integrity sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==
intersection-observer@^0.12.0:
version "0.12.2"
resolved "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz#4a45349cc0cd91916682b1f44c28d7ec737dc375"
integrity sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==
js-cookie@^2.x.x:
version "2.2.1"
resolved "https://registry.npmmirror.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
regenerator-runtime@^0.14.0:
version "0.14.0"
resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45"
integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==
resize-observer-polyfill@^1.5.1:
version "1.5.1"
resolved "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
screenfull@^5.0.0:
version "5.2.0"
resolved "https://registry.npmmirror.com/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba"
integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==
tslib@^2.4.1:
version "2.6.2"
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
Loading…
Cancel
Save