feat: main content

main
fadeaway 4 months ago
parent a761ea3d0d
commit 72c4fa2c77

24001
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -19,6 +19,7 @@
"@arco-themes/react-arco-pro": "^0.0.7",
"@loadable/component": "^5.13.2",
"@turf/turf": "^6.5.0",
"ahooks": "^3.8.0",
"arco-design-pro": "^2.8.1",
"axios": "^0.24.0",
"bizcharts": "^4.1.11",

@ -6,6 +6,8 @@
padding: 28px 28px 33px;
background: #101011;
color: #ffffff99;
width: 100%;
box-sizing: border-box;
.nav {
.center();

@ -2,16 +2,22 @@
@import '@/style/common.less';
.header {
position: fixed;
left: 0;
top: 0;
.center();
padding-left: 20px;
padding-right: 20px;
box-sizing: border-box;
width: 100%;
z-index: 99;
&.light {
background-color: #fff;
box-shadow: 0px -1px 0px 0px #00000014 inset;
}
&.dark {
// background-color: #000;
background-color: #000;
}
.cont {

@ -41,7 +41,7 @@ function LoginModal(props: LoginModalProps, ref: React.Ref<any>) {
setSubmiting(true);
const { userName, password } = values;
request
.post(`/user/user/login/${userName}/${password}`, values)
.post(`/user/user/login/username`, values)
.then((res: any) => {
if (res?.code === 200 && res?.data?.token) {
Message.success('登录成功');

@ -0,0 +1,76 @@
import React from 'react';
import {
Typography,
Card,
Table,
Form,
Grid,
Input,
Select,
Button,
Space,
DatePicker,
} from '@arco-design/web-react';
import type { TableProps } from '@arco-design/web-react';
import styles from './style/index.module.less';
export interface SearchTableProps extends TableProps {
searchFields: any[];
}
const { Item: FormItem, useForm } = Form;
const { Row, Col } = Grid;
const { RangePicker } = DatePicker;
function SearchTable(props?: SearchTableProps) {
const { columns, data, searchFields } = props || {};
const [form] = useForm();
const handleSearch = () => {
//
};
const handleReset = () => {
form.resetFields();
};
return (
<>
{searchFields && searchFields.length > 0 && (
<Form form={form} className={styles.mb24}>
<Row gutter={12}>
{searchFields.map((item) => {
return (
<Col flex={item.width || '200px'} key={item.field}>
<FormItem field={item.field} noStyle>
{item.ele}
</FormItem>
</Col>
);
})}
<Col flex={1} className={styles.alignRight}>
<Space size={12}>
<Button type="primary" onClick={handleSearch}>
</Button>
<Button onClick={handleReset}></Button>
</Space>
</Col>
</Row>
</Form>
)}
<Table
columns={columns}
data={data}
rowSelection={{
type: 'checkbox',
checkAll: true,
}}
border={false}
pagePosition="bl"
/>
</>
);
}
export default SearchTable;

@ -0,0 +1,11 @@
.mb24 {
margin-bottom: 24px;
}
.w200 {
width: 200px;
}
.alignRight {
text-align: right;
}

@ -1,17 +1,20 @@
import React, { useState, useRef, useMemo, useEffect } from 'react';
import React, { useState, useRef, useMemo, useEffect, Children } from 'react';
import { Switch, Route, Redirect, useHistory } from 'react-router-dom';
import { Layout, Menu, Breadcrumb, Spin } from '@arco-design/web-react';
import cs from 'classnames';
import {
IconDashboard,
IconTag,
IconBulb,
IconUserGroup,
IconFileAudio,
IconDesktop,
IconTool,
IconMenuFold,
IconMenuUnfold,
} from '@arco-design/web-react/icon';
import { useSelector } from 'react-redux';
import qs from 'query-string';
import NProgress from 'nprogress';
import Navbar from './components/NavBar';
import Header from './components/Header';
import Footer from './components/Footer';
import useRoute, { IRoute } from '@/routes';
import useLocale from './utils/useLocale';
@ -28,10 +31,20 @@ const Content = Layout.Content;
function getIconFromKey(key) {
switch (key) {
case 'dashboard':
return <IconDashboard className={styles.icon} />;
case 'example':
return <IconTag className={styles.icon} />;
case 'index':
return <IconBulb className={styles.icon} />;
case 'artists':
return <IconUserGroup className={styles.icon} />;
case 'albumWorks':
return <IconFileAudio className={styles.icon} />;
case 'financial':
return <IconDesktop className={styles.icon} />;
case 'settings':
return <IconTool className={styles.icon} />;
// case 'dashboard':
// return <IconDashboard className={styles.icon} />;
// case 'example':
// return <IconTag className={styles.icon} />;
default:
return <div className={styles['icon-empty']} />;
}
@ -157,10 +170,6 @@ function PageLayout() {
setCollapsed((collapsed) => !collapsed);
}
const paddingLeft = showMenu ? { paddingLeft: menuWidth } : {};
const paddingTop = showNavbar ? { paddingTop: navbarHeight } : {};
const paddingStyle = { ...paddingLeft, ...paddingTop };
function updateMenuStatus() {
const pathKeys = pathname.split('/');
const newSelectedKeys: string[] = [];
@ -186,31 +195,22 @@ function PageLayout() {
setBreadCrumb(routeConfig || []);
updateMenuStatus();
}, [pathname]);
return (
<Layout className={styles.layout}>
<div
className={cs(styles['layout-navbar'], {
[styles['layout-navbar-hidden']]: !showNavbar,
})}
>
<Navbar show={showNavbar} />
</div>
{userLoading ? (
<Spin className={styles['spin']} />
) : (
<Layout>
<Header mode="light" />
<Layout className={styles.layoutContent}>
{showMenu && (
<Sider
className={styles['layout-sider']}
className={styles.layoutSider}
width={menuWidth}
collapsed={collapsed}
onCollapse={setCollapsed}
trigger={null}
collapsible
breakpoint="xl"
style={paddingTop}
>
<div className={styles['menu-wrapper']}>
<div className={styles.menuWrapper}>
<Menu
collapse={collapsed}
onClickMenuItem={onClickMenuItem}
@ -221,15 +221,14 @@ function PageLayout() {
{renderRoutes(locale)(routes, 1)}
</Menu>
</div>
<div className={styles['collapse-btn']} onClick={toggleCollapse}>
<div className={styles.collapseBtn} onClick={toggleCollapse}>
{collapsed ? <IconMenuUnfold /> : <IconMenuFold />}
</div>
</Sider>
)}
<Layout className={styles['layout-content']} style={paddingStyle}>
<div className={styles['layout-content-wrapper']}>
<Layout className={styles.layoutMainContent}>
{!!breadcrumb.length && (
<div className={styles['layout-breadcrumb']}>
<div className={styles.layoutBreadcrumb}>
<Breadcrumb>
{breadcrumb.map((node, index) => (
<Breadcrumb.Item key={index}>
@ -259,11 +258,9 @@ function PageLayout() {
/>
</Switch>
</Content>
</div>
{showFooter && <Footer />}
</Layout>
</Layout>
)}
{showFooter && <Footer />}
</Layout>
);
}

@ -1,5 +1,10 @@
const i18n = {
'en-US': {
'menu.index': 'Index',
'menu.artists': 'Artists',
'menu.albumWorks': 'Album Works',
'menu.financial': 'Financial',
'menu.settings': 'Settings',
'menu.dashboard': 'Dashboard',
'menu.dashboard.workplace': 'Workplace',
'menu.user.info': 'User Info',
@ -38,6 +43,11 @@ const i18n = {
'navbar.search.placeholder': 'Please search',
},
'zh-CN': {
'menu.index': '首页',
'menu.artists': '厂牌艺人',
'menu.albumWorks': '专辑作品',
'menu.financial': '财务报表',
'menu.settings': '个人设置',
'menu.dashboard': '仪表盘',
'menu.dashboard.workplace': '工作台',
'menu.user.info': '用户信息',

@ -0,0 +1,13 @@
import React from 'react';
import { Typography, Card } from '@arco-design/web-react';
function AlbumWorks() {
return (
<Card>
<Typography.Title heading={6}></Typography.Title>
<Typography.Text>You can add content here :)</Typography.Text>
</Card>
);
}
export default AlbumWorks;

@ -0,0 +1,146 @@
import React, { useState } from 'react';
import {
Input,
Select,
Button,
Avatar,
Space,
DatePicker,
} from '@arco-design/web-react';
import { useAsyncEffect } from 'ahooks';
import { IconDelete } from '@arco-design/web-react/icon';
import SearchTable from '@/components/SearchTable';
const { RangePicker } = DatePicker;
const columns = [
{
title: '名称',
dataIndex: 'name',
render: (name) => {
return (
<Space size={8}>
<Avatar size={24} />
<span>{name}</span>
</Space>
);
},
},
{
title: '类型',
dataIndex: 'type',
},
{
title: '粉丝数',
dataIndex: 'fans',
sorter: true,
},
{
title: '专辑数',
dataIndex: 'album',
sorter: true,
},
{
title: '歌曲数',
dataIndex: 'song',
sorter: true,
},
{
title: '加入时间',
dataIndex: 'time',
},
{
title: '操作',
dataIndex: 'operation',
render: (_, record) => (
<>
<Button type="text"></Button>
<Button type="text"></Button>
<Button type="text" status="danger" icon={<IconDelete />}>
</Button>
</>
),
},
];
const defaultData = [
{
key: '1',
name: 'Jane Doe',
type: '个人',
fans: '1.2万',
album: '2张',
song: '30首',
time: '2024.05.26',
},
{
key: '2',
name: 'Jane Doe',
type: '个人',
fans: '1.2万',
album: '2张',
song: '30首',
time: '2024.05.26',
},
{
key: '3',
name: 'Jane Doe',
type: '个人',
fans: '1.2万',
album: '2张',
song: '30首',
time: '2024.05.26',
},
{
key: '4',
name: 'Jane Doe',
type: '个人',
fans: '1.2万',
album: '2张',
song: '30首',
time: '2024.05.26',
},
{
key: '5',
name: 'Jane Doe',
type: '个人',
fans: '1.2万',
album: '2张',
song: '30首',
time: '2024.05.26',
},
];
const options = [
{ label: '个人', value: 0 },
{ label: '团体', value: 1 },
];
const searchFields = [
{
field: 'q',
ele: <Input placeholder="输入搜索内容" allowClear />,
},
{
field: 'q2',
ele: <Select placeholder="请选择" options={options} allowClear />,
},
{
field: 'q3',
ele: <RangePicker mode="month" allowClear />,
},
];
function Artists() {
const [data, setData] = useState<any>();
useAsyncEffect(async () => {
setData(defaultData);
}, []);
return (
<SearchTable searchFields={searchFields} columns={columns} data={data} />
);
}
export default Artists;

@ -0,0 +1,13 @@
import React from 'react';
import { Typography, Card } from '@arco-design/web-react';
function Index() {
return (
<Card>
<Typography.Title heading={6}></Typography.Title>
<Typography.Text>You can add content here :)</Typography.Text>
</Card>
);
}
export default Index;

@ -13,8 +13,20 @@ export type IRoute = AuthParams & {
export const routes: IRoute[] = [
{
name: 'menu.dashboard',
key: 'dashboard',
name: 'menu.index',
key: 'index',
},
{
name: 'menu.artists',
key: 'artists',
},
{
name: 'menu.albumWorks',
key: 'albumWorks',
},
{
name: 'menu.financial',
key: 'financial',
children: [
{
name: 'menu.dashboard.workplace',
@ -23,9 +35,29 @@ export const routes: IRoute[] = [
],
},
{
name: 'Example',
key: 'example',
name: 'menu.settings',
key: 'settings',
children: [
{
name: 'menu.dashboard.workplace',
key: 'dashboard/workplace',
},
],
},
// {
// name: 'menu.dashboard',
// key: 'dashboard',
// children: [
// {
// name: 'menu.dashboard.workplace',
// key: 'dashboard/workplace',
// },
// ],
// },
// {
// name: 'Example',
// key: 'example',
// },
];
export const getName = (path: string, routes) => {

@ -4,5 +4,5 @@
"menu": true,
"footer": true,
"themeColor": "#165DFF",
"menuWidth": 220
"menuWidth": 180
}

@ -1,29 +1,44 @@
@import '@/style/variable.less';
@import '@/style/common.less';
@nav-size-height: 60px;
@layout-max-width: 1100px;
.layout {
width: 100%;
height: 100%;
min-height: 100vh;
margin: auto;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
background-color: #fff;
}
.layout-navbar {
position: fixed;
.layoutBreadcrumb {
margin-bottom: 22px;
}
.spin {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-width: @layout-max-width;
top: 0;
left: 0;
height: @nav-size-height;
z-index: 100;
min-height: calc(100vh - @nav-size-height);
}
&-hidden {
height: 0;
}
.layoutContent {
flex: 1;
width: @CONTENT_WIDTH;
display: flex;
padding-top: 72px;
position: relative;
}
.layout-sider {
position: fixed;
height: 100%;
top: 0;
.layoutContent .layoutSider {
position: sticky;
height: calc(100vh - 72px - 103px);
top: 72px;
left: 0;
z-index: 99;
box-sizing: border-box;
@ -59,7 +74,7 @@
overflow-y: hidden;
}
.collapse-btn {
.collapseBtn {
height: 24px;
width: 24px;
background-color: var(--color-fill-1);
@ -80,7 +95,7 @@
}
}
.menu-wrapper {
.menuWrapper {
overflow: auto;
height: 100%;
@ -102,37 +117,11 @@
}
}
.icon {
font-size: 18px;
vertical-align: text-bottom;
}
.icon-empty {
width: 12px;
height: 18px;
display: inline-block;
}
.layout-content {
background-color: var(--color-fill-2);
min-width: @layout-max-width;
min-height: 100vh;
.layoutMainContent {
background-color: #fff;
transition: padding-left 0.2s;
box-sizing: border-box;
}
.layout-content-wrapper {
padding: 16px 20px 0px 20px;
}
.layout-breadcrumb {
margin-bottom: 16px;
}
.spin {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: calc(100vh - @nav-size-height);
padding-top: 15px;
padding-left: 30px;
padding-bottom: 50px;
}

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save