From 23e63904e4c2b734f92bdfd5aac0e16948af72b3 Mon Sep 17 00:00:00 2001
From: skyouc
Date: 星期一, 14 四月 2025 09:21:21 +0800
Subject: [PATCH] no message

---
 rsf-admin/src/page/orders/purchase/PurchaseList.jsx       |  170 +++++++
 rsf-admin/src/page/orders/purchase/PurchaseEdit.jsx       |  152 ++++++
 rsf-admin/src/layout/MyMenu.jsx                           |    2 
 rsf-admin/src/page/orders/asnOrder/AsnOrderItemEdit.jsx   |   54 +-
 rsf-admin/src/page/orders/purchase/PurchaseItemEdit.jsx   |  198 ++++++++
 rsf-admin/src/page/orders/purchase/index.jsx              |   18 
 rsf-admin/src/page/orders/purchase/PurchaseItemList.jsx   |  171 +++++++
 rsf-admin/src/layout/SubMenu.jsx                          |    4 
 rsf-admin/src/page/orders/asnOrder/AsnOrderItemList.jsx   |    2 
 rsf-admin/src/page/orders/purchase/PurchaseItemCreate.jsx |  201 ++++++++
 rsf-admin/src/page/ResourceContent.js                     |    4 
 rsf-admin/src/page/orders/purchase/PurchaseCreate.jsx     |  194 ++++++++
 rsf-admin/src/page/orders/purchase/PurchasePanel.jsx      |  182 +++++++
 13 files changed, 1,317 insertions(+), 35 deletions(-)

diff --git a/rsf-admin/src/layout/MyMenu.jsx b/rsf-admin/src/layout/MyMenu.jsx
index 547f65a..5338309 100644
--- a/rsf-admin/src/layout/MyMenu.jsx
+++ b/rsf-admin/src/layout/MyMenu.jsx
@@ -58,6 +58,8 @@
     const IconComponent = getIconComponent(iconStr);
     if (IconComponent) {
       return <IconComponent />;
+    } else {
+      return <KeyboardArrowDownIcon />
     }
   };
 
diff --git a/rsf-admin/src/layout/SubMenu.jsx b/rsf-admin/src/layout/SubMenu.jsx
index d79867e..e09b22d 100644
--- a/rsf-admin/src/layout/SubMenu.jsx
+++ b/rsf-admin/src/layout/SubMenu.jsx
@@ -15,14 +15,12 @@
 const SubMenu = (props) => {
     const { handleToggle, isOpen, name, icon, children, dense } = props;
     const translate = useTranslate();
-
     const [sidebarIsOpen] = useSidebarState();
 
     const header = (
         <MenuItem dense={dense} onClick={handleToggle} sx={{ display: 'flex', alignItems: 'center' }}>
             <ListItemIcon sx={{ minWidth: 40, color: 'text.secondary', display: 'flex', alignItems: 'center' }}>
-                {/* {isOpen ? <ExpandMore /> : icon}  */}
-                {isOpen ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
+                {icon ? icon :  isOpen ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
             </ListItemIcon>
             <Typography variant="inherit" color="textSecondary" sx={{ ml: 1, display: 'flex', alignItems: 'center' }}>
                 {translate(name)}
diff --git a/rsf-admin/src/page/ResourceContent.js b/rsf-admin/src/page/ResourceContent.js
index 5a90285..3a81c8e 100644
--- a/rsf-admin/src/page/ResourceContent.js
+++ b/rsf-admin/src/page/ResourceContent.js
@@ -80,8 +80,6 @@
             return contract;
         case 'qlyInspect':
             return qlyInspect;
-        case 'qlyIsptItem':
-            return qlyIsptItem;
         case 'dictType':
             return dictType;
         case 'companys':
@@ -92,8 +90,6 @@
             return whMat;
         case 'asnOrder':
             return asnOrder;
-        case 'asnOrderItem':
-            return asnOrderItem;
         case 'asnOrderLog':
             return asnOrderLog;
         case 'purchase':
diff --git a/rsf-admin/src/page/orders/asnOrder/AsnOrderItemEdit.jsx b/rsf-admin/src/page/orders/asnOrder/AsnOrderItemEdit.jsx
index 07570e0..0ed7504 100644
--- a/rsf-admin/src/page/orders/asnOrder/AsnOrderItemEdit.jsx
+++ b/rsf-admin/src/page/orders/asnOrder/AsnOrderItemEdit.jsx
@@ -55,33 +55,33 @@
     if (data == null || data == undefined) { return }
 
     return (
-        <EditBase
-            id={record?.id}
-            resource="asnOrderItem"
-            mutationMode={EDIT_MODE}
-            actions={<CustomerTopToolBar />}
+        <Dialog
+            open={open}
+            onClose={handleClose}
+            aria-labelledby="form-dialog-title"
+            fullWidth
+            disableRestoreFocus
+            maxWidth="md"
         >
-            <Dialog
-                open={open}
-                onClose={handleClose}
-                aria-labelledby="form-dialog-title"
-                fullWidth
-                disableRestoreFocus
-                maxWidth="md"
+            <DialogTitle id="form-dialog-title" sx={{
+                position: 'sticky',
+                top: 0,
+                backgroundColor: 'background.paper',
+                zIndex: 1000
+            }}
             >
-                <DialogTitle id="form-dialog-title" sx={{
-                    position: 'sticky',
-                    top: 0,
-                    backgroundColor: 'background.paper',
-                    zIndex: 1000
-                }}
+                {translate('update.title')}
+                <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}>
+                    <DialogCloseButton onClose={handleClose} />
+                </Box>
+            </DialogTitle>
+            <DialogContent sx={{ mt: 2 }}>
+                <EditBase
+                    id={record?.id}
+                    resource="asnOrderItem"
+                    mutationMode={EDIT_MODE}
+                    actions={<CustomerTopToolBar />}
                 >
-                    {translate('update.title')}
-                    <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}>
-                        <DialogCloseButton onClose={handleClose} />
-                    </Box>
-                </DialogTitle>
-                <DialogContent sx={{ mt: 2 }}>
                     <Form
                         shouldUnregister
                         warnWhenUnsavedChanges
@@ -190,9 +190,9 @@
                             </Toolbar>
                         </DialogActions>
                     </Form>
-                </DialogContent>
-            </Dialog>
-        </EditBase >
+                </EditBase >
+            </DialogContent>
+        </Dialog>
     )
 }
 
diff --git a/rsf-admin/src/page/orders/asnOrder/AsnOrderItemList.jsx b/rsf-admin/src/page/orders/asnOrder/AsnOrderItemList.jsx
index 085e065..ef8db15 100644
--- a/rsf-admin/src/page/orders/asnOrder/AsnOrderItemList.jsx
+++ b/rsf-admin/src/page/orders/asnOrder/AsnOrderItemList.jsx
@@ -102,7 +102,7 @@
   const [drawerVal, setDrawerVal] = useState(false);
   const [select, setSelect] = useState({});
   const asnId = useGetRecordId();
-  const { data: dicts, isPending, error } = useGetOne('asnOrder', { id: asnId }); const creatCode = () => { };
+  const { data: dicts, isPending, error } = useGetOne('asnOrder', { id: asnId });
 
   return (
     <>
diff --git a/rsf-admin/src/page/orders/purchase/PurchaseCreate.jsx b/rsf-admin/src/page/orders/purchase/PurchaseCreate.jsx
new file mode 100644
index 0000000..f44ae47
--- /dev/null
+++ b/rsf-admin/src/page/orders/purchase/PurchaseCreate.jsx
@@ -0,0 +1,194 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import {
+    CreateBase,
+    useTranslate,
+    TextInput,
+    NumberInput,
+    BooleanInput,
+    DateInput,
+    SaveButton,
+    SelectInput,
+    ReferenceInput,
+    ReferenceArrayInput,
+    AutocompleteInput,
+    Toolbar,
+    required,
+    useDataProvider,
+    useNotify,
+    Form,
+    useCreateController,
+} from 'react-admin';
+import {
+    Dialog,
+    DialogActions,
+    DialogContent,
+    DialogTitle,
+    Stack,
+    Grid,
+    Box,
+} from '@mui/material';
+import DialogCloseButton from "../../components/DialogCloseButton";
+import StatusSelectInput from "../../components/StatusSelectInput";
+import MemoInput from "../../components/MemoInput";
+
+const PurchaseCreate = (props) => {
+    const { open, setOpen } = props;
+
+    const translate = useTranslate();
+    const notify = useNotify();
+
+    const handleClose = (event, reason) => {
+        if (reason !== "backdropClick") {
+            setOpen(false);
+        }
+    };
+
+    const handleSuccess = async (data) => {
+        setOpen(false);
+        notify('common.response.success');
+    };
+
+    const handleError = async (error) => {
+        notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } });
+    };
+
+    return (
+        <>
+            <CreateBase
+                record={{}}
+                transform={(data) => {
+                    return data;
+                }}
+                mutationOptions={{ onSuccess: handleSuccess, onError: handleError }}
+            >
+                <Dialog
+                    open={open}
+                    onClose={handleClose}
+                    aria-labelledby="form-dialog-title"
+                    fullWidth
+                    disableRestoreFocus
+                    maxWidth="md"   // 'xs' | 'sm' | 'md' | 'lg' | 'xl'
+                >
+                    <Form>
+                        <DialogTitle id="form-dialog-title" sx={{
+                            position: 'sticky',
+                            top: 0,
+                            backgroundColor: 'background.paper',
+                            zIndex: 1000
+                        }}
+                        >
+                            {translate('create.title')}
+                            <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}>
+                                <DialogCloseButton onClose={handleClose} />
+                            </Box>
+                        </DialogTitle>
+                        <DialogContent sx={{ mt: 2 }}>
+                            <Grid container rowSpacing={2} columnSpacing={2}>
+                                {/* <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.purchase.code"
+                                        source="code"
+                                        parse={v => v}
+                                        autoFocus
+                                    />
+                                </Grid> */}
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.purchase.type"
+                                        source="type"
+                                        parse={v => v}
+                                        validate={required()}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.purchase.source"
+                                        source="source"
+                                        parse={v => v}
+                                        validate={required()}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <DateInput
+                                        label="table.field.purchase.preArr"
+                                        source="preArr"
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <NumberInput
+                                        label="table.field.purchase.anfme"
+                                        source="anfme"
+                                        validate={required()}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <NumberInput
+                                        label="table.field.purchase.qty"
+                                        source="qty"
+                                        validate={required()}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <NumberInput
+                                        label="table.field.purchase.workQty"
+                                        source="workQty"
+                                        validate={required()}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.purchase.channel"
+                                        source="channel"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.purchase.platCode"
+                                        source="platCode"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <DateInput
+                                        label="table.field.purchase.startTime"
+                                        source="startTime"
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <DateInput
+                                        label="table.field.purchase.endTime"
+                                        source="endTime"
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.purchase.project"
+                                        source="project"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <StatusSelectInput />
+                                </Grid>
+                                <Grid item xs={12} display="flex" gap={1}>
+                                    <Stack direction="column" spacing={1} width={'100%'}>
+                                        <MemoInput />
+                                    </Stack>
+                                </Grid>
+                            </Grid>
+                        </DialogContent>
+                        <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
+                            <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }}  >
+                                <SaveButton />
+                            </Toolbar>
+                        </DialogActions>
+                    </Form>
+                </Dialog>
+            </CreateBase>
+        </>
+    )
+}
+
+export default PurchaseCreate;
diff --git a/rsf-admin/src/page/orders/purchase/PurchaseEdit.jsx b/rsf-admin/src/page/orders/purchase/PurchaseEdit.jsx
new file mode 100644
index 0000000..759b842
--- /dev/null
+++ b/rsf-admin/src/page/orders/purchase/PurchaseEdit.jsx
@@ -0,0 +1,152 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import {
+    Edit,
+    SimpleForm,
+    FormDataConsumer,
+    useTranslate,
+    TextInput,
+    NumberInput,
+    BooleanInput,
+    DateInput,
+    SelectInput,
+    ReferenceInput,
+    ReferenceArrayInput,
+    AutocompleteInput,
+    SaveButton,
+    Toolbar,
+    Labeled,
+    NumberField,
+    required,
+    useRecordContext,
+    DeleteButton,
+} from 'react-admin';
+import { useWatch, useFormContext } from "react-hook-form";
+import { Stack, Grid, Box, Typography } from '@mui/material';
+import * as Common from '@/utils/common';
+import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting';
+import EditBaseAside from "../../components/EditBaseAside";
+import CustomerTopToolBar from "../../components/EditTopToolBar";
+import MemoInput from "../../components/MemoInput";
+import StatusSelectInput from "../../components/StatusSelectInput";
+import PurchaseItemList from "./PurchaseItemList";
+
+const FormToolbar = () => {
+    const { getValues } = useFormContext();
+    return (
+        <Toolbar sx={{ justifyContent: 'end' }}>
+            <SaveButton />
+            <DeleteButton mutationMode="optimistic" />
+        </Toolbar>
+    )
+}
+
+const PurchaseEdit = () => {
+    const translate = useTranslate();
+
+    return (
+        <>
+            <Edit
+                redirect="list"
+                mutationMode={EDIT_MODE}
+                actions={<CustomerTopToolBar />}
+                aside={<EditBaseAside />}
+            >
+                <SimpleForm
+                    shouldUnregister
+                    warnWhenUnsavedChanges
+                    toolbar={<FormToolbar />}
+                    mode="onTouched"
+                    defaultValues={{}}
+                // validate={(values) => { }}
+                >
+                    <Grid container width={{ xs: '100%', xl: '80%' }} rowSpacing={3} columnSpacing={3}>
+                        <Grid item xs={18} md={10}>
+                            <Typography variant="h6" gutterBottom>
+                                {translate('common.edit.title.main')}
+                            </Typography>
+                            {/* <Stack direction='row' gap={2}>
+                            <TextInput
+                                label="table.field.purchase.code"
+                                source="code"
+                                parse={v => v}
+                                autoFocus
+                            />
+                        </Stack> */}
+                            <Stack direction='row' gap={2}>
+                                <TextInput
+                                    label="table.field.purchase.type"
+                                    source="type$"
+                                    parse={v => v}
+                                    validate={required()}
+                                />
+                                <TextInput
+                                    label="table.field.purchase.source"
+                                    source="source"
+                                    parse={v => v}
+                                    validate={required()}
+                                />
+                                <DateInput
+                                    label="table.field.purchase.preArr"
+                                    source="preArr"
+                                />
+                                <NumberInput
+                                    label="table.field.purchase.anfme"
+                                    source="anfme"
+                                    validate={required()}
+                                />
+                            </Stack>
+                            <Stack direction='row' gap={2}>
+                                <NumberInput
+                                    label="table.field.purchase.qty"
+                                    source="qty"
+                                    validate={required()}
+                                />
+                                <NumberInput
+                                    label="table.field.purchase.workQty"
+                                    source="workQty"
+                                    validate={required()}
+                                />
+                                <TextInput
+                                    label="table.field.purchase.channel"
+                                    source="channel"
+                                    parse={v => v}
+                                />
+                                <TextInput
+                                    label="table.field.purchase.platCode"
+                                    source="platCode"
+                                    parse={v => v}
+                                />
+                            </Stack>
+                            <Stack direction='row' gap={2}>
+                            <DateInput
+                                    label="table.field.purchase.startTime"
+                                    source="startTime"
+                                />
+                                <DateInput
+                                    label="table.field.purchase.endTime"
+                                    source="endTime"
+                                />
+                                <TextInput
+                                    label="table.field.purchase.project"
+                                    source="project"
+                                    parse={v => v}
+                                />
+                            </Stack>
+                        </Grid>
+                        <Grid item xs={6} md={2}>
+                            <Typography variant="h6" gutterBottom>
+                                {translate('common.edit.title.common')}
+                            </Typography>
+                            <StatusSelectInput />
+                            <Box mt="2em" />
+                            <MemoInput />
+                        </Grid>
+                    </Grid>
+                </SimpleForm>
+            </Edit >
+            <PurchaseItemList />                            
+        </>
+    )
+}
+
+export default PurchaseEdit;
diff --git a/rsf-admin/src/page/orders/purchase/PurchaseItemCreate.jsx b/rsf-admin/src/page/orders/purchase/PurchaseItemCreate.jsx
new file mode 100644
index 0000000..4afa238
--- /dev/null
+++ b/rsf-admin/src/page/orders/purchase/PurchaseItemCreate.jsx
@@ -0,0 +1,201 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import {
+    CreateBase,
+    useTranslate,
+    TextInput,
+    NumberInput,
+    BooleanInput,
+    DateInput,
+    SaveButton,
+    SelectInput,
+    ReferenceInput,
+    ReferenceArrayInput,
+    AutocompleteInput,
+    Toolbar,
+    required,
+    useDataProvider,
+    useNotify,
+    Form,
+    useCreateController,
+} from 'react-admin';
+import {
+    Dialog,
+    DialogActions,
+    DialogContent,
+    DialogTitle,
+    Stack,
+    Grid,
+    Box,
+} from '@mui/material';
+import DialogCloseButton from "../../components/DialogCloseButton";
+import StatusSelectInput from "../../components/StatusSelectInput";
+import MemoInput from "../../components/MemoInput";
+
+const PurchaseItemCreate = (props) => {
+    const { open, setOpen, row } = props;
+
+    const translate = useTranslate();
+    const notify = useNotify();
+
+    const handleClose = (event, reason) => {
+        if (reason !== "backdropClick") {
+            setOpen(false);
+        }
+    };
+
+    const handleSuccess = async (data) => {
+        setOpen(false);
+        notify('common.response.success');
+    };
+
+    const handleError = async (error) => {
+        notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } });
+    };
+
+    return (
+        <>
+            <CreateBase
+                record={{}}
+                transform={(data) => {
+                    return data;
+                }}
+                mutationOptions={{ onSuccess: handleSuccess, onError: handleError }}
+            >
+                <Dialog
+                    open={open}
+                    onClose={handleClose}
+                    aria-labelledby="form-dialog-title"
+                    fullWidth
+                    disableRestoreFocus
+                    maxWidth="md"   // 'xs' | 'sm' | 'md' | 'lg' | 'xl'
+                >
+                    <Form>
+                        <DialogTitle id="form-dialog-title" sx={{
+                            position: 'sticky',
+                            top: 0,
+                            backgroundColor: 'background.paper',
+                            zIndex: 1000
+                        }}
+                        >
+                            {translate('create.title')}
+                            <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}>
+                                <DialogCloseButton onClose={handleClose} />
+                            </Box>
+                        </DialogTitle>
+                        <DialogContent sx={{ mt: 2 }}>
+                            <Grid container rowSpacing={2} columnSpacing={2}>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <NumberInput
+                                        label="table.field.purchaseItem.purchaseId"
+                                        source="purchaseId"
+                                        defaultValue={row.poId}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.purchaseItem.platItemId"
+                                        source="platItemId"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.purchaseItem.matnrCode"
+                                        source="matnrCode"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.purchaseItem.matnrName"
+                                        source="matnrName"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.purchaseItem.unit"
+                                        source="unit"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <NumberInput
+                                        label="table.field.purchaseItem.anfme"
+                                        source="anfme"
+                                        validate={required()}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <NumberInput
+                                        label="table.field.purchaseItem.qty"
+                                        source="qty"
+                                        validate={required()}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <NumberInput
+                                        label="table.field.purchaseItem.nromQty"
+                                        source="nromQty"
+                                        validate={required()}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <NumberInput
+                                        label="table.field.purchaseItem.asnQty"
+                                        source="asnQty"
+                                        validate={required()}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <NumberInput
+                                        label="table.field.purchaseItem.printQty"
+                                        source="printQty"
+                                        validate={required()}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.purchaseItem.splrName"
+                                        source="splrName"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.purchaseItem.splrCode"
+                                        source="splrCode"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <TextInput
+                                        label="table.field.purchaseItem.splrBatch"
+                                        source="splrBatch"
+                                        parse={v => v}
+                                    />
+                                </Grid>
+
+                                <Grid item xs={6} display="flex" gap={1}>
+                                    <StatusSelectInput />
+                                </Grid>
+                                <Grid item xs={12} display="flex" gap={1}>
+                                    <Stack direction="column" spacing={1} width={'100%'}>
+                                        <MemoInput />
+                                    </Stack>
+                                </Grid>
+                            </Grid>
+                        </DialogContent>
+                        <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
+                            <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }}  >
+                                <SaveButton />
+                            </Toolbar>
+                        </DialogActions>
+                    </Form>
+                </Dialog>
+            </CreateBase>
+        </>
+    )
+}
+
+export default PurchaseItemCreate;
diff --git a/rsf-admin/src/page/orders/purchase/PurchaseItemEdit.jsx b/rsf-admin/src/page/orders/purchase/PurchaseItemEdit.jsx
new file mode 100644
index 0000000..be298d4
--- /dev/null
+++ b/rsf-admin/src/page/orders/purchase/PurchaseItemEdit.jsx
@@ -0,0 +1,198 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import {
+    Edit,
+    SimpleForm,
+    FormDataConsumer,
+    useTranslate,
+    TextInput,
+    NumberInput,
+    BooleanInput,
+    DateInput,
+    SelectInput,
+    ReferenceInput,
+    ReferenceArrayInput,
+    AutocompleteInput,
+    SaveButton,
+    Toolbar,
+    Labeled,
+    NumberField,
+    required,
+    useGetOne,
+    useRecordContext,
+    DeleteButton,
+    Form,
+    EditBase,
+} from 'react-admin';
+import { useWatch, useFormContext } from "react-hook-form";
+import { Stack, Grid, Box, Typography, Dialog, DialogActions, DialogContent, DialogTitle } from '@mui/material';
+import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting';
+import CustomerTopToolBar from "../../components/EditTopToolBar";
+import DialogCloseButton from "../../components/DialogCloseButton";
+import StatusSelectInput from "../../components/StatusSelectInput";
+import MemoInput from "../../components/MemoInput";
+
+
+const FormToolbar = () => {
+    const { getValues } = useFormContext();
+
+    return (
+        <Toolbar sx={{ justifyContent: 'space-between' }}>
+            <SaveButton />
+            <DeleteButton mutationMode="optimistic" />
+        </Toolbar>
+    )
+}
+
+const PurchaseItemEdit = (props) => {
+    const { open, setOpen, record } = props;
+    const translate = useTranslate();
+    const handleClose = (event, reason) => {
+        if (reason !== "backdropClick") {
+            setOpen(false);
+        }
+    };
+    const { data, isPending, } = useGetOne('purchaseItem', { id: record?.id });
+    if (data == null || data == undefined) { return }
+
+    return (
+        <>
+            <Dialog
+                open={open}
+                onClose={handleClose}
+                aria-labelledby="form-dialog-title"
+                fullWidth
+                disableRestoreFocus
+                maxWidth="md"
+            >
+                <DialogTitle id="form-dialog-title" sx={{
+                    position: 'sticky',
+                    top: 0,
+                    backgroundColor: 'background.paper',
+                    zIndex: 1000
+                }}
+                >
+                    {translate('update.title')}
+                    <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}>
+                        <DialogCloseButton onClose={handleClose} />
+                    </Box>
+                </DialogTitle>
+                <EditBase
+                    resource="purchaseItem"
+                    mutationMode={EDIT_MODE}
+                    actions={<CustomerTopToolBar />}
+                >
+                    <Form
+                        shouldUnregister
+                        warnWhenUnsavedChanges
+                        toolbar={<FormToolbar />}
+                        mode="onTouched"
+                        defaultValues={{}}
+                    >
+                        <DialogContent sx={{ mt: 2 }}>
+
+                            <Grid container width={{ xs: '100%', xl: '100%' }} rowSpacing={3} columnSpacing={3}>
+                                <Grid item xs={12} md={8} gap={2}>
+                                    <Typography variant="h6" gutterBottom>
+                                        {translate('common.edit.title.main')}
+                                    </Typography>
+                                    <Stack direction='row' gap={2}>
+                                        <NumberInput
+                                            label="table.field.purchaseItem.purchaseId"
+                                            source="purchaseId"
+                                            defaultValue={record?.id}
+                                        />
+                                        <TextInput
+                                            label="table.field.purchaseItem.platItemId"
+                                            source="platItemId"
+                                            parse={v => v}
+                                        />
+                                        <TextInput
+                                            label="table.field.purchaseItem.matnrCode"
+                                            source="matnrCode"
+                                            parse={v => v}
+                                        />
+                                    </Stack>
+                                    <Stack direction='row' gap={2}>
+                                        <TextInput
+                                            label="table.field.purchaseItem.matnrName"
+                                            source="matnrName"
+                                            parse={v => v}
+                                        />
+                                        <TextInput
+                                            label="table.field.purchaseItem.unit"
+                                            source="unit"
+                                            parse={v => v}
+                                        />
+                                        <NumberInput
+                                            label="table.field.purchaseItem.anfme"
+                                            source="anfme"
+                                            validate={required()}
+                                        />
+                                    </Stack>
+                                    <Stack direction='row' gap={2}>
+                                        <NumberInput
+                                            label="table.field.purchaseItem.qty"
+                                            source="qty"
+                                            validate={required()}
+                                        />
+                                        <NumberInput
+                                            label="table.field.purchaseItem.nromQty"
+                                            source="nromQty"
+                                            validate={required()}
+                                        />
+                                        <NumberInput
+                                            label="table.field.purchaseItem.asnQty"
+                                            source="asnQty"
+                                            validate={required()}
+                                        />
+                                    </Stack>
+                                    <Stack direction='row' gap={2}>
+                                        <NumberInput
+                                            label="table.field.purchaseItem.printQty"
+                                            source="printQty"
+                                            validate={required()}
+                                        />
+                                        <TextInput
+                                            label="table.field.purchaseItem.splrName"
+                                            source="splrName"
+                                            parse={v => v}
+                                        />
+                                        <TextInput
+                                            label="table.field.purchaseItem.splrCode"
+                                            source="splrCode"
+                                            parse={v => v}
+                                        />
+                                        <TextInput
+                                            label="table.field.purchaseItem.splrBatch"
+                                            source="splrBatch"
+                                            parse={v => v}
+                                        />
+                                    </Stack>
+                                </Grid>
+                                <Grid item xs={12} md={4} >
+                                    <Typography variant="h6" gutterBottom>
+                                        {translate('common.edit.title.common')}
+                                    </Typography>
+                                    <StatusSelectInput />
+                                    <Box mt="2em" />
+                                    <MemoInput />
+                                </Grid>
+                            </Grid>
+                        </DialogContent>
+                        <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
+                            <Toolbar sx={{ width: '100%', justifyContent: 'end' }}  >
+                                <SaveButton type="button" mutationOptions={{
+                                    onSuccess: () => {
+                                        setOpen(false)
+                                    }
+                                }} />
+                            </Toolbar>
+                        </DialogActions>
+                    </Form>
+                </EditBase >
+            </Dialog>
+        </>
+    )
+}
+
+export default PurchaseItemEdit;
diff --git a/rsf-admin/src/page/orders/purchase/PurchaseItemList.jsx b/rsf-admin/src/page/orders/purchase/PurchaseItemList.jsx
new file mode 100644
index 0000000..13222c9
--- /dev/null
+++ b/rsf-admin/src/page/orders/purchase/PurchaseItemList.jsx
@@ -0,0 +1,171 @@
+import React, { useState, useRef, useEffect, useMemo, useCallback } from "react";
+import {
+  List,
+  DatagridConfigurable,
+  SearchInput,
+  TopToolbar,
+  SelectColumnsButton,
+  EditButton,
+  FilterButton,
+  BulkDeleteButton,
+  WrapperField,
+  useTranslate,
+  TextField,
+  NumberField,
+  DateField,
+  BooleanField,
+  TextInput,
+  SelectInput,
+  NumberInput,
+  DeleteButton,
+  useGetRecordId,
+  Button,
+  useGetOne
+} from 'react-admin';
+import { Box, Typography, Card, Stack } from '@mui/material';
+import { styled } from '@mui/material/styles';
+import PurchaseItemCreate from "./PurchaseItemCreate";
+import EmptyData from "../../components/EmptyData";
+import MyCreateButton from "../../components/MyCreateButton";
+import MyExportButton from '../../components/MyExportButton';
+import PageDrawer from "../../components/PageDrawer";
+import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
+import PurchaseItemEdit from "./PurchaseItemEdit";
+
+const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
+  '& .css-1vooibu-MuiSvgIcon-root': {
+    height: '.9em'
+  },
+  '& .RaDatagrid-row': {
+    cursor: 'auto'
+  },
+  '& .column-name': {
+  },
+  '& .opt': {
+    width: 200
+  },
+}));
+
+const filters = [
+  <SearchInput source="condition" alwaysOn />,
+  <NumberInput source="purchaseId" label="table.field.purchaseItem.purchaseId" />,
+  <TextInput source="platItemId" label="table.field.purchaseItem.platItemId" />,
+  <TextInput source="matnrCode" label="table.field.purchaseItem.matnrCode" />,
+  <TextInput source="matnrName" label="table.field.purchaseItem.matnrName" />,
+  <TextInput source="unit" label="table.field.purchaseItem.unit" />,
+  <NumberInput source="anfme" label="table.field.purchaseItem.anfme" />,
+  <NumberInput source="qty" label="table.field.purchaseItem.qty" />,
+  <NumberInput source="nromQty" label="table.field.purchaseItem.nromQty" />,
+  <NumberInput source="asnQty" label="table.field.purchaseItem.asnQty" />,
+  <NumberInput source="printQty" label="table.field.purchaseItem.printQty" />,
+  <TextInput source="splrName" label="table.field.purchaseItem.splrName" />,
+  <TextInput source="splrCode" label="table.field.purchaseItem.splrCode" />,
+  <TextInput source="splrBatch" label="table.field.purchaseItem.splrBatch" />,
+  <TextInput label="common.field.memo" source="memo" />,
+  <SelectInput
+    label="common.field.status"
+    source="status"
+    choices={[
+      { id: '1', name: 'common.enums.statusTrue' },
+      { id: '0', name: 'common.enums.statusFalse' },
+    ]}
+    resettable
+  />,
+]
+
+const PurchaseItemList = () => {
+  const translate = useTranslate();
+  const [createDialog, setCreateDialog] = useState(false);
+  const [drawerVal, setDrawerVal] = useState(false);
+  const [editDialog, setEditDialog] = useState(false);
+  const [select, setSelect] = useState({});
+  const poId = useGetRecordId();
+  const { data: purchase, isPending, error } = useGetOne('purchase', { id: poId });
+
+  return (
+    <>
+      <Box display="flex">
+        <List
+          resource="purchaseItem"
+          sx={{
+            flexGrow: 1,
+            transition: (theme) =>
+              theme.transitions.create(['all'], {
+                duration: theme.transitions.duration.enteringScreen,
+              }),
+            marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+          }}
+          title={"menu.purchaseItem"}
+          empty={false}
+          filters={filters}
+          filter={{ purchaseId: poId }}
+          sort={{ field: "create_time", order: "desc" }}
+          actions={(
+            <TopToolbar>
+              <FilterButton />
+              <MyCreateButton onClick={() => { setCreateDialog(true) }} />
+              <SelectColumnsButton preferenceKey='purchaseItem' />
+              <MyExportButton />
+            </TopToolbar>
+          )}
+          perPage={DEFAULT_PAGE_SIZE}
+        >
+          <StyledDatagrid
+            preferenceKey='purchaseItem'
+            bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
+            rowClick={(id, resource, record) => {
+              setSelect(record)
+              setEditDialog(true)
+            }}
+            omit={['id', 'createTime', 'purchaseId', 'platItemId', 'createBy', 'memo']}
+          >
+            <NumberField source="id" />
+            <NumberField source="purchaseId" label="table.field.purchaseItem.purchaseId" />
+            <TextField source="platItemId" label="table.field.purchaseItem.platItemId" />
+            <TextField source="matnrCode" label="table.field.purchaseItem.matnrCode" />
+            <TextField source="matnrName" label="table.field.purchaseItem.matnrName" />
+            <TextField source="unit" label="table.field.purchaseItem.unit" />
+            <NumberField source="anfme" label="table.field.purchaseItem.anfme" />
+            <NumberField source="qty" label="table.field.purchaseItem.qty" />
+            <NumberField source="nromQty" label="table.field.purchaseItem.nromQty" />
+            <NumberField source="asnQty" label="table.field.purchaseItem.asnQty" />
+            <NumberField source="printQty" label="table.field.purchaseItem.printQty" />
+            <TextField source="splrName" label="table.field.purchaseItem.splrName" />
+            <TextField source="splrCode" label="table.field.purchaseItem.splrCode" />
+            <TextField source="splrBatch" label="table.field.purchaseItem.splrBatch" />
+            <TextField source="updateBy$" label="common.field.updateBy" reference="user" />
+            <DateField source="updateTime" label="common.field.updateTime" showTime />
+            <TextField source="createBy$" label="common.field.createBy" />
+            <DateField source="createTime" label="common.field.createTime" showTime />
+            <BooleanField source="statusBool" label="common.field.status" sortable={false} />
+            <TextField source="memo" label="common.field.memo" sortable={false} />
+            <WrapperField cellClassName="opt" label="common.field.opt">
+              <Button label="ra.action.edit" onClick={(id, resource, record) => {
+                setEditDialog(true)
+                setSelect(record)
+              }} />
+              <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} />
+            </WrapperField>
+          </StyledDatagrid>
+        </List>
+        <PurchaseItemEdit
+          open={editDialog}
+          setOpen={setEditDialog}
+          record={select}
+        />
+        <PurchaseItemCreate
+          open={createDialog}
+          setOpen={setCreateDialog}
+          row={{ poId }}
+        />
+        <PageDrawer
+          title='PurchaseItem Detail'
+          drawerVal={drawerVal}
+          setDrawerVal={setDrawerVal}
+        >
+        </PageDrawer>
+      </Box></>
+  )
+}
+
+export default PurchaseItemList;
diff --git a/rsf-admin/src/page/orders/purchase/PurchaseList.jsx b/rsf-admin/src/page/orders/purchase/PurchaseList.jsx
new file mode 100644
index 0000000..3cbbd27
--- /dev/null
+++ b/rsf-admin/src/page/orders/purchase/PurchaseList.jsx
@@ -0,0 +1,170 @@
+import React, { useState, useRef, useEffect, useMemo, useCallback } from "react";
+import { useNavigate } from 'react-router-dom';
+import {
+  List,
+  DatagridConfigurable,
+  SearchInput,
+  TopToolbar,
+  SelectColumnsButton,
+  EditButton,
+  FilterButton,
+  CreateButton,
+  ExportButton,
+  BulkDeleteButton,
+  WrapperField,
+  useRecordContext,
+  useTranslate,
+  useNotify,
+  useListContext,
+  FunctionField,
+  TextField,
+  NumberField,
+  DateField,
+  BooleanField,
+  ReferenceField,
+  TextInput,
+  DateTimeInput,
+  DateInput,
+  SelectInput,
+  NumberInput,
+  ReferenceInput,
+  ReferenceArrayInput,
+  AutocompleteInput,
+  DeleteButton,
+} from 'react-admin';
+import { Box, Typography, Card, Stack } from '@mui/material';
+import { styled } from '@mui/material/styles';
+import PurchaseCreate from "./PurchaseCreate";
+import PurchasePanel from "./PurchasePanel";
+import EmptyData from "../../components/EmptyData";
+import MyCreateButton from "../../components/MyCreateButton";
+import MyExportButton from '../../components/MyExportButton';
+import PageDrawer from "../../components/PageDrawer";
+import MyField from "../../components/MyField";
+import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
+import * as Common from '@/utils/common';
+
+const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
+  '& .css-1vooibu-MuiSvgIcon-root': {
+    height: '.9em'
+  },
+  '& .RaDatagrid-row': {
+    cursor: 'auto'
+  },
+  '& .column-name': {
+  },
+  '& .opt': {
+    width: 200
+  },
+}));
+
+const filters = [
+  <SearchInput source="condition" alwaysOn />,
+  <TextInput source="code" label="table.field.purchase.code" />,
+  <TextInput source="type" label="table.field.purchase.type" />,
+  <TextInput source="source" label="table.field.purchase.source" />,
+  <DateInput source="preArr" label="table.field.purchase.preArr" />,
+  <NumberInput source="anfme" label="table.field.purchase.anfme" />,
+  <NumberInput source="qty" label="table.field.purchase.qty" />,
+  <NumberInput source="workQty" label="table.field.purchase.workQty" />,
+  <TextInput source="channel" label="table.field.purchase.channel" />,
+  <TextInput source="platCode" label="table.field.purchase.platCode" />,
+  <DateInput source="startTime" label="table.field.purchase.startTime" />,
+  <DateInput source="endTime" label="table.field.purchase.endTime" />,
+  <TextInput source="project" label="table.field.purchase.project" />,
+  <TextInput label="common.field.memo" source="memo" />,
+  <SelectInput
+    label="common.field.status"
+    source="status"
+    choices={[
+      { id: '1', name: 'common.enums.statusTrue' },
+      { id: '0', name: 'common.enums.statusFalse' },
+    ]}
+    resettable
+  />,
+]
+
+const PurchaseList = () => {
+  const translate = useTranslate();
+
+  const [createDialog, setCreateDialog] = useState(false);
+  const [drawerVal, setDrawerVal] = useState(false);
+
+  const navigate = useNavigate();
+  const assign = (record) => {
+    navigate(`/purchaseItem?poId=${record.id}`);
+  };
+
+  return (
+    <Box display="flex">
+      <List
+        sx={{
+          flexGrow: 1,
+          transition: (theme) =>
+            theme.transitions.create(['all'], {
+              duration: theme.transitions.duration.enteringScreen,
+            }),
+          marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
+        }}
+        title={"menu.purchase"}
+        empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
+        filters={filters}
+        sort={{ field: "create_time", order: "desc" }}
+        actions={(
+          <TopToolbar>
+            <FilterButton />
+            <MyCreateButton onClick={() => { setCreateDialog(true) }} />
+            <SelectColumnsButton preferenceKey='purchase' />
+            <MyExportButton />
+          </TopToolbar>
+        )}
+        perPage={DEFAULT_PAGE_SIZE}
+      >
+        <StyledDatagrid
+          preferenceKey='purchase'
+          bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
+          rowClick={'edit'}
+          expand={false}
+          expandSingle={true}
+          omit={['id', 'createTime', 'createBy', 'memo', 'preArr', 'channel','startTime','workQty', 'endTime']}
+        >
+          <NumberField source="id" />
+          <TextField source="code" label="table.field.purchase.code" />
+          <TextField source="type$" label="table.field.purchase.type" />
+          <TextField source="source" label="table.field.purchase.source" />
+          <DateField source="preArr" label="table.field.purchase.preArr" showTime />
+          <NumberField source="anfme" label="table.field.purchase.anfme" />
+          <NumberField source="qty" label="table.field.purchase.qty" />
+          <NumberField source="workQty" label="table.field.purchase.workQty" />
+          <TextField source="channel" label="table.field.purchase.channel" />
+          <TextField source="platCode" label="table.field.purchase.platCode" />
+          <DateField source="startTime" label="table.field.purchase.startTime" showTime />
+          <DateField source="endTime" label="table.field.purchase.endTime" showTime />
+          <TextField source="project" label="table.field.purchase.project" />
+          <TextField source="updateBy$" label="common.field.updateBy"  />
+          <DateField source="updateTime" label="common.field.updateTime" showTime />
+          <TextField source="createBy$" label="common.field.createBy"  />
+          <DateField source="createTime" label="common.field.createTime" showTime />
+          <BooleanField source="statusBool" label="common.field.status" sortable={false} />
+          <TextField source="memo" label="common.field.memo" sortable={false} />
+          <WrapperField cellClassName="opt" label="common.field.opt">
+            <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} />
+            <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} />
+          </WrapperField>
+        </StyledDatagrid>
+      </List>
+      <PurchaseCreate
+        open={createDialog}
+        setOpen={setCreateDialog}
+      />
+      <PageDrawer
+        title='Purchase Detail'
+        drawerVal={drawerVal}
+        setDrawerVal={setDrawerVal}
+      >
+      </PageDrawer>
+    </Box>
+  )
+}
+
+export default PurchaseList;
diff --git a/rsf-admin/src/page/orders/purchase/PurchasePanel.jsx b/rsf-admin/src/page/orders/purchase/PurchasePanel.jsx
new file mode 100644
index 0000000..0793a58
--- /dev/null
+++ b/rsf-admin/src/page/orders/purchase/PurchasePanel.jsx
@@ -0,0 +1,182 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import { Box, Card, CardContent, Grid, Typography, Tooltip, Paper, TableContainer, Table, TableBody, TableCell, TableHead, TableRow } from '@mui/material';
+import {
+    useTranslate,
+    useRecordContext,
+    useNotify
+} from 'react-admin';
+import PanelTypography from "../../components/PanelTypography";
+import * as Common from '@/utils/common'
+import { styled } from "@mui/material/styles";
+import request from '@/utils/request';
+const PurchasePanel = () => {
+    const record = useRecordContext();
+    if (!record) return null;
+    const translate = useTranslate();
+    const notify = useNotify();
+    const [rows, setRows] = useState([]);
+    const poId = record.id;
+
+    useEffect(() => {
+        http();
+    }, [poId]);
+
+    const http = async () => {
+        const res = await request.post('/purchaseItem/page', { purchaseId: poId });
+        if (res?.data?.code === 200) {
+            setRows(res.data.data.records)
+        } else {
+            notify(res.data.msg);
+        }
+    }
+
+    const StyledTable = styled(TableRow)(({ theme }) => ({
+        "& .MuiButtonBase-root.": {
+            padding: "0px 0px",
+        },
+    }));
+
+    const StyledTableRow = styled(TableRow)(({ theme }) => ({
+        "& .MuiButtonBase-root.": {
+            padding: "0px 0px",
+        },
+    }));
+
+    const StyledTableCell = styled(TableCell)(({ theme }) => ({
+        "& .MuiButtonBase-root": {
+            padding: "0px 0px",
+        },
+        overflow: "hidden",
+        textOverflow: "ellipsis",
+        whiteSpace: "nowrap",
+        maxWidth: 600,
+    }));
+
+    const columns = [
+        {
+            id: 'purchaseId',
+            label: 'table.field.purchaseItem.purchaseId',
+            minWidth: 100
+        },
+        {
+            id: 'platItemId',
+            label: 'table.field.purchaseItem.platItemId',
+            minWidth: 100
+        },
+        {
+            id: 'matnrCode',
+            label: 'table.field.purchaseItem.matnrCode',
+            minWidth: 100
+        },
+        {
+            id: 'matnrName',
+            label: 'table.field.purchaseItem.matnrName',
+            minWidth: 100
+        },
+        {
+            id: 'unit',
+            label: 'table.field.purchaseItem.unit',
+            minWidth: 100
+        },
+        {
+            id: 'anfme',
+            label: 'table.field.purchaseItem.anfme',
+            minWidth: 100
+        },
+        {
+            id: 'qty',
+            label: 'table.field.purchaseItem.qty',
+            minWidth: 100
+        },
+        {
+            id: 'nromQty',
+            label: 'table.field.purchaseItem.nromQty',
+            minWidth: 100
+        },
+        {
+            id: 'asnQty',
+            label: 'table.field.purchaseItem.asnQty',
+            minWidth: 100
+        },
+        {
+            id: 'printQty',
+            label: 'table.field.purchaseItem.printQty',
+            minWidth: 100
+        },
+        {
+            id: 'splrName',
+            label: 'table.field.purchaseItem.splrName',
+            minWidth: 100
+        },
+        {
+            id: 'splrCode',
+            label: 'table.field.purchaseItem.splrCode',
+            minWidth: 100
+        },
+        {
+            id: 'splrBatch',
+            label: 'table.field.purchaseItem.splrBatch',
+            minWidth: 100
+        },
+        {
+            id: 'statusBool',
+            label: 'common.field.status',
+            minWidth: 100,
+            formatter: (value) => value ? 'Yes' : 'No'
+        },
+        {
+            id: 'memo',
+            label: 'common.field.memo',
+            minWidth: 100
+        }
+    ];
+
+
+    return (
+
+        <Box sx={{
+            position: 'relative',
+            padding: '5px 10px'
+        }}>
+            <TableContainer component={Paper} >
+                <Table size="small" >
+                    <TableHead>
+                        <StyledTableRow key={'head'}>
+                            {columns.map((column, idx) => {
+                                const value = column.label;
+                                return (
+                                    <>
+                                        <StyledTableCell
+                                            key={column.id}
+                                            align={column.align || "left"}
+                                        // style={{ paddingLeft: idx === 0 && (depth * 16 + 16) }}
+                                        >
+                                            {column.format ? column.format(value) : translate(value)}
+                                        </StyledTableCell>
+                                    </>
+                                );
+
+                            })}
+                        </StyledTableRow>
+                    </TableHead>
+
+                    <TableBody>
+                        {rows.map((row) => (
+                            <StyledTableRow key={row.id || Math.random()}>
+                                {columns.map((column) => (
+                                    <StyledTableCell key={column.id} >
+                                        {row[column.id]}
+                                    </StyledTableCell>
+                                ))}
+                            </StyledTableRow>
+                        ))}
+
+                    </TableBody>
+                </Table>
+            </TableContainer>
+        </Box>
+
+    );
+};
+
+export default PurchasePanel;
diff --git a/rsf-admin/src/page/orders/purchase/index.jsx b/rsf-admin/src/page/orders/purchase/index.jsx
new file mode 100644
index 0000000..a03738a
--- /dev/null
+++ b/rsf-admin/src/page/orders/purchase/index.jsx
@@ -0,0 +1,18 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import {
+    ListGuesser,
+    EditGuesser,
+    ShowGuesser,
+} from "react-admin";
+
+import PurchaseList from "./PurchaseList";
+import PurchaseEdit from "./PurchaseEdit";
+
+export default {
+    list: PurchaseList,
+    edit: PurchaseEdit,
+    show: ShowGuesser,
+    recordRepresentation: (record) => {
+        return `${record.id}`
+    }
+};

--
Gitblit v1.9.1