u
This commit is contained in:
@@ -1,10 +0,0 @@
|
||||
import Typography from '@mui/material/Typography';
|
||||
import PageLayout from '../components/PageLayout';
|
||||
|
||||
export default function InfosPage() {
|
||||
return (
|
||||
<PageLayout title="Infos">
|
||||
<Typography color="text.secondary">Infos — Inhalt folgt.</Typography>
|
||||
</PageLayout>
|
||||
);
|
||||
}
|
||||
152
src/routes/infos/ArticleHistoryPage.jsx
Normal file
152
src/routes/infos/ArticleHistoryPage.jsx
Normal file
@@ -0,0 +1,152 @@
|
||||
import { PureComponent } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Button from '@mui/material/Button';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import { PanelTile } from 'dashgui/panels';
|
||||
import { AutomatGrid } from 'react-virtual-aggridautomat';
|
||||
import { articleHistoryGridAutomat } from '../../automats';
|
||||
import { router } from '../../appRouter';
|
||||
|
||||
const COLUMN_DEFS = [
|
||||
{
|
||||
headerName: 'ID',
|
||||
field: 'id',
|
||||
maxWidth: 90,
|
||||
sortable: true,
|
||||
filter: 'agNumberColumnFilter',
|
||||
cellStyle: { fontVariantNumeric: 'tabular-nums' },
|
||||
},
|
||||
{
|
||||
headerName: 'Datum',
|
||||
field: 'date',
|
||||
minWidth: 170,
|
||||
maxWidth: 200,
|
||||
sortable: true,
|
||||
valueFormatter: (p) => (p.value ? new Date(p.value).toLocaleString('de-DE') : ''),
|
||||
cellStyle: { fontVariantNumeric: 'tabular-nums' },
|
||||
},
|
||||
{
|
||||
headerName: 'Artikel-Nr.',
|
||||
field: 'sku',
|
||||
minWidth: 130,
|
||||
maxWidth: 160,
|
||||
sortable: true,
|
||||
filter: 'agTextColumnFilter',
|
||||
cellRenderer: (p) => {
|
||||
if (!p.value) return '';
|
||||
return (
|
||||
<a
|
||||
href={`/artikel/${encodeURIComponent(p.value)}`}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
void router.navigate(`/artikel/${encodeURIComponent(p.value)}`);
|
||||
}}
|
||||
style={{ color: '#2563eb', fontWeight: 600, textDecoration: 'none' }}
|
||||
>
|
||||
{p.value}
|
||||
</a>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
headerName: 'Artikelname',
|
||||
field: 'name',
|
||||
minWidth: 180,
|
||||
flex: 1,
|
||||
sortable: true,
|
||||
filter: 'agTextColumnFilter',
|
||||
},
|
||||
{
|
||||
headerName: 'Änderung / Ereignis',
|
||||
field: 'text',
|
||||
minWidth: 300,
|
||||
flex: 2,
|
||||
sortable: true,
|
||||
filter: 'agTextColumnFilter',
|
||||
cellStyle: { whiteSpace: 'pre-wrap', lineHeight: '1.4' },
|
||||
autoHeight: true,
|
||||
},
|
||||
{
|
||||
headerName: 'Benutzer',
|
||||
field: 'user',
|
||||
maxWidth: 160,
|
||||
sortable: true,
|
||||
filter: 'agTextColumnFilter',
|
||||
valueGetter: (p) =>
|
||||
p.data?.user ||
|
||||
p.data?.employee ||
|
||||
p.data?.companyuser ||
|
||||
(p.data?.companyuserId ? `User #${p.data.companyuserId}` : '—'),
|
||||
},
|
||||
];
|
||||
|
||||
export default class ArticleHistoryPage extends PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const s = articleHistoryGridAutomat.state;
|
||||
this.state = {
|
||||
loading: s.loading,
|
||||
error: s.error,
|
||||
totalRows: s.totalRows,
|
||||
};
|
||||
this.handleReload = this.handleReload.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.unsub = articleHistoryGridAutomat.subscribe(this, (state) => ({
|
||||
loading: state.loading,
|
||||
error: state.error,
|
||||
totalRows: state.totalRows,
|
||||
}));
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.unsub?.();
|
||||
}
|
||||
|
||||
handleReload() {
|
||||
articleHistoryGridAutomat.actions.reload();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { loading, totalRows } = this.state;
|
||||
|
||||
const actions = (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5 }}>
|
||||
{loading && <CircularProgress size={18} thickness={5} />}
|
||||
{totalRows >= 0 && (
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{totalRows} Einträge
|
||||
</Typography>
|
||||
)}
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
startIcon={<RefreshIcon />}
|
||||
onClick={this.handleReload}
|
||||
disabled={loading}
|
||||
>
|
||||
Aktualisieren
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
|
||||
return (
|
||||
<PanelTile title="Artikel-Historie" actions={actions} sx={{ p: 0, height: 'calc(100vh - 140px)', display: 'flex', flexDirection: 'column' }}>
|
||||
<Box sx={{ flex: 1, minHeight: 0, width: '100%' }}>
|
||||
<AutomatGrid
|
||||
automat={articleHistoryGridAutomat}
|
||||
columnDefs={COLUMN_DEFS}
|
||||
rowIdField="id"
|
||||
cacheBlockSize={50}
|
||||
height="100%"
|
||||
width="100%"
|
||||
noRowsOverlayText="Keine Historieneinträge vorhanden"
|
||||
/>
|
||||
</Box>
|
||||
</PanelTile>
|
||||
);
|
||||
}
|
||||
}
|
||||
137
src/routes/infos/GlobalHistoryPage.jsx
Normal file
137
src/routes/infos/GlobalHistoryPage.jsx
Normal file
@@ -0,0 +1,137 @@
|
||||
import { PureComponent } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Button from '@mui/material/Button';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import { PanelTile } from 'dashgui/panels';
|
||||
import { AutomatGrid } from 'react-virtual-aggridautomat';
|
||||
import { globalHistoryGridAutomat } from '../../automats';
|
||||
|
||||
const COLUMN_DEFS = [
|
||||
{
|
||||
headerName: 'ID',
|
||||
field: 'id',
|
||||
maxWidth: 90,
|
||||
sortable: true,
|
||||
filter: 'agNumberColumnFilter',
|
||||
cellStyle: { fontVariantNumeric: 'tabular-nums' },
|
||||
},
|
||||
{
|
||||
headerName: 'Datum',
|
||||
field: 'date',
|
||||
minWidth: 170,
|
||||
maxWidth: 200,
|
||||
sortable: true,
|
||||
valueFormatter: (p) => (p.value ? new Date(p.value).toLocaleString('de-DE') : ''),
|
||||
cellStyle: { fontVariantNumeric: 'tabular-nums' },
|
||||
},
|
||||
{
|
||||
headerName: 'Typ',
|
||||
field: 'type',
|
||||
minWidth: 120,
|
||||
maxWidth: 160,
|
||||
sortable: true,
|
||||
filter: 'agTextColumnFilter',
|
||||
},
|
||||
{
|
||||
headerName: 'Referenz / Key',
|
||||
field: 'reference',
|
||||
minWidth: 140,
|
||||
maxWidth: 200,
|
||||
sortable: true,
|
||||
filter: 'agTextColumnFilter',
|
||||
valueGetter: (p) => p.data?.reference || p.data?.p1 || '',
|
||||
},
|
||||
{
|
||||
headerName: 'Meldung / Beschreibung',
|
||||
field: 'text',
|
||||
minWidth: 300,
|
||||
flex: 2,
|
||||
sortable: true,
|
||||
filter: 'agTextColumnFilter',
|
||||
valueGetter: (p) => p.data?.text || p.data?.value || '',
|
||||
cellStyle: { whiteSpace: 'pre-wrap', lineHeight: '1.4' },
|
||||
autoHeight: true,
|
||||
},
|
||||
{
|
||||
headerName: 'Benutzer',
|
||||
field: 'user',
|
||||
maxWidth: 160,
|
||||
sortable: true,
|
||||
filter: 'agTextColumnFilter',
|
||||
valueGetter: (p) =>
|
||||
p.data?.user ||
|
||||
p.data?.employee ||
|
||||
(p.data?.companyuserId ? `User #${p.data.companyuserId}` : '—'),
|
||||
},
|
||||
];
|
||||
|
||||
export default class GlobalHistoryPage extends PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const s = globalHistoryGridAutomat.state;
|
||||
this.state = {
|
||||
loading: s.loading,
|
||||
error: s.error,
|
||||
totalRows: s.totalRows,
|
||||
};
|
||||
this.handleReload = this.handleReload.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.unsub = globalHistoryGridAutomat.subscribe(this, (state) => ({
|
||||
loading: state.loading,
|
||||
error: state.error,
|
||||
totalRows: state.totalRows,
|
||||
}));
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.unsub?.();
|
||||
}
|
||||
|
||||
handleReload() {
|
||||
globalHistoryGridAutomat.actions.reload();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { loading, totalRows } = this.state;
|
||||
|
||||
const actions = (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5 }}>
|
||||
{loading && <CircularProgress size={18} thickness={5} />}
|
||||
{totalRows >= 0 && (
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{totalRows} Einträge
|
||||
</Typography>
|
||||
)}
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
startIcon={<RefreshIcon />}
|
||||
onClick={this.handleReload}
|
||||
disabled={loading}
|
||||
>
|
||||
Aktualisieren
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
|
||||
return (
|
||||
<PanelTile title="Globale Historie" actions={actions} sx={{ p: 0, height: 'calc(100vh - 140px)', display: 'flex', flexDirection: 'column' }}>
|
||||
<Box sx={{ flex: 1, minHeight: 0, width: '100%' }}>
|
||||
<AutomatGrid
|
||||
automat={globalHistoryGridAutomat}
|
||||
columnDefs={COLUMN_DEFS}
|
||||
rowIdField="id"
|
||||
cacheBlockSize={50}
|
||||
height="100%"
|
||||
width="100%"
|
||||
noRowsOverlayText="Keine globalen Historieneinträge vorhanden"
|
||||
/>
|
||||
</Box>
|
||||
</PanelTile>
|
||||
);
|
||||
}
|
||||
}
|
||||
36
src/routes/infos/StatisticsPage.jsx
Normal file
36
src/routes/infos/StatisticsPage.jsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { PureComponent } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import BarChartIcon from '@mui/icons-material/BarChart';
|
||||
import { PanelTile } from 'dashgui/panels';
|
||||
|
||||
export default class StatisticsPage extends PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<PanelTile title="Statistik">
|
||||
<Box
|
||||
sx={{
|
||||
py: 8,
|
||||
px: 2,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
color: 'text.secondary',
|
||||
textAlign: 'center',
|
||||
gap: 1.5,
|
||||
}}
|
||||
>
|
||||
<BarChartIcon sx={{ fontSize: 48, opacity: 0.4 }} />
|
||||
<Typography variant="h6" color="text.primary" fontWeight={600}>
|
||||
Statistik & Auswertungen
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ maxWidth: 420 }}>
|
||||
Hier entstehen demnächst grafische Auswertungen, Umsatzstatistiken und
|
||||
Bestandskennzahlen.
|
||||
</Typography>
|
||||
</Box>
|
||||
</PanelTile>
|
||||
);
|
||||
}
|
||||
}
|
||||
3
src/routes/infos/index.js
Normal file
3
src/routes/infos/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export { default as ArticleHistoryPage } from './ArticleHistoryPage';
|
||||
export { default as GlobalHistoryPage } from './GlobalHistoryPage';
|
||||
export { default as StatisticsPage } from './StatisticsPage';
|
||||
Reference in New Issue
Block a user