Merge branch 'dev' of http://47.97.1.152:5880/r/wms-master into dev
| | |
| | | VITE_BASE_IP=localhost |
| | | VITE_BASE_IP=192.168.4.24 |
| | | VITE_BASE_PORT=8080 |
| | |
| | | "@hello-pangea/dnd": "^16.3.0", |
| | | "@mui/icons-material": "^5.16.7", |
| | | "@mui/material": "^5.16.7", |
| | | "@mui/system": "^6.4.7", |
| | | "@mui/x-tree-view": "^7.16.0", |
| | | "@tweenjs/tween.js": "^21.0.0", |
| | | "axios": "^1.7.4", |
| | | "date-fns": "^3.6.0", |
| | | "framer-motion": "^12.4.10", |
| | | "lodash": "^4.17.21", |
| | | "motion": "^12.4.1", |
| | | "papaparse": "^5.4.1", |
| | | "pixi.js": "^7.4.0", |
| | | "prop-types": "^15.8.1", |
| | | "ra-i18n-polyglot": "^5.6.2", |
| | | "ra-language-english": "^5.6.2", |
| | | "react": "^18.3.0", |
| | | "react-admin": "^5.1.0", |
| | | "react-dom": "^18.3.0", |
| | | "react-hook-form": "^7.53.0", |
| | | "react-router": "^6.22.0", |
| | | "react-router-dom": "^6.26.1", |
| | | "react-syntax-highlighter": "^15.5.0", |
| | | "three": "^0.155.0", |
| | |
| | | import React, { useState, useRef, useEffect, useMemo } from "react"; |
| | | import { Route } from 'react-router-dom' |
| | | import { Route } from "react-router-dom"; |
| | | import { |
| | | Admin, |
| | | Resource, |
| | |
| | | StoreContextProvider, |
| | | resolveBrowserLocale, |
| | | } from "react-admin"; |
| | | import polyglotI18nProvider from 'ra-i18n-polyglot'; |
| | | import englishMessages from './i18n/en'; |
| | | import polyglotI18nProvider from "ra-i18n-polyglot"; |
| | | import englishMessages from "./i18n/en"; |
| | | import { Layout } from "./layout"; |
| | | import AuthProvider from "./config/authProvider"; |
| | | import DataProvider from "./config/dataProvider"; |
| | | import Dashboard from "./page/dashboard"; |
| | | import Settings from "./page/settings"; |
| | | import Login from "./page/login"; |
| | | import * as Common from './utils/common' |
| | | import { themes } from './themes/themes'; |
| | | import { SPA_NAME, SPA_VERSION, DEFAULT_THEME_NAME, DEFAULT_THEME_MODE, DATA_PROVIDER_SPRING } from "./config/setting"; |
| | | import * as Common from "./utils/common"; |
| | | import { themes } from "./themes/themes"; |
| | | import { |
| | | SPA_NAME, |
| | | SPA_VERSION, |
| | | DEFAULT_THEME_NAME, |
| | | DEFAULT_THEME_MODE, |
| | | DATA_PROVIDER_SPRING, |
| | | } from "./config/setting"; |
| | | import ResourceContent from "./page/ResourceContent"; |
| | | import { getSystemInfo } from '@/api/auth'; |
| | | import { getSystemInfo } from "@/api/auth"; |
| | | |
| | | const i18nProvider = polyglotI18nProvider( |
| | | locale => { |
| | | if (locale === 'zh') { |
| | | return import('./i18n/zh').then(messages => messages.default); |
| | | (locale) => { |
| | | if (locale === "zh") { |
| | | return import("./i18n/zh").then((messages) => messages.default); |
| | | } |
| | | // fallback |
| | | return englishMessages; |
| | | }, |
| | | // default |
| | | // 'en', |
| | | resolveBrowserLocale('en', { fullLocale: true }), |
| | | resolveBrowserLocale("en", { fullLocale: true }), |
| | | [ |
| | | { locale: 'en', name: 'English' }, |
| | | { locale: 'zh', name: '简体中文' }, |
| | | { locale: "en", name: "English" }, |
| | | { locale: "zh", name: "简体中文" }, |
| | | ], |
| | | { |
| | | // msg in console |
| | | allowMissing: true, |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | const store = localStorageStore(SPA_VERSION, SPA_NAME); |
| | | |
| | | const App = () => { |
| | | const [themeName] = useStore('themeName', DEFAULT_THEME_NAME); |
| | | const lightTheme = themes.find(theme => theme.name === themeName)?.light; |
| | | const darkTheme = themes.find(theme => theme.name === themeName)?.dark; |
| | | const [themeName] = useStore("themeName", DEFAULT_THEME_NAME); |
| | | const lightTheme = themes.find((theme) => theme.name === themeName)?.light; |
| | | const darkTheme = themes.find((theme) => theme.name === themeName)?.dark; |
| | | |
| | | useEffect(() => { |
| | | getSystemInfo().then(data => { |
| | | getSystemInfo().then((data) => { |
| | | localStorage.setItem("system", JSON.stringify(data)); |
| | | }) |
| | | }); |
| | | }, []); |
| | | |
| | | return ( |
| | |
| | | loginPage={Login} |
| | | dashboard={Dashboard} |
| | | > |
| | | {permissions => ( |
| | | {(permissions) => ( |
| | | <> |
| | | { |
| | | Common.extractNavMenus(permissions)?.map(node => { |
| | | return ( |
| | | <Resource |
| | | key={node.id} |
| | | name={node.component} |
| | | {...ResourceContent(node)} |
| | | /> |
| | | ) |
| | | }) |
| | | } |
| | | {Common.extractNavMenus(permissions)?.map((node) => { |
| | | return ( |
| | | <Resource |
| | | key={node.id} |
| | | name={node.component} |
| | | {...ResourceContent(node)} |
| | | /> |
| | | ); |
| | | })} |
| | | </> |
| | | )} |
| | | {/* CustomRoutes don't trigger checkAuth */} |
| | |
| | | </CustomRoutes> |
| | | </Admin> |
| | | </> |
| | | ) |
| | | ); |
| | | }; |
| | | |
| | | const AppWrapper = () => ( |
| | |
| | | </StoreContextProvider> |
| | | ); |
| | | |
| | | export default AppWrapper; |
| | | export default AppWrapper; |
| | |
| | | import request from '../utils/request'; |
| | | import * as Common from '../utils/common'; |
| | | import request from "../utils/request"; |
| | | import * as Common from "../utils/common"; |
| | | |
| | | const MyDataProvider = { |
| | | // *** https://marmelab.com/react-admin/DataProviderWriting.html *** |
| | | // *** https://marmelab.com/react-admin/DataProviderWriting.html *** |
| | | |
| | | // get a list of records based on sort, filter, and pagination |
| | | getList: async (resource, params) => { |
| | | console.log("getList", resource, params); |
| | | const _params = Common.integrateParams(params) |
| | | const res = await request.post(resource + '/page', _params); |
| | | const { code, msg, data } = res.data; |
| | | if (code === 200) { |
| | | return Promise.resolve({ |
| | | data: data.records, |
| | | total: data.total |
| | | }); |
| | | } |
| | | return Promise.reject(new Error(msg)); |
| | | }, |
| | | |
| | | // get a single record by id |
| | | getOne: async (resource, params) => { |
| | | console.log("getOne", resource, params); |
| | | const res = await request.get(resource + '/' + params.id); |
| | | const { code, msg, data } = res.data; |
| | | if (code === 200) { |
| | | return Promise.resolve({ |
| | | data: { |
| | | id: data.id, |
| | | ...data, |
| | | }, |
| | | }); |
| | | } |
| | | return Promise.reject(new Error(msg)); |
| | | }, |
| | | |
| | | // get a list of records based on an array of ids |
| | | getMany: async (resource, params) => { |
| | | console.log("getMany", resource, params); |
| | | const res = await request.post(resource + '/many/' + params.ids); |
| | | const { code, msg, data } = res.data; |
| | | if (code === 200) { |
| | | return Promise.resolve({ |
| | | data: data.map(item => ({ |
| | | id: item.id, |
| | | ...item, |
| | | })), |
| | | }); |
| | | } |
| | | return Promise.reject(new Error(msg)); |
| | | }, |
| | | |
| | | // get the records referenced to another record, e.g. comments for a post |
| | | getManyReference: async (resource, params) => { |
| | | console.log("getManyReference", resource, params); |
| | | |
| | | return Promise.resolve(); |
| | | }, |
| | | |
| | | // create a record |
| | | create: async (resource, params) => { |
| | | console.log("create", resource, params); |
| | | const res = await request.post(resource + '/save', params?.data); |
| | | const { code, msg, data } = res.data; |
| | | if (code === 200) { |
| | | return Promise.resolve({ |
| | | data: { |
| | | id: data.id |
| | | }, |
| | | }); |
| | | } |
| | | return Promise.reject(new Error(msg)); |
| | | }, |
| | | |
| | | // update a record based on a patch |
| | | update: async (resource, params) => { |
| | | console.log("update", resource, params); |
| | | const res = await request.post(resource + '/update', { id: params.id, ...params.data }); |
| | | const { code, msg, data } = res.data; |
| | | if (code === 200) { |
| | | return Promise.resolve({ |
| | | data: data, |
| | | }); |
| | | } |
| | | return Promise.reject(new Error(msg)); |
| | | }, |
| | | |
| | | // update a list of records based on an array of ids and a common patch |
| | | updateMany: async (resource, params) => { |
| | | console.log("updateMany", resource, params); |
| | | const res = await request.post( |
| | | resource + '/update/many' |
| | | , params.ids.map(id => ({ id, ...params.data })) |
| | | ); |
| | | const { code, msg, data } = res.data; |
| | | if (code === 200) { |
| | | return Promise.resolve({ |
| | | data: data, |
| | | }); |
| | | } |
| | | return Promise.reject(new Error(msg)); |
| | | }, |
| | | |
| | | // delete a record by id |
| | | delete: async (resource, params) => { |
| | | console.log("delete", resource, params); |
| | | const res = await request.post(resource + '/remove/' + [params.id]); |
| | | const { code, msg, data } = res.data; |
| | | if (code === 200) { |
| | | return Promise.resolve({ |
| | | data: { |
| | | id: params.id |
| | | }, |
| | | }); |
| | | } |
| | | return Promise.reject(new Error(msg)); |
| | | }, |
| | | |
| | | // delete a list of records based on an array of ids |
| | | deleteMany: async (resource, params) => { |
| | | console.log("deleteMany", resource, params); |
| | | const res = await request.post(resource + '/remove/' + params?.ids); |
| | | const { code, msg, data } = res.data; |
| | | if (code === 200) { |
| | | return Promise.resolve({ |
| | | data: data, |
| | | }); |
| | | } |
| | | return Promise.reject(new Error(msg)); |
| | | }, |
| | | |
| | | // export excel from all data |
| | | export: async (resource, params) => { |
| | | console.log("export", resource, params); |
| | | const _params = Common.integrateParams(params); |
| | | try { |
| | | const res = await request.post(`${resource}/export`, _params, { |
| | | responseType: 'blob', |
| | | }); |
| | | return res; |
| | | } catch (error) { |
| | | return Promise.reject(new Error(error)); |
| | | } |
| | | // get a list of records based on sort, filter, and pagination |
| | | getList: async (resource, params) => { |
| | | // console.log("getList", resource, params); |
| | | const _params = Common.integrateParams(params); |
| | | const res = await request.post(resource + "/page", _params); |
| | | const { code, msg, data } = res.data; |
| | | if (code === 200) { |
| | | return Promise.resolve({ |
| | | data: data.records, |
| | | total: data.total, |
| | | }); |
| | | } |
| | | } |
| | | return Promise.reject(new Error(msg)); |
| | | }, |
| | | |
| | | export default MyDataProvider; |
| | | // get a single record by id |
| | | getOne: async (resource, params) => { |
| | | // console.log("getOne", resource, params); |
| | | const res = await request.get(resource + "/" + params.id); |
| | | const { code, msg, data } = res.data; |
| | | if (code === 200) { |
| | | return Promise.resolve({ |
| | | data: { |
| | | id: data.id, |
| | | ...data, |
| | | }, |
| | | }); |
| | | } |
| | | return Promise.reject(new Error(msg)); |
| | | }, |
| | | |
| | | // get a list of records based on an array of ids |
| | | getMany: async (resource, params) => { |
| | | // console.log("getMany", resource, params); |
| | | const res = await request.post(resource + "/many/" + params.ids); |
| | | const { code, msg, data } = res.data; |
| | | if (code === 200) { |
| | | return Promise.resolve({ |
| | | data: data.map((item) => ({ |
| | | id: item.id, |
| | | ...item, |
| | | })), |
| | | }); |
| | | } |
| | | return Promise.reject(new Error(msg)); |
| | | }, |
| | | |
| | | // get the records referenced to another record, e.g. comments for a post |
| | | getManyReference: async (resource, params) => { |
| | | console.log("getManyReference", resource, params); |
| | | |
| | | return Promise.resolve(); |
| | | }, |
| | | |
| | | // create a record |
| | | create: async (resource, params) => { |
| | | console.log("create", resource, params); |
| | | const res = await request.post(resource + "/save", params?.data); |
| | | const { code, msg, data } = res.data; |
| | | if (code === 200) { |
| | | return Promise.resolve({ |
| | | data: { |
| | | id: data.id, |
| | | }, |
| | | }); |
| | | } |
| | | return Promise.reject(new Error(msg)); |
| | | }, |
| | | |
| | | // update a record based on a patch |
| | | update: async (resource, params) => { |
| | | console.log("update", resource, params); |
| | | const res = await request.post(resource + "/update", { |
| | | id: params.id, |
| | | ...params.data, |
| | | }); |
| | | const { code, msg, data } = res.data; |
| | | if (code === 200) { |
| | | return Promise.resolve({ |
| | | data: data, |
| | | }); |
| | | } |
| | | return Promise.reject(new Error(msg)); |
| | | }, |
| | | |
| | | // update a list of records based on an array of ids and a common patch |
| | | updateMany: async (resource, params) => { |
| | | console.log("updateMany", resource, params); |
| | | const res = await request.post( |
| | | resource + "/update/many", |
| | | params.ids.map((id) => ({ id, ...params.data })), |
| | | ); |
| | | const { code, msg, data } = res.data; |
| | | if (code === 200) { |
| | | return Promise.resolve({ |
| | | data: data, |
| | | }); |
| | | } |
| | | return Promise.reject(new Error(msg)); |
| | | }, |
| | | |
| | | // delete a record by id |
| | | delete: async (resource, params) => { |
| | | console.log("delete", resource, params); |
| | | const res = await request.post(resource + "/remove/" + [params.id]); |
| | | const { code, msg, data } = res.data; |
| | | if (code === 200) { |
| | | return Promise.resolve({ |
| | | data: { |
| | | id: params.id, |
| | | }, |
| | | }); |
| | | } |
| | | return Promise.reject(new Error(msg)); |
| | | }, |
| | | |
| | | // delete a list of records based on an array of ids |
| | | deleteMany: async (resource, params) => { |
| | | console.log("deleteMany", resource, params); |
| | | const res = await request.post(resource + "/remove/" + params?.ids); |
| | | const { code, msg, data } = res.data; |
| | | if (code === 200) { |
| | | return Promise.resolve({ |
| | | data: data, |
| | | }); |
| | | } |
| | | return Promise.reject(new Error(msg)); |
| | | }, |
| | | |
| | | // export excel from all data |
| | | export: async (resource, params) => { |
| | | console.log("export", resource, params); |
| | | const _params = Common.integrateParams(params); |
| | | try { |
| | | const res = await request.post(`${resource}/export`, _params, { |
| | | responseType: "blob", |
| | | }); |
| | | return res; |
| | | } catch (error) { |
| | | return Promise.reject(new Error(error)); |
| | | } |
| | | }, |
| | | }; |
| | | |
| | | export default MyDataProvider; |
| | |
| | | import ReactDOM from "react-dom/client"; |
| | | import App from "./App"; |
| | | |
| | | import '@fontsource/roboto/300.css'; |
| | | import '@fontsource/roboto/400.css'; |
| | | import '@fontsource/roboto/500.css'; |
| | | import '@fontsource/roboto/700.css'; |
| | | import "@fontsource/roboto/300.css"; |
| | | import "@fontsource/roboto/400.css"; |
| | | import "@fontsource/roboto/500.css"; |
| | | import "@fontsource/roboto/700.css"; |
| | | |
| | | ReactDOM.createRoot(document.getElementById("root")).render( |
| | | <App /> |
| | | ); |
| | | ReactDOM.createRoot(document.getElementById("root")).render(<App />); |
| | |
| | | import React, { useState, useEffect, useMemo, Suspense } from "react"; |
| | | import { |
| | | useTranslate, |
| | | DashboardMenuItem, |
| | | MenuItemLink, |
| | | Menu, |
| | | useSidebarState, |
| | | usePermissions, |
| | | } from 'react-admin'; |
| | | import { useLocation } from 'react-router-dom'; |
| | | import { Box } from '@mui/material'; |
| | | import SubMenu from './SubMenu'; |
| | | import SettingsIcon from '@mui/icons-material/Settings'; |
| | | import DashboardIcon from '@mui/icons-material/Dashboard'; |
| | | import HorizontalRuleIcon from '@mui/icons-material/HorizontalRule'; |
| | | import PersonIcon from '@mui/icons-material/Person'; |
| | | import * as Icons from '@mui/icons-material'; |
| | | useTranslate, |
| | | DashboardMenuItem, |
| | | MenuItemLink, |
| | | Menu, |
| | | useSidebarState, |
| | | usePermissions, |
| | | } from "react-admin"; |
| | | import { useLocation } from "react-router-dom"; |
| | | import { Box } from "@mui/material"; |
| | | import SubMenu from "./SubMenu"; |
| | | import SettingsIcon from "@mui/icons-material/Settings"; |
| | | import DashboardIcon from "@mui/icons-material/Dashboard"; |
| | | import HorizontalRuleIcon from "@mui/icons-material/HorizontalRule"; |
| | | import PersonIcon from "@mui/icons-material/Person"; |
| | | import * as Icons from "@mui/icons-material"; |
| | | |
| | | const getIconComponent = (iconStr) => { |
| | | return Icons[iconStr] || HorizontalRuleIcon; |
| | | return Icons[iconStr] || HorizontalRuleIcon; |
| | | }; |
| | | |
| | | export const MyMenu = ({ dense = false }) => { |
| | | const [state, setState] = useState({}); |
| | | const translate = useTranslate(); |
| | | const location = useLocation(); |
| | | const [sidebarIsOpen] = useSidebarState(); |
| | | const { isPending, permissions } = usePermissions(); |
| | | const [state, setState] = useState({}); |
| | | const translate = useTranslate(); |
| | | const location = useLocation(); |
| | | const [sidebarIsOpen] = useSidebarState(); |
| | | const { isPending, permissions } = usePermissions(); |
| | | |
| | | useEffect(() => { |
| | | // default open sub menu |
| | | const defaultExpandMenu = ["menu.system", "menu.dispatcher", "menu.equipment"]; |
| | | permissions?.forEach(item => { |
| | | if (defaultExpandMenu.includes(item.name)) { |
| | | setState(state => ({ ...state, [item.route]: true })); |
| | | } |
| | | }); |
| | | }, [permissions]); |
| | | useEffect(() => { |
| | | // default open sub menu |
| | | const defaultExpandMenu = [ |
| | | "menu.system", |
| | | "menu.dispatcher", |
| | | "menu.equipment", |
| | | ]; |
| | | permissions?.forEach((item) => { |
| | | if (defaultExpandMenu.includes(item.name)) { |
| | | setState((state) => ({ ...state, [item.route]: true })); |
| | | } |
| | | }); |
| | | }, [permissions]); |
| | | |
| | | useEffect(() => { |
| | | // expand this parent menu |
| | | const currentPath = location.pathname; |
| | | const parentRoutes = findParentRoutes(currentPath, permissions) |
| | | for (const parentRoute of parentRoutes) { |
| | | setState(state => ({ ...state, [parentRoute]: true })); |
| | | useEffect(() => { |
| | | // expand this parent menu |
| | | const currentPath = location.pathname; |
| | | const parentRoutes = findParentRoutes(currentPath, permissions); |
| | | for (const parentRoute of parentRoutes) { |
| | | setState((state) => ({ ...state, [parentRoute]: true })); |
| | | } |
| | | }, [location.pathname]); |
| | | |
| | | const handleToggle = (menu) => { |
| | | setState((state) => ({ ...state, [menu]: !state[menu] })); |
| | | }; |
| | | |
| | | const getIcon = (iconStr) => { |
| | | const IconComponent = getIconComponent(iconStr); |
| | | if (IconComponent) { |
| | | return <IconComponent />; |
| | | } |
| | | }; |
| | | |
| | | const generateMenu = (permissions) => { |
| | | return permissions.map((node) => { |
| | | if (node.children) { |
| | | return ( |
| | | <SubMenu |
| | | key={node.id} |
| | | handleToggle={() => handleToggle(node.route)} |
| | | isOpen={state[node.route]} |
| | | name={node.name} |
| | | dense={dense} |
| | | icon={getIcon(node.icon)} |
| | | > |
| | | {generateMenu(node.children)} |
| | | </SubMenu> |
| | | ); |
| | | } else { |
| | | if (node.component) { |
| | | return ( |
| | | <MenuItemLink |
| | | key={node.id} |
| | | to={node.component} // correspond to Resource.name |
| | | state={{ _scrollToTop: true }} |
| | | // primaryText={translate(`resources.orders.name`, { |
| | | // smart_count: 2, |
| | | // })} |
| | | primaryText={node.name} |
| | | leftIcon={getIcon(node.icon)} |
| | | dense={dense} |
| | | /> |
| | | ); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | }, [location.pathname]); |
| | | |
| | | const handleToggle = (menu) => { |
| | | setState(state => ({ ...state, [menu]: !state[menu] })); |
| | | }; |
| | | |
| | | const getIcon = (iconStr) => { |
| | | const IconComponent = getIconComponent(iconStr); |
| | | if (IconComponent) { |
| | | return <IconComponent />; |
| | | } |
| | | }; |
| | | |
| | | const generateMenu = (permissions) => { |
| | | return permissions.map((node) => { |
| | | if (node.children) { |
| | | return ( |
| | | <SubMenu |
| | | key={node.id} |
| | | handleToggle={() => handleToggle(node.route)} |
| | | isOpen={state[node.route]} |
| | | name={node.name} |
| | | dense={dense} |
| | | icon={getIcon(node.icon)} |
| | | > |
| | | {generateMenu(node.children)} |
| | | </SubMenu> |
| | | ); |
| | | } else { |
| | | if (node.component) { |
| | | return ( |
| | | <MenuItemLink |
| | | key={node.id} |
| | | to={node.component} // correspond to Resource.name |
| | | state={{ _scrollToTop: true }} |
| | | // primaryText={translate(`resources.orders.name`, { |
| | | // smart_count: 2, |
| | | // })} |
| | | primaryText={node.name} |
| | | leftIcon={getIcon(node.icon)} |
| | | dense={dense} |
| | | /> |
| | | ); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | return isPending |
| | | ? (<div>Waiting for permissions...</div>) : |
| | | ( |
| | | <Box |
| | | sx={{ |
| | | width: sidebarIsOpen ? 200 : 50, |
| | | marginTop: 1, |
| | | marginBottom: 1, |
| | | transition: theme => |
| | | theme.transitions.create('width', { |
| | | easing: theme.transitions.easing.sharp, |
| | | duration: theme.transitions.duration.leavingScreen, |
| | | }), |
| | | }} |
| | | > |
| | | <Menu.Item |
| | | to="/dashboard" |
| | | primaryText="menu.dashboard" |
| | | leftIcon={<DashboardIcon />} |
| | | /> |
| | | {permissions && (generateMenu(permissions))} |
| | | {/* <Menu.ResourceItems /> */} |
| | | <Menu.Item |
| | | to="/settings" |
| | | primaryText="menu.settings" |
| | | leftIcon={<PersonIcon />} |
| | | /> |
| | | </Box> |
| | | ) |
| | | } |
| | | return isPending ? ( |
| | | <div>Waiting for permissions...</div> |
| | | ) : ( |
| | | <Box |
| | | sx={{ |
| | | width: sidebarIsOpen ? 200 : 50, |
| | | marginTop: 1, |
| | | marginBottom: 1, |
| | | transition: (theme) => |
| | | theme.transitions.create("width", { |
| | | easing: theme.transitions.easing.sharp, |
| | | duration: theme.transitions.duration.leavingScreen, |
| | | }), |
| | | }} |
| | | > |
| | | <Menu.Item |
| | | to="/dashboard" |
| | | primaryText="menu.dashboard" |
| | | leftIcon={<DashboardIcon />} |
| | | /> |
| | | {permissions && generateMenu(permissions)} |
| | | {/* <Menu.ResourceItems /> */} |
| | | <Menu.Item |
| | | to="/settings" |
| | | primaryText="menu.settings" |
| | | leftIcon={<PersonIcon />} |
| | | /> |
| | | </Box> |
| | | ); |
| | | }; |
| | | |
| | | const findParentRoutes = (pathname, permissions) => { |
| | | if (!pathname || !permissions) { |
| | | return []; |
| | | } |
| | | const findMenu = (currentPermissions, path) => { |
| | | for (const item of currentPermissions) { |
| | | if (item.component === path) { |
| | | return item; |
| | | } |
| | | if (item.children) { |
| | | const found = findMenu(item.children, path); |
| | | if (found) { |
| | | return found; |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | }; |
| | | |
| | | const findParentRoutesRecursive = (item, allPermissions) => { |
| | | const parentRoutes = []; |
| | | let current = item; |
| | | while (current && current.parentId) { |
| | | const parent = allPermissions.find(permission => permission.id === current.parentId); |
| | | if (parent) { |
| | | parentRoutes.push(parent.route); |
| | | current = parent; |
| | | } else { |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return parentRoutes; |
| | | }; |
| | | |
| | | const currentMenu = findMenu(permissions, pathname.replace("/", "")); |
| | | if (currentMenu) { |
| | | return findParentRoutesRecursive(currentMenu, permissions); |
| | | } |
| | | |
| | | if (!pathname || !permissions) { |
| | | return []; |
| | | }; |
| | | } |
| | | const findMenu = (currentPermissions, path) => { |
| | | for (const item of currentPermissions) { |
| | | if (item.component === path) { |
| | | return item; |
| | | } |
| | | if (item.children) { |
| | | const found = findMenu(item.children, path); |
| | | if (found) { |
| | | return found; |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | }; |
| | | |
| | | const findParentRoutesRecursive = (item, allPermissions) => { |
| | | const parentRoutes = []; |
| | | let current = item; |
| | | while (current && current.parentId) { |
| | | const parent = allPermissions.find( |
| | | (permission) => permission.id === current.parentId, |
| | | ); |
| | | if (parent) { |
| | | parentRoutes.push(parent.route); |
| | | current = parent; |
| | | } else { |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return parentRoutes; |
| | | }; |
| | | |
| | | const currentMenu = findMenu(permissions, pathname.replace("/", "")); |
| | | if (currentMenu) { |
| | | return findParentRoutesRecursive(currentMenu, permissions); |
| | | } |
| | | |
| | | return []; |
| | | }; |
| | |
| | | import React, { useState, useRef, useEffect, useMemo } from "react"; |
| | | import { Box, Card, CardContent, LinearProgress, TextField, Button, Typography } from "@mui/material"; |
| | | import * as Icons from '@mui/icons-material'; |
| | | import { List, useTranslate, useListContext, Title, } from "react-admin"; |
| | | import { |
| | | Box, |
| | | Card, |
| | | CardContent, |
| | | LinearProgress, |
| | | TextField, |
| | | Button, |
| | | Typography, |
| | | } from "@mui/material"; |
| | | import * as Icons from "@mui/icons-material"; |
| | | import { |
| | | List, |
| | | useTranslate, |
| | | useListContext, |
| | | Title, |
| | | useGetList, |
| | | useNotify, |
| | | } from "react-admin"; |
| | | import WhMatListAside from "./WhMatListAside"; |
| | | import { RichTreeView } from "@mui/x-tree-view/RichTreeView"; |
| | | import { TreeItem2 } from "@mui/x-tree-view/TreeItem2"; |
| | | import request from '@/utils/request'; |
| | | import { Add, Edit, Delete, Padding, Save } from '@mui/icons-material'; |
| | | import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; |
| | | import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight'; |
| | | import RefreshIcon from '@mui/icons-material/Refresh'; |
| | | import { useTreeItem2Utils } from '@mui/x-tree-view/hooks'; |
| | | import request from "@/utils/request"; |
| | | import { Add, Edit, Delete, Padding, Save } from "@mui/icons-material"; |
| | | import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; |
| | | import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight"; |
| | | import RefreshIcon from "@mui/icons-material/Refresh"; |
| | | import { useTreeItem2Utils } from "@mui/x-tree-view/hooks"; |
| | | import WhMatCreate from "./whMatCreate"; |
| | | |
| | | // const RESOURCE = 'dept'; |
| | | const TITLE = 'menu.whMat'; |
| | | const TITLE = "menu.whMat"; |
| | | |
| | | const WhMatListContent = () => { |
| | | const translate = useTranslate(); |
| | | const [searchVal, setSearchVal] = useState(''); |
| | | const [createDialog, setCreateDialog] = React.useState(false); |
| | | const [editRecord, setEditRecord] = React.useState(null); |
| | | const treeData = [ |
| | | const translate = useTranslate(); |
| | | const [searchVal, setSearchVal] = useState(""); |
| | | const [createDialog, setCreateDialog] = React.useState(false); |
| | | const [editRecord, setEditRecord] = React.useState(null); |
| | | const treeData = [ |
| | | { |
| | | id: "19", |
| | | label: "半成品", |
| | | secondaryLabel: "RM001", |
| | | editable: true, |
| | | children: [ |
| | | { |
| | | id: '19', |
| | | label: '半成品', |
| | | secondaryLabel: 'RM001', |
| | | editable: true, |
| | | children: [ |
| | | { |
| | | id: 'grid-community', primaryText: '半成品', |
| | | secondaryText: 'RM001', label: '@mui/x-data-grid', editable: true, children: [ |
| | | { |
| | | id: 'grid-community22', primaryText: '半成品', |
| | | secondaryText: 'RM001', label: '@mui/x-data-grid', editable: true |
| | | },] |
| | | }, |
| | | { |
| | | id: 'grid-pro', primaryText: '半成品', |
| | | secondaryText: 'RM001', label: '@mui/x-data-grid-pro', editable: true |
| | | }, |
| | | { |
| | | id: 'grid-premium', primaryText: '半成品', |
| | | secondaryText: 'RM001', label: '@mui/x-data-grid-premium', editable: true |
| | | }, |
| | | ], |
| | | id: "grid-community", |
| | | primaryText: "半成品", |
| | | secondaryText: "RM001", |
| | | label: "@mui/x-data-grid", |
| | | editable: true, |
| | | children: [ |
| | | { |
| | | id: "grid-community22", |
| | | primaryText: "半成品", |
| | | secondaryText: "RM001", |
| | | label: "@mui/x-data-grid", |
| | | editable: true, |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | id: '18', |
| | | label: '原材料', |
| | | primaryText: '半成品', |
| | | secondaryText: 'RM001', |
| | | id: "grid-pro", |
| | | primaryText: "半成品", |
| | | secondaryText: "RM001", |
| | | label: "@mui/x-data-grid-pro", |
| | | editable: true, |
| | | }, |
| | | { |
| | | id: 'charts', |
| | | label: 'Charts', |
| | | primaryText: '半成品', |
| | | secondaryText: 'RM001', |
| | | children: [{ |
| | | id: 'charts-community', primaryText: '半成品', |
| | | secondaryText: 'RM001', label: '@mui/x-charts' |
| | | }], |
| | | id: "grid-premium", |
| | | primaryText: "半成品", |
| | | secondaryText: "RM001", |
| | | label: "@mui/x-data-grid-premium", |
| | | editable: true, |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | id: "18", |
| | | label: "原材料", |
| | | primaryText: "半成品", |
| | | secondaryText: "RM001", |
| | | }, |
| | | { |
| | | id: "charts", |
| | | label: "Charts", |
| | | primaryText: "半成品", |
| | | secondaryText: "RM001", |
| | | children: [ |
| | | { |
| | | id: 'tree-view', |
| | | label: 'Tree View', |
| | | primaryText: '半成品', |
| | | secondaryLabel: 'RM001', |
| | | children: [{ |
| | | id: 'tree-view-community', primaryText: '半成品', |
| | | secondaryText: 'RM001', label: '@mui/x-tree-view' |
| | | }], |
| | | id: "charts-community", |
| | | primaryText: "半成品", |
| | | secondaryText: "RM001", |
| | | label: "@mui/x-charts", |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | id: "tree-view", |
| | | label: "Tree View", |
| | | primaryText: "半成品", |
| | | secondaryLabel: "RM001", |
| | | children: [ |
| | | { |
| | | id: 'tree-view2', |
| | | label: 'Tree View3', |
| | | primaryText: '半成品', |
| | | secondaryText: 'RM001', |
| | | children: [{ |
| | | id: 'tree-view-community1', primaryText: '半成品', |
| | | secondaryText: 'RM001', label: '@mui/x-tree-view' |
| | | }], |
| | | id: "tree-view-community", |
| | | primaryText: "半成品", |
| | | secondaryText: "RM001", |
| | | label: "@mui/x-tree-view", |
| | | }, |
| | | ]; |
| | | const handleNodeSelect = (event, nodeId) => { |
| | | console.log('Selected Node ID:', nodeId); |
| | | // 在这里可以根据 nodeId 更新主内容区域 |
| | | }; |
| | | const handleSearch = () => { |
| | | console.log('Search Input:', selectedOption); |
| | | }; |
| | | ], |
| | | }, |
| | | { |
| | | id: "tree-view2", |
| | | label: "Tree View3", |
| | | primaryText: "半成品", |
| | | secondaryText: "RM001", |
| | | children: [ |
| | | { |
| | | id: "tree-view-community1", |
| | | primaryText: "半成品", |
| | | secondaryText: "RM001", |
| | | label: "@mui/x-tree-view", |
| | | }, |
| | | ], |
| | | }, |
| | | ]; |
| | | |
| | | const notify = useNotify(); |
| | | const handleNodeSelect = (event, nodeId) => { |
| | | console.log("Selected Node ID:", nodeId); |
| | | // 在这里可以根据 nodeId 更新主内容区域 |
| | | }; |
| | | const handleSearch = () => { |
| | | console.log("Search Input:", selectedOption); |
| | | }; |
| | | |
| | | const CustomCheckbox = React.forwardRef(function CustomCheckbox(props, ref) { |
| | | return <input type="checkbox" ref={ref} {...props} />; |
| | | }); |
| | | function CustomLabel({ children, className, secondaryLabel }) { |
| | | return ( |
| | | <Box display={"flex"} alignItems={"end"}> |
| | | <Typography fontWeight={500}>{children}</Typography> |
| | | <Box width={10}></Box> |
| | | {secondaryLabel && ( |
| | | <Typography variant="caption" color="secondary"> |
| | | {secondaryLabel} |
| | | </Typography> |
| | | )} |
| | | </Box> |
| | | ); |
| | | const handleInput = (value) => { |
| | | setSearchVal(value); |
| | | }; |
| | | |
| | | const CustomCheckbox = React.forwardRef(function CustomCheckbox(props, ref) { |
| | | return <input type="checkbox" ref={ref} {...props} />; |
| | | }); |
| | | |
| | | const getMatnrList = async () => { |
| | | const { |
| | | data: { code, data, msg }, |
| | | } = await request.post("/matnr/list", {}).then(); |
| | | if (code === 200) { |
| | | console.log(data); |
| | | } else { |
| | | notify(msg); |
| | | } |
| | | const CustomTreeItem = React.forwardRef(function CustomTreeItem(props, ref) { |
| | | const { publicAPI } = useTreeItem2Utils({ |
| | | itemId: props.itemId, |
| | | children: props.children, |
| | | }); |
| | | }; |
| | | |
| | | const item = publicAPI.getItem(props.itemId); |
| | | React.useEffect(() => { |
| | | getMatnrList(); |
| | | }, []); |
| | | |
| | | return ( |
| | | <TreeItem2 |
| | | {...props} |
| | | ref={ref} |
| | | slots={{ |
| | | label: CustomLabel, |
| | | }} |
| | | slotProps={{ |
| | | label: { secondaryLabel: item?.secondaryLabel || '' }, |
| | | }} |
| | | |
| | | /> |
| | | ); |
| | | function CustomLabel({ children, className, secondaryLabel }) { |
| | | return ( |
| | | <Box display={"flex"} alignItems={"end"}> |
| | | <Typography fontWeight={500}>{children}</Typography> |
| | | <Box width={10}></Box> |
| | | {secondaryLabel && ( |
| | | <Typography variant="caption" color="secondary"> |
| | | {secondaryLabel} |
| | | </Typography> |
| | | )} |
| | | </Box> |
| | | ); |
| | | } |
| | | const CustomTreeItem = React.forwardRef(function CustomTreeItem(props, ref) { |
| | | const { publicAPI } = useTreeItem2Utils({ |
| | | itemId: props.itemId, |
| | | children: props.children, |
| | | }); |
| | | |
| | | const isLoading = false; |
| | | |
| | | React.useEffect(() => { |
| | | request.post('/matnrGroup/tree', {}) |
| | | .then(res => { |
| | | if (res?.data?.code === 200) { |
| | | let data = res.data.data; |
| | | console.log(data); |
| | | |
| | | } else { |
| | | notify(res.data.msg); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | notify('Error fetching tree data'); |
| | | }); |
| | | }, [searchVal]) |
| | | |
| | | const handleAdd = () => { |
| | | setCreateDialog(true); |
| | | }; |
| | | const item = publicAPI.getItem(props.itemId); |
| | | |
| | | return ( |
| | | <> |
| | | <Box sx={{ mt: 1, mr: 3, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}> |
| | | <WhMatCreate |
| | | editRecord={editRecord} |
| | | open={createDialog} |
| | | setOpen={setCreateDialog} |
| | | /> |
| | | <Box |
| | | width={300} |
| | | mb={1} |
| | | > |
| | | <TextField |
| | | label={translate('ra.action.search')} |
| | | value={searchVal} |
| | | onChange={(e) => handleInput(e.target.value)} |
| | | /> |
| | | </Box> |
| | | <Box> |
| | | <Button |
| | | variant="outlined" |
| | | color="primary" |
| | | startIcon={<Add />} |
| | | onClick={handleAdd} |
| | | > |
| | | {translate('ra.action.add')} |
| | | </Button> |
| | | <Button |
| | | variant="outlined" |
| | | color="error" |
| | | startIcon={<Delete />} |
| | | sx={{ ml: 1 }} |
| | | > |
| | | {translate('ra.action.delete')} |
| | | </Button> |
| | | <Button |
| | | variant="outlined" |
| | | color="primary" |
| | | sx={{ ml: 1 }} |
| | | startIcon={<Save />} |
| | | > |
| | | {translate('ra.action.save')} |
| | | </Button> |
| | | </Box> |
| | | </Box> |
| | | <TreeItem2 |
| | | {...props} |
| | | ref={ref} |
| | | slots={{ |
| | | label: CustomLabel, |
| | | }} |
| | | slotProps={{ |
| | | label: { secondaryLabel: item?.secondaryLabel || "" }, |
| | | }} |
| | | /> |
| | | ); |
| | | }); |
| | | |
| | | <Card> |
| | | <CardContent> |
| | | <RichTreeView |
| | | defaultExpandedItems={['grid', 'pickers']} |
| | | checkboxSelection |
| | | items={treeData} |
| | | slots={{ item: CustomTreeItem }} |
| | | onItemClick={handleNodeSelect} // 监听节点点击事件 |
| | | /> |
| | | </CardContent> |
| | | </Card> |
| | | </> |
| | | ) |
| | | } |
| | | const isLoading = false; |
| | | |
| | | React.useEffect(() => { |
| | | request |
| | | .post("/matnrGroup/tree", {}) |
| | | .then((res) => { |
| | | if (res?.data?.code === 200) { |
| | | let data = res.data.data; |
| | | console.log(data); |
| | | } else { |
| | | notify(res.data.msg); |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | notify("Error fetching tree data"); |
| | | }); |
| | | }, [searchVal]); |
| | | |
| | | const handleAdd = () => { |
| | | setCreateDialog(true); |
| | | }; |
| | | |
| | | return ( |
| | | <> |
| | | <Box |
| | | sx={{ |
| | | mt: 1, |
| | | mr: 3, |
| | | display: "flex", |
| | | alignItems: "center", |
| | | justifyContent: "space-between", |
| | | }} |
| | | > |
| | | <WhMatCreate |
| | | editRecord={editRecord} |
| | | open={createDialog} |
| | | setOpen={setCreateDialog} |
| | | /> |
| | | <Box width={300} mb={1}> |
| | | <TextField |
| | | label={translate("ra.action.search")} |
| | | value={searchVal} |
| | | onChange={(e) => handleInput(e.target.value)} |
| | | /> |
| | | </Box> |
| | | <Box> |
| | | <Button |
| | | variant="outlined" |
| | | color="primary" |
| | | startIcon={<Add />} |
| | | onClick={handleAdd} |
| | | > |
| | | {translate("ra.action.add")} |
| | | </Button> |
| | | <Button |
| | | variant="outlined" |
| | | color="error" |
| | | startIcon={<Delete />} |
| | | sx={{ ml: 1 }} |
| | | > |
| | | {translate("ra.action.delete")} |
| | | </Button> |
| | | <Button |
| | | variant="outlined" |
| | | color="primary" |
| | | sx={{ ml: 1 }} |
| | | startIcon={<Save />} |
| | | > |
| | | {translate("ra.action.save")} |
| | | </Button> |
| | | </Box> |
| | | </Box> |
| | | |
| | | <Card> |
| | | <CardContent> |
| | | <RichTreeView |
| | | defaultExpandedItems={["grid", "pickers"]} |
| | | checkboxSelection |
| | | items={treeData} |
| | | slots={{ item: CustomTreeItem }} |
| | | onItemClick={handleNodeSelect} // 监听节点点击事件 |
| | | /> |
| | | </CardContent> |
| | | </Card> |
| | | </> |
| | | ); |
| | | }; |
| | | |
| | | const WhMatList = () => { |
| | | const translate = useTranslate(); |
| | | return ( |
| | | <> |
| | | <Box sx={{ |
| | | display: 'flex', |
| | | marginBottom: 24 |
| | | }}> |
| | | <Title title={TITLE} /> |
| | | <Box> |
| | | <WhMatListAside /> |
| | | </Box> |
| | | <Box sx={{ flexGrow: 1 }}> |
| | | <WhMatListContent /> |
| | | </Box> |
| | | </Box> |
| | | </> |
| | | |
| | | ) |
| | | } |
| | | export default WhMatList; |
| | | const translate = useTranslate(); |
| | | return ( |
| | | <> |
| | | <Box |
| | | sx={{ |
| | | display: "flex", |
| | | marginBottom: 24, |
| | | }} |
| | | > |
| | | <Title title={TITLE} /> |
| | | <Box> |
| | | <WhMatListAside /> |
| | | </Box> |
| | | <Box sx={{ flexGrow: 1 }}> |
| | | <WhMatListContent /> |
| | | </Box> |
| | | </Box> |
| | | </> |
| | | ); |
| | | }; |
| | | export default WhMatList; |
| | |
| | | import React, { useState, useRef, useEffect, useMemo, useCallback } from "react"; |
| | | import { Card, useTheme, List, CardContent, Input, InputAdornment, IconButton, TextField } from "@mui/material"; |
| | | import { useForm } from 'react-hook-form'; |
| | | import React, { |
| | | useState, |
| | | useRef, |
| | | useEffect, |
| | | useMemo, |
| | | useCallback, |
| | | } from "react"; |
| | | import { |
| | | Card, |
| | | useTheme, |
| | | List, |
| | | CardContent, |
| | | Input, |
| | | InputAdornment, |
| | | IconButton, |
| | | TextField, |
| | | } from "@mui/material"; |
| | | import { useForm } from "react-hook-form"; |
| | | import Warehouse from "./warehouse"; |
| | | import { Filter, SearchInput, useListContext,useTranslate } from 'react-admin'; |
| | | import request from '@/utils/request'; |
| | | import { |
| | | Filter, |
| | | SearchInput, |
| | | useListContext, |
| | | useTranslate, |
| | | useNotify, |
| | | } from "react-admin"; |
| | | import request from "@/utils/request"; |
| | | |
| | | const WhMatListAside = () => { |
| | | const theme = useTheme(); |
| | | const translate = useTranslate(); |
| | | const [searchVal, setSearchVal] = useState(''); |
| | | const { control, getValues } = useForm(); |
| | | const [map, setMap] = useState([ |
| | | { |
| | | id: 1, |
| | | name: '仓库1', |
| | | code: 'WH1', |
| | | icon: 'Warehouse', |
| | | locCount: 350, |
| | | }, |
| | | { |
| | | id: 2, |
| | | name: '仓库2', |
| | | code: 'WH1', |
| | | icon: 'Warehouse', |
| | | locCount: 237, |
| | | }, |
| | | { |
| | | id: 3, |
| | | name: '仓库3', |
| | | code: 'WH1', |
| | | icon: 'Warehouse', |
| | | locCount: 590, |
| | | } |
| | | ]); |
| | | |
| | | const handleInput = (value) => { |
| | | console.log(value); |
| | | setSearchVal(value); |
| | | const theme = useTheme(); |
| | | const translate = useTranslate(); |
| | | const [searchVal, setSearchVal] = useState(""); |
| | | const { control, getValues } = useForm(); |
| | | const notify = useNotify(); |
| | | |
| | | const [map, setMap] = useState([ |
| | | { |
| | | id: 1, |
| | | name: "仓库1", |
| | | code: "WH1", |
| | | icon: "Warehouse", |
| | | locCount: 350, |
| | | }, |
| | | { |
| | | id: 2, |
| | | name: "仓库2", |
| | | code: "WH1", |
| | | icon: "Warehouse", |
| | | locCount: 237, |
| | | }, |
| | | { |
| | | id: 3, |
| | | name: "仓库3", |
| | | code: "WH1", |
| | | icon: "Warehouse", |
| | | locCount: 590, |
| | | }, |
| | | ]); |
| | | |
| | | const handleInput = (value) => { |
| | | console.log(value); |
| | | setSearchVal(value); |
| | | }; |
| | | |
| | | const getMatnrList = async () => { |
| | | const { |
| | | data: { code, data, msg }, |
| | | } = await request.post("/warehouse/list", {}).then(); |
| | | if (code === 200) { |
| | | console.log(data); |
| | | } else { |
| | | notify(msg); |
| | | } |
| | | React.useEffect(() => { |
| | | request.post('/matnrGroup/tree', {}) |
| | | .then(res => { |
| | | if (res?.data?.code === 200) { |
| | | let data = res.data.data; |
| | | console.log(data); |
| | | }; |
| | | |
| | | } else { |
| | | notify(res.data.msg); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | notify('Error fetching tree data'); |
| | | }); |
| | | }, [searchVal]) |
| | | React.useEffect(() => { |
| | | getMatnrList(); |
| | | }, [searchVal]); |
| | | |
| | | return ( |
| | | <Card |
| | | sx={{ |
| | | order: -1, |
| | | mr: 2, |
| | | mt: 4, |
| | | width: 250 |
| | | }} |
| | | > |
| | | <CardContent> |
| | | <div> |
| | | <TextField |
| | | label={translate('ra.action.search')} |
| | | value={searchVal} |
| | | onChange={(e) => handleInput(e.target.value)} |
| | | return ( |
| | | <Card |
| | | sx={{ |
| | | order: -1, |
| | | mr: 2, |
| | | mt: 4, |
| | | width: 250, |
| | | }} |
| | | > |
| | | <CardContent> |
| | | <div> |
| | | <TextField |
| | | label={translate("ra.action.search")} |
| | | value={searchVal} |
| | | onChange={(e) => handleInput(e.target.value)} |
| | | /> |
| | | </div> |
| | | <List> |
| | | {map.map((record) => ( |
| | | <Warehouse key={record.id} record={record} /> |
| | | ))} |
| | | </List> |
| | | </CardContent> |
| | | </Card> |
| | | ); |
| | | }; |
| | | |
| | | /> |
| | | </div> |
| | | <List> |
| | | {map.map(record => ( |
| | | <Warehouse key={record.id} record={record} /> |
| | | ))} |
| | | </List> |
| | | </CardContent> |
| | | |
| | | </Card> |
| | | ) |
| | | } |
| | | |
| | | export default WhMatListAside; |
| | | export default WhMatListAside; |
| | |
| | | import React, { useState, useRef, useEffect, useMemo } from "react"; |
| | | import { |
| | | CreateBase, |
| | | Form, |
| | | useTranslate, |
| | | Toolbar, |
| | | SaveButton, |
| | | TextInput, |
| | | ReferenceInput, |
| | | AutocompleteInput, |
| | | required, |
| | | NumberInput, |
| | | } from 'react-admin'; |
| | | CreateBase, |
| | | Form, |
| | | useTranslate, |
| | | Toolbar, |
| | | SaveButton, |
| | | TextInput, |
| | | ReferenceInput, |
| | | AutocompleteInput, |
| | | required, |
| | | NumberInput, |
| | | } from "react-admin"; |
| | | import { |
| | | Dialog, |
| | | DialogActions, |
| | | DialogContent, |
| | | DialogTitle, |
| | | Stack, |
| | | Grid, |
| | | Box, |
| | | TableRow, |
| | | IconButton, |
| | | Table, |
| | | TableBody, |
| | | TableCell, |
| | | TableContainer, |
| | | TableHead, |
| | | Paper, |
| | | Checkbox, |
| | | Button |
| | | } from '@mui/material'; |
| | | Dialog, |
| | | DialogActions, |
| | | DialogContent, |
| | | DialogTitle, |
| | | Stack, |
| | | Grid, |
| | | Box, |
| | | TableRow, |
| | | IconButton, |
| | | Table, |
| | | TableBody, |
| | | TableCell, |
| | | TableContainer, |
| | | TableHead, |
| | | Paper, |
| | | Checkbox, |
| | | Button, |
| | | } from "@mui/material"; |
| | | import DialogCloseButton from "@/page/components/DialogCloseButton"; |
| | | import { styled } from '@mui/material/styles'; |
| | | import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; |
| | | import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight'; |
| | | import { styled } from "@mui/material/styles"; |
| | | import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; |
| | | import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight"; |
| | | import { Search } from "@mui/icons-material"; |
| | | import { tr } from "date-fns/locale"; |
| | | |
| | | import WhTable from "./whTable"; |
| | | |
| | | const columns = [ |
| | | { |
| | | id: 'matnrCode', |
| | | label: 'table.field.whMat.matnrCode', |
| | | minWidth: 160, |
| | | }, |
| | | { |
| | | id: 'matnrName', |
| | | label: 'table.field.whMat.matnrName', |
| | | }, |
| | | { |
| | | id: 'matnrGroupId', |
| | | label: 'table.field.whMat.matnrGroupId', |
| | | }, |
| | | { |
| | | id: 'spec', |
| | | label: 'table.field.whMat.spec', |
| | | }, |
| | | { |
| | | id: 'color', |
| | | label: 'table.field.whMat.color', |
| | | }, |
| | | { |
| | | id: 'size', |
| | | label: 'table.field.whMat.size', |
| | | }, |
| | | { |
| | | id: 'minWeight', |
| | | label: 'table.field.whMat.minWeight', |
| | | }, |
| | | { |
| | | id: 'maxWeight', |
| | | label: 'table.field.whMat.maxWeight', |
| | | }, |
| | | { |
| | | id: "matnrCode", |
| | | label: "table.field.whMat.matnrCode", |
| | | minWidth: 160, |
| | | }, |
| | | { |
| | | id: "matnrName", |
| | | label: "table.field.whMat.matnrName", |
| | | }, |
| | | { |
| | | id: "matnrGroupId", |
| | | label: "table.field.whMat.matnrGroupId", |
| | | }, |
| | | { |
| | | id: "spec", |
| | | label: "table.field.whMat.spec", |
| | | }, |
| | | { |
| | | id: "color", |
| | | label: "table.field.whMat.color", |
| | | }, |
| | | { |
| | | id: "size", |
| | | label: "table.field.whMat.size", |
| | | }, |
| | | { |
| | | id: "minWeight", |
| | | label: "table.field.whMat.minWeight", |
| | | }, |
| | | { |
| | | id: "maxWeight", |
| | | label: "table.field.whMat.maxWeight", |
| | | }, |
| | | ]; |
| | | |
| | | const WhMatCreate = (props) => { |
| | | const translate = useTranslate(); |
| | | const { editRecord, open, setOpen, callback, resource } = props; |
| | | const translate = useTranslate(); |
| | | const { editRecord, open, setOpen, callback, resource } = props; |
| | | |
| | | const handleClose = (event, reason) => { |
| | | if (reason !== "backdropClick") { |
| | | setOpen(false); |
| | | } |
| | | }; |
| | | const handleClose = (event, reason) => { |
| | | if (reason !== "backdropClick") { |
| | | setOpen(false); |
| | | } |
| | | }; |
| | | |
| | | const onSubmit = (data) => { |
| | | const _params = { ...data }; |
| | | }; |
| | | const onSubmit = (data) => { |
| | | const _params = { ...data }; |
| | | }; |
| | | |
| | | return ( |
| | | <> |
| | | <CreateBase> |
| | | <Dialog |
| | | open={open} |
| | | onClose={handleClose} |
| | | aria-labelledby="form-dialog-title" |
| | | fullWidth |
| | | disableRestoreFocus |
| | | maxWidth="lg" // 'xs' | 'sm' | 'md' | 'lg' | 'xl' |
| | | > |
| | | <Form record={editRecord} onSubmit={onSubmit}> |
| | | <DialogTitle id="form-dialog-title" sx={{ |
| | | position: 'sticky', |
| | | top: 0, |
| | | backgroundColor: 'background.paper', |
| | | zIndex: 1000 |
| | | }} |
| | | > |
| | | {editRecord ? translate('update.title') : translate('create.title')} |
| | | <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}> |
| | | <DialogCloseButton onClose={handleClose} /> |
| | | </Box> |
| | | </DialogTitle> |
| | | <DialogContent sx={{ mt: 2 }}> |
| | | <WhMatCreateContent /> |
| | | </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> |
| | | </> |
| | | ); |
| | | return ( |
| | | <> |
| | | <CreateBase> |
| | | <Dialog |
| | | open={open} |
| | | onClose={handleClose} |
| | | aria-labelledby="form-dialog-title" |
| | | fullWidth |
| | | disableRestoreFocus |
| | | maxWidth="lg" // 'xs' | 'sm' | 'md' | 'lg' | 'xl' |
| | | > |
| | | <Form record={editRecord} onSubmit={onSubmit}> |
| | | <DialogTitle |
| | | id="form-dialog-title" |
| | | sx={{ |
| | | position: "sticky", |
| | | top: 0, |
| | | backgroundColor: "background.paper", |
| | | zIndex: 1000, |
| | | }} |
| | | > |
| | | {editRecord |
| | | ? translate("update.title") |
| | | : translate("create.title")} |
| | | <Box |
| | | sx={{ position: "absolute", top: 8, right: 8, zIndex: 1001 }} |
| | | > |
| | | <DialogCloseButton onClose={handleClose} /> |
| | | </Box> |
| | | </DialogTitle> |
| | | <DialogContent sx={{ mt: 2 }}> |
| | | <WhMatCreateContent /> |
| | | </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> |
| | | </> |
| | | ); |
| | | }; |
| | | const StyledTableRow = styled(TableRow)(({ theme }) => ({ |
| | | '& .MuiButtonBase-root': { |
| | | padding: '0px 0px' |
| | | } |
| | | "& .MuiButtonBase-root": { |
| | | padding: "0px 0px", |
| | | }, |
| | | })); |
| | | |
| | | const StyledTableCell = styled(TableCell)(({ theme }) => ({ |
| | | '& .MuiButtonBase-root': { |
| | | padding: '0px 0px' |
| | | }, |
| | | overflow: 'hidden', |
| | | textOverflow: 'ellipsis', |
| | | whiteSpace: 'nowrap', |
| | | maxWidth: 600, |
| | | "& .MuiButtonBase-root": { |
| | | padding: "0px 0px", |
| | | }, |
| | | overflow: "hidden", |
| | | textOverflow: "ellipsis", |
| | | whiteSpace: "nowrap", |
| | | maxWidth: 600, |
| | | })); |
| | | |
| | | const TreeTableRow = (props) => { |
| | | const { row, depth = 0, openNodes, setOpenNodes, onEdit, onDelete } = props; |
| | | const isOpen = openNodes[row.id] || false; |
| | | const [checked, setChecked] = useState(false); |
| | | const toggleNode = (id) => { |
| | | setOpenNodes(prevState => ({ ...prevState, [id]: !prevState[id] })); |
| | | }; |
| | | return ( |
| | | <React.Fragment> |
| | | <StyledTableRow hover tabIndex={-1} key={row.id}> |
| | | <StyledTableCell sx={{ padding: 0, width: 20 }}> |
| | | {row.children && ( |
| | | <IconButton |
| | | aria-label="expand row" |
| | | size="small" |
| | | style={{ marginLeft: (depth * 16 + 8) }} |
| | | onClick={() => toggleNode(row.id)} |
| | | > |
| | | {isOpen ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />} |
| | | </IconButton> |
| | | )} |
| | | const { row, depth = 0, openNodes, setOpenNodes, onEdit, onDelete } = props; |
| | | const isOpen = openNodes[row.id] || false; |
| | | const [checked, setChecked] = useState(false); |
| | | const toggleNode = (id) => { |
| | | setOpenNodes((prevState) => ({ ...prevState, [id]: !prevState[id] })); |
| | | }; |
| | | return ( |
| | | <React.Fragment> |
| | | <StyledTableRow hover tabIndex={-1} key={row.id}> |
| | | <StyledTableCell sx={{ padding: 0, width: 20 }}> |
| | | {row.children && ( |
| | | <IconButton |
| | | aria-label="expand row" |
| | | size="small" |
| | | style={{ marginLeft: depth * 16 + 8 }} |
| | | onClick={() => toggleNode(row.id)} |
| | | > |
| | | {isOpen ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />} |
| | | </IconButton> |
| | | )} |
| | | </StyledTableCell> |
| | | <StyledTableCell style={{ paddingLeft: depth * 16 + 16 }}> |
| | | <Checkbox |
| | | key={row.id} |
| | | checked={row.checked} |
| | | // onChange={() => { row.checked = !row.checked; }} |
| | | /> |
| | | </StyledTableCell> |
| | | {columns.map((column, idx) => { |
| | | if (column.id !== "actions") { |
| | | const value = row[column.id]; |
| | | return ( |
| | | <> |
| | | <StyledTableCell |
| | | key={column.id} |
| | | align={column.align || "left"} |
| | | // style={{ paddingLeft: idx === 0 && (depth * 16 + 16) }} |
| | | onClick={() => toggleNode(row.id)} |
| | | > |
| | | {column.format ? column.format(value) : value} |
| | | </StyledTableCell> |
| | | <StyledTableCell style={{ paddingLeft: (depth * 16 + 16) }}> |
| | | <Checkbox |
| | | key={row.id} |
| | | checked={row.checked} |
| | | // onChange={() => { row.checked = !row.checked; }} |
| | | /> |
| | | </StyledTableCell> |
| | | {columns.map((column, idx) => { |
| | | if (column.id !== 'actions') { |
| | | const value = row[column.id]; |
| | | return ( |
| | | <> |
| | | <StyledTableCell |
| | | key={column.id} |
| | | align={column.align || 'left'} |
| | | // style={{ paddingLeft: idx === 0 && (depth * 16 + 16) }} |
| | | onClick={() => toggleNode(row.id)} |
| | | > |
| | | {column.format ? column.format(value) : value} |
| | | </StyledTableCell> |
| | | </> |
| | | |
| | | ) |
| | | } |
| | | })} |
| | | </StyledTableRow> |
| | | {row.children && isOpen && ( |
| | | row.children.map((child) => ( |
| | | <TreeTableRow |
| | | key={child.id} |
| | | row={child} |
| | | depth={depth + 1} |
| | | openNodes={openNodes} |
| | | setOpenNodes={setOpenNodes} |
| | | /> |
| | | )) |
| | | )} |
| | | </React.Fragment> |
| | | ); |
| | | </> |
| | | ); |
| | | } |
| | | })} |
| | | </StyledTableRow> |
| | | {row.children && |
| | | isOpen && |
| | | row.children.map((child) => ( |
| | | <TreeTableRow |
| | | key={child.id} |
| | | row={child} |
| | | depth={depth + 1} |
| | | openNodes={openNodes} |
| | | setOpenNodes={setOpenNodes} |
| | | /> |
| | | ))} |
| | | </React.Fragment> |
| | | ); |
| | | }; |
| | | |
| | | const WhMatCreateContent = (props) => { |
| | | const translate = useTranslate(); |
| | | const [selAll, setSelAll] = useState(false); |
| | | const [treeData, setTreeData] = useState([ |
| | | const translate = useTranslate(); |
| | | const [selAll, setSelAll] = useState(false); |
| | | const [treeData, setTreeData] = useState([ |
| | | { |
| | | id: 1, |
| | | matnrCode: "root1", |
| | | matnrName: "根节点", |
| | | matnrGroupId: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: [ |
| | | { |
| | | id: 1, matnrCode: 'root1', matnrName: '根节点', matnrGroupId: 'admin', sort: 1, checked: false, children: [ |
| | | { |
| | | id: 29, matnrCode: 'root29', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: [ |
| | | { id: 30, matnrCode: 'root30', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 31, matnrCode: 'root31', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 32, matnrCode: 'root32', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 33, matnrCode: 'root33', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 34, matnrCode: 'root34', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 35, matnrCode: 'root35', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | ] |
| | | }, |
| | | { id: 24, matnrCode: 'root24', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 25, matnrCode: 'root25', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 26, matnrCode: 'root26', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 27, matnrCode: 'root27', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 28, matnrCode: 'root28', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | |
| | | ] |
| | | id: 29, |
| | | matnrCode: "root29", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: [ |
| | | { |
| | | id: 30, |
| | | matnrCode: "root30", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 31, |
| | | matnrCode: "root31", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 32, |
| | | matnrCode: "root32", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 33, |
| | | matnrCode: "root33", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 34, |
| | | matnrCode: "root34", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 35, |
| | | matnrCode: "root35", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | ], |
| | | }, |
| | | { id: 2, matnrCode: 'root2', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 3, matnrCode: 'root3', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 4, matnrCode: 'root4', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 5, matnrCode: 'root5', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 6, matnrCode: 'root6', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 7, matnrCode: 'root', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 8, matnrCode: 'root', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 9, matnrCode: 'root', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 10, matnrCode: 'root', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 11, matnrCode: 'root', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 12, matnrCode: 'root', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 13, matnrCode: 'root', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 14, matnrCode: 'root', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 15, matnrCode: 'root', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 16, matnrCode: 'root', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 17, matnrCode: 'root', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 18, matnrCode: 'root', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 19, matnrCode: 'root', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 20, matnrCode: 'root', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 21, matnrCode: 'root', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 22, matnrCode: 'root', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { id: 23, matnrCode: 'root', fullName: '根节点', leader: 'admin', sort: 1, checked: false, children: null }, |
| | | { |
| | | id: 24, |
| | | matnrCode: "root24", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 25, |
| | | matnrCode: "root25", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 26, |
| | | matnrCode: "root26", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 27, |
| | | matnrCode: "root27", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 28, |
| | | matnrCode: "root28", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | id: 2, |
| | | matnrCode: "root2", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 3, |
| | | matnrCode: "root3", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 4, |
| | | matnrCode: "root4", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | ]); |
| | | const [openNodes, setOpenNodes] = React.useState({}); |
| | | |
| | | const handleSearch = () => { |
| | | console.log("handleSearch"); |
| | | }; |
| | | const selectAll = () => { |
| | | selAll ? setSelAll(false) : setSelAll(true); |
| | | }; |
| | | |
| | | ]); |
| | | const [openNodes, setOpenNodes] = React.useState({}); |
| | | useEffect(() => { |
| | | console.log(selAll); |
| | | |
| | | const handleSearch = () => { |
| | | console.log('handleSearch'); |
| | | } |
| | | const selectAll = () => { |
| | | selAll ? setSelAll(false) : setSelAll(true); |
| | | } |
| | | |
| | | useEffect(() => { |
| | | console.log(selAll); |
| | | |
| | | const setAllChecked = (nodes, checked) => { |
| | | nodes.forEach(node => { |
| | | node.checked = !checked; |
| | | if (node.children) { |
| | | setAllChecked(node.children, checked); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | if (selAll) { |
| | | setAllChecked(treeData, true); |
| | | } else { |
| | | setAllChecked(treeData, false); |
| | | const setAllChecked = (nodes, checked) => { |
| | | nodes.forEach((node) => { |
| | | node.checked = !checked; |
| | | if (node.children) { |
| | | setAllChecked(node.children, checked); |
| | | } |
| | | }, [selAll]); |
| | | }); |
| | | }; |
| | | |
| | | return ( |
| | | <> |
| | | <Grid container rowSpacing={2} columnSpacing={2}> |
| | | <Grid item xs={3} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.whMat.matnrCode" |
| | | source="matnrCode" |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={3} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.whMat.matnrName" |
| | | source="matnrName" |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={3} display="flex" gap={1}> |
| | | <ReferenceInput |
| | | source="groupId" |
| | | reference="matnrGroup" |
| | | > |
| | | <AutocompleteInput |
| | | label="table.field.whMat.matnrGroupId" |
| | | optionText="name" |
| | | filterToQuery={(val) => ({ name: val })} |
| | | /> |
| | | </ReferenceInput> |
| | | </Grid> |
| | | <Grid item xs={3} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.whMat.spec" |
| | | source="spec" |
| | | /> |
| | | </Grid> |
| | | if (selAll) { |
| | | setAllChecked(treeData, true); |
| | | } else { |
| | | setAllChecked(treeData, false); |
| | | } |
| | | }, [selAll]); |
| | | |
| | | <Grid item xs={3} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.whMat.color" |
| | | source="color" |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={3} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.whMat.size" |
| | | source="size" |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={3} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.whMat.minWeight" |
| | | source="minWeight" |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={3} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.whMat.maxWeight" |
| | | source="maxWeight" |
| | | /> |
| | | </Grid> |
| | | </Grid> |
| | | <Box sx={{ mt: 2, mb: 2 }}> |
| | | <Stack direction="row" spacing={1} justifyContent="flex-end"> |
| | | <Button |
| | | variant="outlined" |
| | | color="primary" |
| | | startIcon={<Search />} |
| | | onClick={handleSearch} |
| | | > |
| | | {translate('ra.action.search')} |
| | | </Button> |
| | | </Stack> |
| | | </Box> |
| | | <TableContainer component={Paper}> |
| | | <Table size="small"> |
| | | <TableHead> |
| | | <TableRow> |
| | | <StyledTableCell sx={{ padding: 0, width: 0 }} /> |
| | | <StyledTableCell sx={{ width: 0 }} > |
| | | <Checkbox checked={selAll} onClick={selectAll} /> |
| | | </StyledTableCell> |
| | | {columns.map((column, idx) => ( |
| | | <StyledTableCell |
| | | key={idx} |
| | | align={column.align || 'left'} |
| | | style={{ |
| | | minWidth: column.minWidth, |
| | | }} |
| | | > |
| | | {translate(column.label)} |
| | | </StyledTableCell> |
| | | ))} |
| | | </TableRow> |
| | | </TableHead> |
| | | <TableBody> |
| | | {treeData && treeData.length > 0 && ( |
| | | treeData.map((row) => ( |
| | | <TreeTableRow |
| | | key={row.id} |
| | | row={row} |
| | | openNodes={openNodes} |
| | | setOpenNodes={setOpenNodes} |
| | | /> |
| | | )) |
| | | )} |
| | | </TableBody> |
| | | </Table> |
| | | </TableContainer> |
| | | </> |
| | | const [treeDatas, setTreeDatas] = useState([ |
| | | { |
| | | id: 1, |
| | | matnrCode: "root1", |
| | | matnrName: "根节点", |
| | | matnrGroupId: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: [ |
| | | { |
| | | id: 29, |
| | | matnrCode: "root29", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: [ |
| | | { |
| | | id: 30, |
| | | matnrCode: "root30", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 31, |
| | | matnrCode: "root31", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 32, |
| | | matnrCode: "root32", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 33, |
| | | matnrCode: "root33", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 34, |
| | | matnrCode: "root34", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 35, |
| | | matnrCode: "root35", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | id: 24, |
| | | matnrCode: "root24", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 25, |
| | | matnrCode: "root25", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 26, |
| | | matnrCode: "root26", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 27, |
| | | matnrCode: "root27", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 28, |
| | | matnrCode: "root28", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | id: 2, |
| | | matnrCode: "root2", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 3, |
| | | matnrCode: "root3", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | { |
| | | id: 4, |
| | | matnrCode: "root4", |
| | | fullName: "根节点", |
| | | leader: "admin", |
| | | sort: 1, |
| | | checked: false, |
| | | children: null, |
| | | }, |
| | | ]); |
| | | |
| | | ); |
| | | return ( |
| | | <> |
| | | <Grid container rowSpacing={2} columnSpacing={2}> |
| | | <Grid item xs={3} display="flex" gap={1}> |
| | | <TextInput label="table.field.whMat.matnrCode" source="matnrCode" /> |
| | | </Grid> |
| | | <Grid item xs={3} display="flex" gap={1}> |
| | | <TextInput label="table.field.whMat.matnrName" source="matnrName" /> |
| | | </Grid> |
| | | <Grid item xs={3} display="flex" gap={1}> |
| | | <ReferenceInput source="groupId" reference="matnrGroup"> |
| | | <AutocompleteInput |
| | | label="table.field.whMat.matnrGroupId" |
| | | optionText="name" |
| | | filterToQuery={(val) => ({ name: val })} |
| | | /> |
| | | </ReferenceInput> |
| | | </Grid> |
| | | <Grid item xs={3} display="flex" gap={1}> |
| | | <TextInput label="table.field.whMat.spec" source="spec" /> |
| | | </Grid> |
| | | |
| | | <Grid item xs={3} display="flex" gap={1}> |
| | | <TextInput label="table.field.whMat.color" source="color" /> |
| | | </Grid> |
| | | <Grid item xs={3} display="flex" gap={1}> |
| | | <TextInput label="table.field.whMat.size" source="size" /> |
| | | </Grid> |
| | | <Grid item xs={3} display="flex" gap={1}> |
| | | <TextInput label="table.field.whMat.minWeight" source="minWeight" /> |
| | | </Grid> |
| | | <Grid item xs={3} display="flex" gap={1}> |
| | | <TextInput label="table.field.whMat.maxWeight" source="maxWeight" /> |
| | | </Grid> |
| | | </Grid> |
| | | <Box sx={{ mt: 2, mb: 2 }}> |
| | | <Stack direction="row" spacing={1} justifyContent="flex-end"> |
| | | <Button |
| | | variant="outlined" |
| | | color="primary" |
| | | startIcon={<Search />} |
| | | onClick={handleSearch} |
| | | > |
| | | {translate("ra.action.search")} |
| | | </Button> |
| | | </Stack> |
| | | </Box> |
| | | <TableContainer component={Paper}> |
| | | <Table size="small"> |
| | | <TableHead> |
| | | <TableRow> |
| | | <StyledTableCell sx={{ padding: 0, width: 0 }} /> |
| | | <StyledTableCell sx={{ width: 0 }}> |
| | | <Checkbox checked={selAll} onClick={selectAll} /> |
| | | </StyledTableCell> |
| | | {columns.map((column, idx) => ( |
| | | <StyledTableCell |
| | | key={idx} |
| | | align={column.align || "left"} |
| | | style={{ |
| | | minWidth: column.minWidth, |
| | | }} |
| | | > |
| | | {translate(column.label)} |
| | | </StyledTableCell> |
| | | ))} |
| | | </TableRow> |
| | | </TableHead> |
| | | <TableBody> |
| | | {treeData && |
| | | treeData.length > 0 && |
| | | treeData.map((row) => ( |
| | | <TreeTableRow |
| | | key={row.id} |
| | | row={row} |
| | | openNodes={openNodes} |
| | | setOpenNodes={setOpenNodes} |
| | | /> |
| | | ))} |
| | | </TableBody> |
| | | </Table> |
| | | </TableContainer> |
| | | <WhTable data={treeDatas} /> |
| | | </> |
| | | ); |
| | | }; |
| | | |
| | | export default WhMatCreate; |
| | | export default WhMatCreate; |
New file |
| | |
| | | import React, { useState } from "react"; |
| | | import { |
| | | Table, |
| | | TableBody, |
| | | TableCell, |
| | | TableHead, |
| | | TableRow, |
| | | IconButton, |
| | | Checkbox, |
| | | } from "@mui/material"; |
| | | import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; |
| | | import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight"; |
| | | |
| | | // 递归收集所有节点的 ID |
| | | const collectAllNodeIds = (nodes) => { |
| | | let allIds = []; |
| | | nodes.forEach((node) => { |
| | | allIds.push(node.id); |
| | | if (node.children) { |
| | | allIds = allIds.concat(collectAllNodeIds(node.children)); |
| | | } |
| | | }); |
| | | return allIds; |
| | | }; |
| | | |
| | | // 递归收集某个节点及其所有子节点的 ID |
| | | const collectNodeAndChildrenIds = (node) => { |
| | | let ids = [node.id]; |
| | | if (node.children) { |
| | | node.children.forEach((child) => { |
| | | ids = ids.concat(collectNodeAndChildrenIds(child)); |
| | | }); |
| | | } |
| | | return ids; |
| | | }; |
| | | |
| | | // 检查某个节点的所有子节点是否都被选中 |
| | | const areAllChildrenSelected = (node, selectedNodeIds) => { |
| | | const childrenIds = collectAllNodeIds(node.children || []); |
| | | return childrenIds.every((id) => selectedNodeIds.includes(id)); |
| | | }; |
| | | |
| | | // 递归渲染树状表格行 |
| | | const renderTreeRows = ( |
| | | nodes, |
| | | level = 0, |
| | | openNodes, |
| | | setOpenNodes, |
| | | selectedNodeIds, |
| | | setSelectedNodeIds, |
| | | ) => { |
| | | return nodes.map((node) => { |
| | | const isOpen = openNodes.includes(node.id); |
| | | const toggleOpen = () => { |
| | | if (isOpen) { |
| | | setOpenNodes(openNodes.filter((id) => id !== node.id)); |
| | | } else { |
| | | setOpenNodes([...openNodes, node.id]); |
| | | } |
| | | }; |
| | | |
| | | const allChildrenIds = collectNodeAndChildrenIds(node); |
| | | const allChildrenSelected = allChildrenIds.every((id) => |
| | | selectedNodeIds.includes(id), |
| | | ); |
| | | const someChildrenSelected = |
| | | allChildrenIds.some((id) => selectedNodeIds.includes(id)) && |
| | | !allChildrenSelected; |
| | | |
| | | const handleCheckboxChange = () => { |
| | | let newSelectedNodeIds = [...selectedNodeIds]; |
| | | if (allChildrenSelected) { |
| | | allChildrenIds.forEach((id) => { |
| | | newSelectedNodeIds = newSelectedNodeIds.filter( |
| | | (selectedId) => selectedId !== id, |
| | | ); |
| | | }); |
| | | } else { |
| | | allChildrenIds.forEach((id) => { |
| | | if (!newSelectedNodeIds.includes(id)) { |
| | | newSelectedNodeIds.push(id); |
| | | } |
| | | }); |
| | | } |
| | | setSelectedNodeIds(newSelectedNodeIds); |
| | | }; |
| | | |
| | | return ( |
| | | <React.Fragment key={node.id}> |
| | | <TableRow size="small"> |
| | | <TableCell padding="none" width={20}> |
| | | {node.children && ( |
| | | <IconButton size="small" onClick={toggleOpen}> |
| | | {isOpen ? ( |
| | | <KeyboardArrowDownIcon fontSize="small" /> |
| | | ) : ( |
| | | <KeyboardArrowRightIcon fontSize="small" /> |
| | | )} |
| | | </IconButton> |
| | | )} |
| | | </TableCell> |
| | | <TableCell width={20} style={{ paddingLeft: 20 * level }}> |
| | | <Checkbox |
| | | size="small" |
| | | checked={allChildrenSelected} |
| | | indeterminate={someChildrenSelected} |
| | | onChange={handleCheckboxChange} |
| | | /> |
| | | </TableCell> |
| | | <TableCell>{node.matnrCode}</TableCell> |
| | | <TableCell>{node.fullName || node.matnrName}</TableCell> |
| | | <TableCell>{node.matnrGroupId}</TableCell> |
| | | <TableCell>{node.specification || "-"}</TableCell> |
| | | <TableCell>{node.color || "-"}</TableCell> |
| | | <TableCell>{node.size || "-"}</TableCell> |
| | | <TableCell>{node.minWeight || "-"}</TableCell> |
| | | <TableCell>{node.maxWeight || "-"}</TableCell> |
| | | </TableRow> |
| | | {isOpen && |
| | | node.children && |
| | | renderTreeRows( |
| | | node.children, |
| | | level + 1, |
| | | openNodes, |
| | | setOpenNodes, |
| | | selectedNodeIds, |
| | | setSelectedNodeIds, |
| | | )} |
| | | </React.Fragment> |
| | | ); |
| | | }); |
| | | }; |
| | | |
| | | const TreeTable = ({ data }) => { |
| | | const [openNodes, setOpenNodes] = useState([]); |
| | | const [selectedNodeIds, setSelectedNodeIds] = useState([]); |
| | | const allNodeIds = collectAllNodeIds(data); |
| | | |
| | | const handleSelectAll = (event) => { |
| | | if (event.target.checked) { |
| | | setSelectedNodeIds(allNodeIds); |
| | | } else { |
| | | setSelectedNodeIds([]); |
| | | } |
| | | }; |
| | | |
| | | const isAllSelected = selectedNodeIds.length === allNodeIds.length; |
| | | |
| | | return ( |
| | | <Table size="small" style={{ backgroundColor: "#121317" }}> |
| | | <TableHead> |
| | | <TableRow size="small"> |
| | | <TableCell width={20}></TableCell> |
| | | <TableCell width={20}> |
| | | <Checkbox |
| | | size="small" |
| | | checked={isAllSelected} |
| | | indeterminate={ |
| | | selectedNodeIds.length > 0 && |
| | | selectedNodeIds.length < allNodeIds.length |
| | | } |
| | | onChange={handleSelectAll} |
| | | /> |
| | | </TableCell> |
| | | <TableCell>物料编码</TableCell> |
| | | <TableCell>物料名称</TableCell> |
| | | <TableCell>物料分组</TableCell> |
| | | <TableCell>规格</TableCell> |
| | | <TableCell>颜色</TableCell> |
| | | <TableCell>尺寸</TableCell> |
| | | <TableCell>最小重量</TableCell> |
| | | <TableCell>最大重量</TableCell> |
| | | </TableRow> |
| | | </TableHead> |
| | | <TableBody> |
| | | {renderTreeRows( |
| | | data, |
| | | 0, |
| | | openNodes, |
| | | setOpenNodes, |
| | | selectedNodeIds, |
| | | setSelectedNodeIds, |
| | | )} |
| | | </TableBody> |
| | | </Table> |
| | | ); |
| | | }; |
| | | |
| | | export default TreeTable; |
| | |
| | | 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'; |
| | | 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"; |
| | | 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 SerialRuleCreate = (props) => { |
| | | const { open, setOpen } = props; |
| | | const { open, setOpen } = props; |
| | | |
| | | const translate = useTranslate(); |
| | | const notify = useNotify(); |
| | | const translate = useTranslate(); |
| | | const notify = useNotify(); |
| | | |
| | | const handleClose = (event, reason) => { |
| | | if (reason !== "backdropClick") { |
| | | setOpen(false); |
| | | } |
| | | }; |
| | | const handleClose = (event, reason) => { |
| | | if (reason !== "backdropClick") { |
| | | setOpen(false); |
| | | } |
| | | }; |
| | | |
| | | const handleSuccess = async (data) => { |
| | | setOpen(false); |
| | | notify('common.response.success'); |
| | | }; |
| | | 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 } }); |
| | | }; |
| | | 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 }} |
| | | 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="xl" // 'xs' | 'sm' | 'md' | 'lg' | 'xl' |
| | | > |
| | | <Form> |
| | | <DialogTitle |
| | | id="form-dialog-title" |
| | | sx={{ |
| | | position: "sticky", |
| | | top: 0, |
| | | backgroundColor: "background.paper", |
| | | zIndex: 1000, |
| | | }} |
| | | > |
| | | <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.serialRule.code" |
| | | source="code" |
| | | parse={v => v} |
| | | autoFocus |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.serialRule.name" |
| | | source="name" |
| | | parse={v => v} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.serialRule.delimit" |
| | | source="delimit" |
| | | parse={v => v} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.serialRule.reset" |
| | | source="reset" |
| | | parse={v => v} |
| | | validate={required()} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.serialRule.resetDep" |
| | | source="resetDep" |
| | | parse={v => v} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.serialRule.currValue" |
| | | source="currValue" |
| | | parse={v => v} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.serialRule.lastCode" |
| | | source="lastCode" |
| | | parse={v => v} |
| | | /> |
| | | </Grid> |
| | | {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.serialRule.code" |
| | | source="code" |
| | | parse={(v) => v} |
| | | autoFocus |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.serialRule.name" |
| | | source="name" |
| | | parse={(v) => v} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.serialRule.delimit" |
| | | source="delimit" |
| | | parse={(v) => v} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.serialRule.reset" |
| | | source="reset" |
| | | parse={(v) => v} |
| | | validate={required()} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.serialRule.resetDep" |
| | | source="resetDep" |
| | | parse={(v) => v} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.serialRule.currValue" |
| | | source="currValue" |
| | | parse={(v) => v} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.serialRule.lastCode" |
| | | source="lastCode" |
| | | 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> |
| | | </> |
| | | ) |
| | | } |
| | | <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 SerialRuleCreate; |
New file |
| | |
| | | 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 SerialRuleItem from "../serialRuleItem/index"; |
| | | |
| | | const SerialRuleDetail = (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 }, |
| | | }); |
| | | }; |
| | | |
| | | console.log(SerialRuleItem); |
| | | |
| | | return ( |
| | | <> |
| | | <Dialog |
| | | open={open} |
| | | onClose={handleClose} |
| | | aria-labelledby="form-dialog-title" |
| | | fullWidth |
| | | disableRestoreFocus |
| | | maxWidth="xl" // 'xs' | 'sm' | 'md' | 'lg' | 'xl' |
| | | > |
| | | <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 }}> |
| | | <SerialRuleItem.list /> |
| | | </DialogContent> |
| | | </Dialog> |
| | | </> |
| | | ); |
| | | }; |
| | | |
| | | export default SerialRuleDetail; |
| | |
| | | import React, { useState, useRef, useEffect, useMemo, useCallback } from "react"; |
| | | import { useNavigate } from 'react-router-dom'; |
| | | 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'; |
| | | 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 SerialRuleCreate from "./SerialRuleCreate"; |
| | | import SerialRuleDetail from "./SerialRuleDetail"; |
| | | import SerialRulePanel from "./SerialRulePanel"; |
| | | 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'; |
| | | 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 |
| | | }, |
| | | "& .css-1vooibu-MuiSvgIcon-root": { |
| | | height: ".9em", |
| | | }, |
| | | "& .RaDatagrid-row": { |
| | | cursor: "auto", |
| | | }, |
| | | "& .column-name": {}, |
| | | "& .opt": { |
| | | width: 200, |
| | | }, |
| | | })); |
| | | |
| | | const filters = [ |
| | | <SearchInput source="condition" alwaysOn />, |
| | | <DateInput label='common.time.after' source="timeStart" alwaysOn />, |
| | | <DateInput label='common.time.before' source="timeEnd" alwaysOn />, |
| | | <SearchInput source="condition" alwaysOn />, |
| | | <DateInput label="common.time.after" source="timeStart" alwaysOn />, |
| | | <DateInput label="common.time.before" source="timeEnd" alwaysOn />, |
| | | |
| | | <TextInput source="code" label="table.field.serialRule.code" />, |
| | | <TextInput source="name" label="table.field.serialRule.name" />, |
| | | <TextInput source="delimit" label="table.field.serialRule.delimit" />, |
| | | <TextInput source="reset" label="table.field.serialRule.reset" />, |
| | | <TextInput source="resetDep" label="table.field.serialRule.resetDep" />, |
| | | <TextInput source="currValue" label="table.field.serialRule.currValue" />, |
| | | <TextInput source="lastCode" label="table.field.serialRule.lastCode" />, |
| | | <TextInput source="code" label="table.field.serialRule.code" />, |
| | | <TextInput source="name" label="table.field.serialRule.name" />, |
| | | <TextInput source="delimit" label="table.field.serialRule.delimit" />, |
| | | <TextInput source="reset" label="table.field.serialRule.reset" />, |
| | | <TextInput source="resetDep" label="table.field.serialRule.resetDep" />, |
| | | <TextInput source="currValue" label="table.field.serialRule.currValue" />, |
| | | <TextInput source="lastCode" label="table.field.serialRule.lastCode" />, |
| | | |
| | | <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 |
| | | />, |
| | | ] |
| | | <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 SerialRuleList = () => { |
| | | const translate = useTranslate(); |
| | | const translate = useTranslate(); |
| | | |
| | | const [createDialog, setCreateDialog] = useState(false); |
| | | const [drawerVal, setDrawerVal] = useState(false); |
| | | const [createDialog, setCreateDialog] = useState(false); |
| | | const [drawerVal, setDrawerVal] = useState(false); |
| | | const [detailDialog, setDetailDialog] = useState(false); |
| | | |
| | | 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.serialRule"} |
| | | empty={<EmptyData onClick={() => { setCreateDialog(true) }} />} |
| | | filters={filters} |
| | | sort={{ field: "create_time", order: "desc" }} |
| | | actions={( |
| | | <TopToolbar> |
| | | <FilterButton /> |
| | | <MyCreateButton onClick={() => { setCreateDialog(true) }} /> |
| | | <SelectColumnsButton preferenceKey='serialRule' /> |
| | | <MyExportButton /> |
| | | </TopToolbar> |
| | | )} |
| | | perPage={DEFAULT_PAGE_SIZE} |
| | | > |
| | | <StyledDatagrid |
| | | preferenceKey='serialRule' |
| | | bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />} |
| | | rowClick={(id, resource, record) => false} |
| | | expand={() => <SerialRulePanel />} |
| | | expandSingle={true} |
| | | omit={['id', 'createTime', 'createBy', 'memo']} |
| | | > |
| | | <NumberField source="id" /> |
| | | <TextField source="code" label="table.field.serialRule.code" /> |
| | | <TextField source="name" label="table.field.serialRule.name" /> |
| | | <TextField source="delimit" label="table.field.serialRule.delimit" /> |
| | | <TextField source="reset" label="table.field.serialRule.reset" /> |
| | | <TextField source="resetDep" label="table.field.serialRule.resetDep" /> |
| | | <TextField source="currValue" label="table.field.serialRule.currValue" /> |
| | | <TextField source="lastCode" label="table.field.serialRule.lastCode" /> |
| | | const navigate = useNavigate(); |
| | | const assign = (record) => { |
| | | navigate(`/serialRuleItem?ruleId=${record.id}`); |
| | | }; |
| | | |
| | | <ReferenceField source="updateBy" label="common.field.updateBy" reference="user" link={false} sortable={false}> |
| | | <TextField source="nickname" /> |
| | | </ReferenceField> |
| | | <DateField source="updateTime" label="common.field.updateTime" showTime /> |
| | | <ReferenceField source="createBy" label="common.field.createBy" reference="user" link={false} sortable={false}> |
| | | <TextField source="nickname" /> |
| | | </ReferenceField> |
| | | <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> |
| | | <SerialRuleCreate |
| | | open={createDialog} |
| | | setOpen={setCreateDialog} |
| | | 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.serialRule"} |
| | | empty={ |
| | | <EmptyData |
| | | onClick={() => { |
| | | setCreateDialog(true); |
| | | }} |
| | | /> |
| | | } |
| | | filters={filters} |
| | | sort={{ field: "create_time", order: "desc" }} |
| | | actions={ |
| | | <TopToolbar> |
| | | <FilterButton /> |
| | | <MyCreateButton |
| | | onClick={() => { |
| | | setCreateDialog(true); |
| | | }} |
| | | /> |
| | | <PageDrawer |
| | | title='SerialRule Detail' |
| | | drawerVal={drawerVal} |
| | | setDrawerVal={setDrawerVal} |
| | | > |
| | | </PageDrawer> |
| | | </Box> |
| | | ) |
| | | } |
| | | <SelectColumnsButton preferenceKey="serialRule" /> |
| | | <MyExportButton /> |
| | | </TopToolbar> |
| | | } |
| | | perPage={DEFAULT_PAGE_SIZE} |
| | | > |
| | | <StyledDatagrid |
| | | preferenceKey="serialRule" |
| | | bulkActionButtons={() => ( |
| | | <BulkDeleteButton mutationMode={OPERATE_MODE} /> |
| | | )} |
| | | rowClick={(id, resource, record) => false} |
| | | expand={() => <SerialRulePanel />} |
| | | expandSingle={true} |
| | | omit={["id", "createTime", "createBy", "memo"]} |
| | | > |
| | | <NumberField source="id" /> |
| | | <MyField |
| | | source="code" |
| | | label="table.field.serialRule.code" |
| | | onClick={(event, record, val) => { |
| | | event.stopPropagation(); |
| | | assign(record); |
| | | }} |
| | | /> |
| | | {/* <MyField |
| | | source="code" |
| | | label="table.field.serialRule.code" |
| | | onClick={() => { |
| | | setDetailDialog(true); |
| | | }} |
| | | /> */} |
| | | |
| | | <TextField source="name" label="table.field.serialRule.name" /> |
| | | <TextField source="delimit" label="table.field.serialRule.delimit" /> |
| | | <TextField source="reset" label="table.field.serialRule.reset" /> |
| | | <TextField |
| | | source="resetDep" |
| | | label="table.field.serialRule.resetDep" |
| | | /> |
| | | <TextField |
| | | source="currValue" |
| | | label="table.field.serialRule.currValue" |
| | | /> |
| | | <TextField |
| | | source="lastCode" |
| | | label="table.field.serialRule.lastCode" |
| | | /> |
| | | |
| | | <ReferenceField |
| | | source="updateBy" |
| | | label="common.field.updateBy" |
| | | reference="user" |
| | | link={false} |
| | | sortable={false} |
| | | > |
| | | <TextField source="nickname" /> |
| | | </ReferenceField> |
| | | <DateField |
| | | source="updateTime" |
| | | label="common.field.updateTime" |
| | | showTime |
| | | /> |
| | | <ReferenceField |
| | | source="createBy" |
| | | label="common.field.createBy" |
| | | reference="user" |
| | | link={false} |
| | | sortable={false} |
| | | > |
| | | <TextField source="nickname" /> |
| | | </ReferenceField> |
| | | <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> |
| | | <SerialRuleCreate open={createDialog} setOpen={setCreateDialog} /> |
| | | <SerialRuleDetail open={detailDialog} setOpen={setDetailDialog} /> |
| | | <PageDrawer |
| | | title="SerialRule Detail" |
| | | drawerVal={drawerVal} |
| | | setDrawerVal={setDrawerVal} |
| | | ></PageDrawer> |
| | | </Box> |
| | | ); |
| | | }; |
| | | |
| | | export default SerialRuleList; |
| | |
| | | import React, { useState, useRef, useEffect, useMemo, useCallback } from "react"; |
| | | import { useNavigate } from 'react-router-dom'; |
| | | import React, { |
| | | useState, |
| | | useRef, |
| | | useEffect, |
| | | useMemo, |
| | | useCallback, |
| | | } from "react"; |
| | | import { useNavigate, useLocation } 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'; |
| | | 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 SerialRuleItemCreate from "./SerialRuleItemCreate"; |
| | | import SerialRuleItemPanel from "./SerialRuleItemPanel"; |
| | | 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'; |
| | | 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"; |
| | | import CustomerTopToolBar from "../components/EditTopToolBar"; |
| | | |
| | | const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({ |
| | | '& .css-1vooibu-MuiSvgIcon-root': { |
| | | height: '.9em' |
| | | }, |
| | | '& .RaDatagrid-row': { |
| | | cursor: 'auto' |
| | | }, |
| | | '& .column-name': { |
| | | }, |
| | | '& .opt': { |
| | | width: 200 |
| | | }, |
| | | "& .css-1vooibu-MuiSvgIcon-root": { |
| | | height: ".9em", |
| | | }, |
| | | "& .RaDatagrid-row": { |
| | | cursor: "auto", |
| | | }, |
| | | "& .column-name": {}, |
| | | "& .opt": { |
| | | width: 200, |
| | | }, |
| | | })); |
| | | |
| | | const filters = [ |
| | | <SearchInput source="condition" alwaysOn />, |
| | | <DateInput label='common.time.after' source="timeStart" alwaysOn />, |
| | | <DateInput label='common.time.before' source="timeEnd" alwaysOn />, |
| | | <SearchInput source="condition" alwaysOn />, |
| | | <DateInput label="common.time.after" source="timeStart" alwaysOn />, |
| | | <DateInput label="common.time.before" source="timeEnd" alwaysOn />, |
| | | |
| | | <NumberInput source="ruleId" label="table.field.serialRuleItem.ruleId" />, |
| | | <TextInput source="wkType" label="table.field.serialRuleItem.wkType" />, |
| | | <TextInput source="feildValue" label="table.field.serialRuleItem.feildValue" />, |
| | | <NumberInput source="len" label="table.field.serialRuleItem.len" />, |
| | | <NumberInput source="lenStr" label="table.field.serialRuleItem.lenStr" />, |
| | | <NumberInput source="sort" label="table.field.serialRuleItem.sort" />, |
| | | <NumberInput source="ruleId" label="table.field.serialRuleItem.ruleId" />, |
| | | <TextInput source="wkType" label="table.field.serialRuleItem.wkType" />, |
| | | <TextInput |
| | | source="feildValue" |
| | | label="table.field.serialRuleItem.feildValue" |
| | | />, |
| | | <NumberInput source="len" label="table.field.serialRuleItem.len" />, |
| | | <NumberInput source="lenStr" label="table.field.serialRuleItem.lenStr" />, |
| | | <NumberInput source="sort" label="table.field.serialRuleItem.sort" />, |
| | | |
| | | <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 |
| | | />, |
| | | ] |
| | | <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 SerialRuleItemList = () => { |
| | | const translate = useTranslate(); |
| | | const translate = useTranslate(); |
| | | const [createDialog, setCreateDialog] = useState(false); |
| | | const [drawerVal, setDrawerVal] = useState(false); |
| | | |
| | | const [createDialog, setCreateDialog] = useState(false); |
| | | const [drawerVal, setDrawerVal] = useState(false); |
| | | const location = useLocation(); |
| | | const queryParams = new URLSearchParams(location.search); |
| | | const ruleId = queryParams.get("ruleId"); |
| | | |
| | | 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.serialRuleItem"} |
| | | empty={<EmptyData onClick={() => { setCreateDialog(true) }} />} |
| | | filters={filters} |
| | | sort={{ field: "create_time", order: "desc" }} |
| | | actions={( |
| | | <TopToolbar> |
| | | <FilterButton /> |
| | | <MyCreateButton onClick={() => { setCreateDialog(true) }} /> |
| | | <SelectColumnsButton preferenceKey='serialRuleItem' /> |
| | | <MyExportButton /> |
| | | </TopToolbar> |
| | | )} |
| | | perPage={DEFAULT_PAGE_SIZE} |
| | | > |
| | | <StyledDatagrid |
| | | preferenceKey='serialRuleItem' |
| | | bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />} |
| | | rowClick={(id, resource, record) => false} |
| | | expand={() => <SerialRuleItemPanel />} |
| | | expandSingle={true} |
| | | omit={['id', 'createTime', 'createBy', 'memo']} |
| | | > |
| | | <NumberField source="id" /> |
| | | <NumberField source="ruleId" label="table.field.serialRuleItem.ruleId" /> |
| | | <TextField source="wkType" label="table.field.serialRuleItem.wkType" /> |
| | | <TextField source="feildValue" label="table.field.serialRuleItem.feildValue" /> |
| | | <NumberField source="len" label="table.field.serialRuleItem.len" /> |
| | | <NumberField source="lenStr" label="table.field.serialRuleItem.lenStr" /> |
| | | <NumberField source="sort" label="table.field.serialRuleItem.sort" /> |
| | | |
| | | <ReferenceField source="updateBy" label="common.field.updateBy" reference="user" link={false} sortable={false}> |
| | | <TextField source="nickname" /> |
| | | </ReferenceField> |
| | | <DateField source="updateTime" label="common.field.updateTime" showTime /> |
| | | <ReferenceField source="createBy" label="common.field.createBy" reference="user" link={false} sortable={false}> |
| | | <TextField source="nickname" /> |
| | | </ReferenceField> |
| | | <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> |
| | | <SerialRuleItemCreate |
| | | open={createDialog} |
| | | setOpen={setCreateDialog} |
| | | return ( |
| | | <> |
| | | {ruleId && <CustomerTopToolBar backPrevious={true} />} |
| | | <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.serialRuleItem"} |
| | | empty={ |
| | | <EmptyData |
| | | onClick={() => { |
| | | setCreateDialog(true); |
| | | }} |
| | | /> |
| | | <PageDrawer |
| | | title='SerialRuleItem Detail' |
| | | drawerVal={drawerVal} |
| | | setDrawerVal={setDrawerVal} |
| | | } |
| | | filters={filters} |
| | | filter={ruleId ? { ruleId } : undefined} |
| | | sort={{ field: "create_time", order: "desc" }} |
| | | actions={ |
| | | <TopToolbar> |
| | | <FilterButton /> |
| | | <MyCreateButton |
| | | onClick={() => { |
| | | setCreateDialog(true); |
| | | }} |
| | | /> |
| | | <SelectColumnsButton preferenceKey="serialRuleItem" /> |
| | | <MyExportButton /> |
| | | </TopToolbar> |
| | | } |
| | | perPage={DEFAULT_PAGE_SIZE} |
| | | > |
| | | <StyledDatagrid |
| | | preferenceKey="serialRuleItem" |
| | | bulkActionButtons={() => ( |
| | | <BulkDeleteButton mutationMode={OPERATE_MODE} /> |
| | | )} |
| | | rowClick={(id, resource, record) => false} |
| | | expand={() => <SerialRuleItemPanel />} |
| | | expandSingle={true} |
| | | omit={["id", "createTime", "createBy", "memo"]} |
| | | > |
| | | <NumberField source="id" /> |
| | | <NumberField |
| | | source="ruleId" |
| | | label="table.field.serialRuleItem.ruleId" |
| | | /> |
| | | <TextField |
| | | source="wkType" |
| | | label="table.field.serialRuleItem.wkType" |
| | | /> |
| | | <TextField |
| | | source="feildValue" |
| | | label="table.field.serialRuleItem.feildValue" |
| | | /> |
| | | <NumberField source="len" label="table.field.serialRuleItem.len" /> |
| | | <NumberField |
| | | source="lenStr" |
| | | label="table.field.serialRuleItem.lenStr" |
| | | /> |
| | | <NumberField |
| | | source="sort" |
| | | label="table.field.serialRuleItem.sort" |
| | | /> |
| | | |
| | | <ReferenceField |
| | | source="updateBy" |
| | | label="common.field.updateBy" |
| | | reference="user" |
| | | link={false} |
| | | sortable={false} |
| | | > |
| | | </PageDrawer> |
| | | </Box> |
| | | ) |
| | | } |
| | | <TextField source="nickname" /> |
| | | </ReferenceField> |
| | | <DateField |
| | | source="updateTime" |
| | | label="common.field.updateTime" |
| | | showTime |
| | | /> |
| | | <ReferenceField |
| | | source="createBy" |
| | | label="common.field.createBy" |
| | | reference="user" |
| | | link={false} |
| | | sortable={false} |
| | | > |
| | | <TextField source="nickname" /> |
| | | </ReferenceField> |
| | | <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> |
| | | <SerialRuleItemCreate open={createDialog} setOpen={setCreateDialog} /> |
| | | <PageDrawer |
| | | title="SerialRuleItem Detail" |
| | | drawerVal={drawerVal} |
| | | setDrawerVal={setDrawerVal} |
| | | ></PageDrawer> |
| | | </Box> |
| | | </> |
| | | ); |
| | | }; |
| | | |
| | | export default SerialRuleItemList; |
| | |
| | | import React, { useState, useRef, useEffect, useMemo, useCallback } from "react"; |
| | | import { useNavigate } from 'react-router-dom'; |
| | | 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, |
| | | useListContext, |
| | | useCreatePath, |
| | | TextField, |
| | | NumberField, |
| | | DateField, |
| | | BooleanField, |
| | | ReferenceField, |
| | | TextInput, |
| | | DateTimeInput, |
| | | DateInput, |
| | | SelectInput, |
| | | NumberInput, |
| | | ReferenceInput, |
| | | ReferenceArrayInput, |
| | | AutocompleteInput, |
| | | DeleteButton, |
| | | FunctionField, |
| | | } from 'react-admin'; |
| | | import { Box, Typography, Card, Stack, LinearProgress } from '@mui/material'; |
| | | import { styled } from '@mui/material/styles'; |
| | | List, |
| | | DatagridConfigurable, |
| | | SearchInput, |
| | | TopToolbar, |
| | | SelectColumnsButton, |
| | | EditButton, |
| | | FilterButton, |
| | | CreateButton, |
| | | ExportButton, |
| | | BulkDeleteButton, |
| | | WrapperField, |
| | | useRecordContext, |
| | | useTranslate, |
| | | useListContext, |
| | | useCreatePath, |
| | | TextField, |
| | | NumberField, |
| | | DateField, |
| | | BooleanField, |
| | | ReferenceField, |
| | | TextInput, |
| | | DateTimeInput, |
| | | DateInput, |
| | | SelectInput, |
| | | NumberInput, |
| | | ReferenceInput, |
| | | ReferenceArrayInput, |
| | | AutocompleteInput, |
| | | DeleteButton, |
| | | FunctionField, |
| | | } from "react-admin"; |
| | | import { Box, Typography, Card, Stack, LinearProgress } from "@mui/material"; |
| | | import { styled } from "@mui/material/styles"; |
| | | import UserCreate from "./UserCreate"; |
| | | import UserPanel from "./UserPanel"; |
| | | import EmptyData from "@/page/components/EmptyData"; |
| | | import MyCreateButton from "@/page/components/MyCreateButton"; |
| | | import MyExportButton from '@/page/components/MyExportButton'; |
| | | import MyExportButton from "@/page/components/MyExportButton"; |
| | | import PageDrawer from "@/page/components/PageDrawer"; |
| | | import MyField from "@/page/components/MyField"; |
| | | import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting'; |
| | | import * as Common from '@/utils/common'; |
| | | import { |
| | | PAGE_DRAWER_WIDTH, |
| | | OPERATE_MODE, |
| | | DEFAULT_PAGE_SIZE, |
| | | } from "@/config/setting"; |
| | | import * as Common from "@/utils/common"; |
| | | import UserListAside from "./UserListAside"; |
| | | import RolesField from './RolesField'; |
| | | import RolesField from "./RolesField"; |
| | | |
| | | const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({ |
| | | '& .css-1vooibu-MuiSvgIcon-root': { |
| | | height: '.9em' |
| | | }, |
| | | '& .RaDatagrid-row': { |
| | | cursor: 'auto' |
| | | }, |
| | | '& .column-username': { |
| | | maxWidth: '10em', |
| | | overflow: 'hidden', |
| | | textOverflow: 'ellipsis', |
| | | whiteSpace: 'nowrap', |
| | | }, |
| | | '& .column-nickname': { |
| | | maxWidth: '10em', |
| | | overflow: 'hidden', |
| | | textOverflow: 'ellipsis', |
| | | whiteSpace: 'nowrap', |
| | | }, |
| | | '& .column-deptId': { |
| | | maxWidth: '10em', |
| | | overflow: 'hidden', |
| | | textOverflow: 'ellipsis', |
| | | whiteSpace: 'nowrap', |
| | | }, |
| | | '& .opt': { |
| | | width: 200 |
| | | }, |
| | | '& .column-statusBool': { |
| | | maxWidth: 60 |
| | | }, |
| | | "& .css-1vooibu-MuiSvgIcon-root": { |
| | | height: ".9em", |
| | | }, |
| | | "& .RaDatagrid-row": { |
| | | cursor: "auto", |
| | | }, |
| | | "& .column-username": { |
| | | maxWidth: "10em", |
| | | overflow: "hidden", |
| | | textOverflow: "ellipsis", |
| | | whiteSpace: "nowrap", |
| | | }, |
| | | "& .column-nickname": { |
| | | maxWidth: "10em", |
| | | overflow: "hidden", |
| | | textOverflow: "ellipsis", |
| | | whiteSpace: "nowrap", |
| | | }, |
| | | "& .column-deptId": { |
| | | maxWidth: "10em", |
| | | overflow: "hidden", |
| | | textOverflow: "ellipsis", |
| | | whiteSpace: "nowrap", |
| | | }, |
| | | "& .opt": { |
| | | width: 200, |
| | | }, |
| | | "& .column-statusBool": { |
| | | maxWidth: 60, |
| | | }, |
| | | })); |
| | | |
| | | const filters = [ |
| | | // <SearchInput source="condition" alwaysOn />, |
| | | <DateInput label='common.time.after' source="timeStart" alwaysOn />, |
| | | <DateInput label='common.time.before' source="timeEnd" alwaysOn />, |
| | | // <SearchInput source="condition" alwaysOn />, |
| | | <DateInput label="common.time.after" source="timeStart" alwaysOn />, |
| | | <DateInput label="common.time.before" source="timeEnd" alwaysOn />, |
| | | |
| | | <TextInput source="username" label="table.field.user.username" />, |
| | | <TextInput source="nickname" label="table.field.user.nickname" />, |
| | | <TextInput source="code" label="table.field.user.code" />, |
| | | <SelectInput source="sex" label="table.field.user.sex" |
| | | choices={[ |
| | | { id: 0, name: 'table.field.user.sexes.unknown' }, |
| | | { id: 1, name: "table.field.user.sexes.male" }, |
| | | { id: 2, name: 'table.field.user.sexes.female' }, |
| | | ]} |
| | | />, |
| | | <TextInput source="phone" label="table.field.user.phone" />, |
| | | <TextInput source="email" label="table.field.user.email" />, |
| | | // <ReferenceInput source="deptId" label="table.field.user.deptId" reference="dept"> |
| | | // <AutocompleteInput label="table.field.user.deptId" optionText="name" filterToQuery={(val) => ({ name: val })} /> |
| | | // </ReferenceInput>, |
| | | <TextInput source="realName" label="table.field.user.realName" />, |
| | | <TextInput source="idCard" label="table.field.user.idCard" />, |
| | | <TextInput source="username" label="table.field.user.username" />, |
| | | <TextInput source="nickname" label="table.field.user.nickname" />, |
| | | <TextInput source="code" label="table.field.user.code" />, |
| | | <SelectInput |
| | | source="sex" |
| | | label="table.field.user.sex" |
| | | choices={[ |
| | | { id: 0, name: "table.field.user.sexes.unknown" }, |
| | | { id: 1, name: "table.field.user.sexes.male" }, |
| | | { id: 2, name: "table.field.user.sexes.female" }, |
| | | ]} |
| | | />, |
| | | <TextInput source="phone" label="table.field.user.phone" />, |
| | | <TextInput source="email" label="table.field.user.email" />, |
| | | // <ReferenceInput source="deptId" label="table.field.user.deptId" reference="dept"> |
| | | // <AutocompleteInput label="table.field.user.deptId" optionText="name" filterToQuery={(val) => ({ name: val })} /> |
| | | // </ReferenceInput>, |
| | | <TextInput source="realName" label="table.field.user.realName" />, |
| | | <TextInput source="idCard" label="table.field.user.idCard" />, |
| | | |
| | | <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' }, |
| | | ]} |
| | | />, |
| | | ] |
| | | <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" }, |
| | | ]} |
| | | />, |
| | | ]; |
| | | |
| | | const UserListContent = (props) => { |
| | | const translate = useTranslate(); |
| | | const { isLoading } = useListContext(); |
| | | const translate = useTranslate(); |
| | | const { isLoading } = useListContext(); |
| | | |
| | | return ( |
| | | <Box sx={{ position: 'relative' }}> |
| | | {isLoading && ( |
| | | <LinearProgress |
| | | sx={{ |
| | | height: "2px", |
| | | position: 'absolute', |
| | | top: 0, |
| | | left: 0, |
| | | right: 0, |
| | | }} |
| | | /> |
| | | )} |
| | | <StyledDatagrid |
| | | preferenceKey='user' |
| | | bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />} |
| | | rowClick={(id, resource, record) => false} |
| | | expand={() => <UserPanel />} |
| | | expandSingle={true} |
| | | omit={['id', 'email', 'idCard', 'birthday', 'realName', 'updateTime', 'createTime', 'memo']} |
| | | > |
| | | <NumberField source="id" /> |
| | | <TextField source="username" label="table.field.user.username" /> |
| | | <ReferenceField source="deptId" label="table.field.user.deptId" reference="dept" link={false} sortable={false}> |
| | | <TextField source="name" /> |
| | | </ReferenceField> |
| | | <TextField source="nickname" label="table.field.user.nickname" /> |
| | | <TextField source="code" label="table.field.user.code" /> |
| | | <FunctionField |
| | | label="table.field.user.sex" |
| | | sortable={false} |
| | | render={(record) => { |
| | | switch (record.sex) { |
| | | case 0: |
| | | return translate('table.field.user.sexes.unknown'); |
| | | case 1: |
| | | return translate('table.field.user.sexes.male'); |
| | | case 2: |
| | | return translate('table.field.user.sexes.female'); |
| | | default: |
| | | return ''; |
| | | } |
| | | }} |
| | | /> |
| | | <TextField source="phone" label="table.field.user.phone" /> |
| | | <TextField source="email" label="table.field.user.email" /> |
| | | <TextField source="realName" label="table.field.user.realName" /> |
| | | <TextField source="idCard" label="table.field.user.idCard" /> |
| | | <TextField source="birthday" label="table.field.user.birthday" /> |
| | | <RolesField source="roles" label="table.field.user.role" sortable={false} /> |
| | | <DateField source="updateTime" label="common.field.updateTime" showTime /> |
| | | <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> |
| | | </Box> |
| | | ) |
| | | } |
| | | return ( |
| | | <Box sx={{ position: "relative" }}> |
| | | {isLoading && ( |
| | | <LinearProgress |
| | | sx={{ |
| | | height: "2px", |
| | | position: "absolute", |
| | | top: 0, |
| | | left: 0, |
| | | right: 0, |
| | | }} |
| | | /> |
| | | )} |
| | | <StyledDatagrid |
| | | preferenceKey="user" |
| | | bulkActionButtons={() => ( |
| | | <BulkDeleteButton mutationMode={OPERATE_MODE} /> |
| | | )} |
| | | rowClick={(id, resource, record) => false} |
| | | expand={() => <UserPanel />} |
| | | expandSingle={true} |
| | | omit={[ |
| | | "id", |
| | | "email", |
| | | "idCard", |
| | | "birthday", |
| | | "realName", |
| | | "updateTime", |
| | | "createTime", |
| | | "memo", |
| | | ]} |
| | | > |
| | | <NumberField source="id" /> |
| | | <TextField source="username" label="table.field.user.username" /> |
| | | <ReferenceField |
| | | source="deptId" |
| | | label="table.field.user.deptId" |
| | | reference="dept" |
| | | link={false} |
| | | sortable={false} |
| | | > |
| | | <TextField source="name" /> |
| | | </ReferenceField> |
| | | <TextField source="nickname" label="table.field.user.nickname" /> |
| | | <TextField source="code" label="table.field.user.code" /> |
| | | <FunctionField |
| | | label="table.field.user.sex" |
| | | sortable={false} |
| | | render={(record) => { |
| | | switch (record.sex) { |
| | | case 0: |
| | | return translate("table.field.user.sexes.unknown"); |
| | | case 1: |
| | | return translate("table.field.user.sexes.male"); |
| | | case 2: |
| | | return translate("table.field.user.sexes.female"); |
| | | default: |
| | | return ""; |
| | | } |
| | | }} |
| | | /> |
| | | <TextField source="phone" label="table.field.user.phone" /> |
| | | <TextField source="email" label="table.field.user.email" /> |
| | | <TextField source="realName" label="table.field.user.realName" /> |
| | | <TextField source="idCard" label="table.field.user.idCard" /> |
| | | <TextField source="birthday" label="table.field.user.birthday" /> |
| | | <RolesField |
| | | source="roles" |
| | | label="table.field.user.role" |
| | | sortable={false} |
| | | /> |
| | | <DateField |
| | | source="updateTime" |
| | | label="common.field.updateTime" |
| | | showTime |
| | | /> |
| | | <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> |
| | | </Box> |
| | | ); |
| | | }; |
| | | |
| | | const UserList = () => { |
| | | const translate = useTranslate(); |
| | | const translate = useTranslate(); |
| | | |
| | | const [createDialog, setCreateDialog] = useState(false); |
| | | const [drawerVal, setDrawerVal] = useState(false); |
| | | const [createDialog, setCreateDialog] = useState(false); |
| | | const [drawerVal, setDrawerVal] = useState(false); |
| | | |
| | | 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.user"} |
| | | empty={<EmptyData onClick={() => { setCreateDialog(true) }} />} |
| | | filters={filters} |
| | | sort={{ field: "create_time", order: "desc" }} |
| | | actions={( |
| | | <TopToolbar> |
| | | <FilterButton /> |
| | | <MyCreateButton onClick={() => { setCreateDialog(true) }} /> |
| | | <SelectColumnsButton preferenceKey='user' /> |
| | | <MyExportButton /> |
| | | </TopToolbar> |
| | | )} |
| | | perPage={DEFAULT_PAGE_SIZE} |
| | | aside={<UserListAside />} |
| | | > |
| | | <UserListContent /> |
| | | </List> |
| | | <UserCreate |
| | | open={createDialog} |
| | | setOpen={setCreateDialog} |
| | | 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.user"} |
| | | empty={ |
| | | <EmptyData |
| | | onClick={() => { |
| | | setCreateDialog(true); |
| | | }} |
| | | /> |
| | | } |
| | | filters={filters} |
| | | sort={{ field: "create_time", order: "desc" }} |
| | | actions={ |
| | | <TopToolbar> |
| | | <FilterButton /> |
| | | <MyCreateButton |
| | | onClick={() => { |
| | | setCreateDialog(true); |
| | | }} |
| | | /> |
| | | <PageDrawer |
| | | title='User Detail' |
| | | drawerVal={drawerVal} |
| | | setDrawerVal={setDrawerVal} |
| | | > |
| | | </PageDrawer> |
| | | </Box> |
| | | ) |
| | | } |
| | | <SelectColumnsButton preferenceKey="user" /> |
| | | <MyExportButton /> |
| | | </TopToolbar> |
| | | } |
| | | perPage={DEFAULT_PAGE_SIZE} |
| | | aside={<UserListAside />} |
| | | > |
| | | <UserListContent /> |
| | | </List> |
| | | <UserCreate open={createDialog} setOpen={setCreateDialog} /> |
| | | <PageDrawer |
| | | title="User Detail" |
| | | drawerVal={drawerVal} |
| | | setDrawerVal={setDrawerVal} |
| | | ></PageDrawer> |
| | | </Box> |
| | | ); |
| | | }; |
| | | |
| | | export default UserList; |
| | |
| | | import React, { useState, useRef, useEffect, useMemo } from "react"; |
| | | import { Box, Card, CardContent, Grid, Typography, Tooltip } from '@mui/material'; |
| | | import { |
| | | useTranslate, |
| | | useRecordContext, |
| | | } from 'react-admin'; |
| | | Box, |
| | | Card, |
| | | CardContent, |
| | | Grid, |
| | | Typography, |
| | | Tooltip, |
| | | } from "@mui/material"; |
| | | import { useTranslate, useRecordContext } from "react-admin"; |
| | | import PanelTypography from "@/page/components/PanelTypography"; |
| | | import * as Common from '@/utils/common' |
| | | import * as Common from "@/utils/common"; |
| | | |
| | | const UserPanel = () => { |
| | | const record = useRecordContext(); |
| | | if (!record) return null; |
| | | const translate = useTranslate(); |
| | | return ( |
| | | <> |
| | | <Card sx={{ width: { xs: 300, sm: 500, md: 600, lg: 800 }, margin: 'auto' }}> |
| | | <CardContent> |
| | | <Grid container spacing={2}> |
| | | <Grid item xs={12} sx={{ display: 'flex', justifyContent: 'space-between' }}> |
| | | <Typography variant="h6" gutterBottom align="left" sx={{ |
| | | maxWidth: { xs: '100px', sm: '180px', md: '260px', lg: '360px' }, |
| | | whiteSpace: 'nowrap', |
| | | overflow: 'hidden', |
| | | textOverflow: 'ellipsis', |
| | | }}> |
| | | {Common.camelToPascalWithSpaces(translate('table.field.user.nickname'))}: {record.nickname} |
| | | </Typography> |
| | | {/* inherit, primary, secondary, textPrimary, textSecondary, error */} |
| | | <Typography variant="h6" gutterBottom align="right" > |
| | | ID: {record.id} |
| | | </Typography> |
| | | </Grid> |
| | | </Grid> |
| | | <Grid container spacing={2}> |
| | | <Grid item xs={12} container alignContent="flex-end"> |
| | | <Typography variant="caption" color="textSecondary" sx={{ wordWrap: 'break-word', wordBreak: 'break-all' }}> |
| | | {Common.camelToPascalWithSpaces(translate('common.field.memo'))}:{record.memo} |
| | | </Typography> |
| | | </Grid> |
| | | </Grid> |
| | | <Box height={20}> </Box> |
| | | <Grid container spacing={2}> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.username" |
| | | property={record.username} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.nickname" |
| | | property={record.nickname} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.avatar" |
| | | property={record.avatar} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.code" |
| | | property={record.code} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.sex" |
| | | property={record.sex$} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.phone" |
| | | property={record.phone} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.email" |
| | | property={record.email} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.emailVerified" |
| | | property={record.emailVerified$} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.deptId" |
| | | property={record.deptId$} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.realName" |
| | | property={record.realName} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.idCard" |
| | | property={record.idCard} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.birthday" |
| | | property={record.birthday} |
| | | /> |
| | | </Grid> |
| | | {/* <Grid item xs={6}> |
| | | const record = useRecordContext(); |
| | | if (!record) return null; |
| | | const translate = useTranslate(); |
| | | return ( |
| | | <> |
| | | <Card |
| | | sx={{ width: { xs: 300, sm: 500, md: 600, lg: 800 }, margin: "auto" }} |
| | | > |
| | | <CardContent> |
| | | <Grid container spacing={2}> |
| | | <Grid |
| | | item |
| | | xs={12} |
| | | sx={{ display: "flex", justifyContent: "space-between" }} |
| | | > |
| | | <Typography |
| | | variant="h6" |
| | | gutterBottom |
| | | align="left" |
| | | sx={{ |
| | | maxWidth: { |
| | | xs: "100px", |
| | | sm: "180px", |
| | | md: "260px", |
| | | lg: "360px", |
| | | }, |
| | | whiteSpace: "nowrap", |
| | | overflow: "hidden", |
| | | textOverflow: "ellipsis", |
| | | }} |
| | | > |
| | | {Common.camelToPascalWithSpaces( |
| | | translate("table.field.user.nickname"), |
| | | )} |
| | | : {record.nickname} |
| | | </Typography> |
| | | {/* inherit, primary, secondary, textPrimary, textSecondary, error */} |
| | | <Typography variant="h6" gutterBottom align="right"> |
| | | ID: {record.id} |
| | | </Typography> |
| | | </Grid> |
| | | </Grid> |
| | | <Grid container spacing={2}> |
| | | <Grid item xs={12} container alignContent="flex-end"> |
| | | <Typography |
| | | variant="caption" |
| | | color="textSecondary" |
| | | sx={{ wordWrap: "break-word", wordBreak: "break-all" }} |
| | | > |
| | | {Common.camelToPascalWithSpaces(translate("common.field.memo"))} |
| | | :{record.memo} |
| | | </Typography> |
| | | </Grid> |
| | | </Grid> |
| | | <Box height={20}> </Box> |
| | | <Grid container spacing={2}> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.username" |
| | | property={record.username} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.nickname" |
| | | property={record.nickname} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.avatar" |
| | | property={record.avatar} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.code" |
| | | property={record.code} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.sex" |
| | | property={record.sex$} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.phone" |
| | | property={record.phone} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.email" |
| | | property={record.email} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.emailVerified" |
| | | property={record.emailVerified$} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.deptId" |
| | | property={record.deptId$} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.realName" |
| | | property={record.realName} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.idCard" |
| | | property={record.idCard} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.birthday" |
| | | property={record.birthday} |
| | | /> |
| | | </Grid> |
| | | {/* <Grid item xs={6}> |
| | | <PanelTypography |
| | | title="table.field.user.introduction" |
| | | property={record.introduction} |
| | | /> |
| | | </Grid> */} |
| | | </Grid> |
| | | </CardContent> |
| | | </Card > |
| | | </> |
| | | ); |
| | | </Grid> |
| | | </CardContent> |
| | | </Card> |
| | | </> |
| | | ); |
| | | }; |
| | | |
| | | export default UserPanel; |
| | |
| | | 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'; |
| | | 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'; |
| | | 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 WarehouseAreasCreate = (props) => { |
| | | const { open, setOpen } = props; |
| | | const { open, setOpen } = props; |
| | | |
| | | const translate = useTranslate(); |
| | | const notify = useNotify(); |
| | | const translate = useTranslate(); |
| | | const notify = useNotify(); |
| | | |
| | | const handleClose = (event, reason) => { |
| | | if (reason !== "backdropClick") { |
| | | setOpen(false); |
| | | } |
| | | }; |
| | | const handleClose = (event, reason) => { |
| | | if (reason !== "backdropClick") { |
| | | setOpen(false); |
| | | } |
| | | }; |
| | | |
| | | const handleSuccess = async (data) => { |
| | | setOpen(false); |
| | | notify('common.response.success'); |
| | | }; |
| | | 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 } }); |
| | | }; |
| | | 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 }} |
| | | 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, |
| | | }} |
| | | > |
| | | <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.warehouseAreas.uuid" |
| | | source="uuid" |
| | | parse={v => v} |
| | | validate={[required()]} |
| | | autoFocus |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.warehouseAreas.name" |
| | | source="name" |
| | | validate={[required()]} |
| | | parse={v => v} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.warehouseAreas.code" |
| | | source="code" |
| | | validate={[required()]} |
| | | parse={v => v} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <ReferenceInput |
| | | source="shipperId" |
| | | reference="shipper" |
| | | > |
| | | <AutocompleteInput |
| | | label="table.field.warehouseAreas.shipperId" |
| | | optionText="name" |
| | | validate={[required()]} |
| | | filterToQuery={(val) => ({ name: val })} |
| | | /> |
| | | </ReferenceInput> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <NumberInput |
| | | label="table.field.warehouseAreas.supplierId" |
| | | source="supplierId" |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <SelectInput |
| | | label="table.field.warehouseAreas.flagMinus" |
| | | source="flagMinus" |
| | | validate={[required()]} |
| | | choices={[ |
| | | { id: 0, name: '否' }, |
| | | { id: 1, name: '是' }, |
| | | ]} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <SelectInput |
| | | label="table.field.warehouseAreas.flagLabelMange" |
| | | source="flagLabelMange" |
| | | validate={[required()]} |
| | | choices={[ |
| | | { id: 0, name: ' 否' }, |
| | | { id: 1, name: ' 是' }, |
| | | ]} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <SelectInput |
| | | label="table.field.warehouseAreas.flagMix" |
| | | source="flagMix" |
| | | validate={[required()]} |
| | | choices={[ |
| | | { id: 0, name: '否' }, |
| | | { id: 1, name: '是' }, |
| | | ]} |
| | | /> |
| | | </Grid> |
| | | {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.warehouseAreas.uuid" |
| | | source="uuid" |
| | | parse={(v) => v} |
| | | validate={[required()]} |
| | | autoFocus |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.warehouseAreas.name" |
| | | source="name" |
| | | validate={[required()]} |
| | | parse={(v) => v} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <TextInput |
| | | label="table.field.warehouseAreas.code" |
| | | source="code" |
| | | validate={[required()]} |
| | | parse={(v) => v} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <ReferenceInput source="shipperId" reference="shipper"> |
| | | <AutocompleteInput |
| | | label="table.field.warehouseAreas.shipperId" |
| | | optionText="name" |
| | | validate={[required()]} |
| | | filterToQuery={(val) => ({ name: val })} |
| | | /> |
| | | </ReferenceInput> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <NumberInput |
| | | label="table.field.warehouseAreas.supplierId" |
| | | source="supplierId" |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <SelectInput |
| | | label="table.field.warehouseAreas.flagMinus" |
| | | source="flagMinus" |
| | | validate={[required()]} |
| | | choices={[ |
| | | { id: 0, name: "否" }, |
| | | { id: 1, name: "是" }, |
| | | ]} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <SelectInput |
| | | label="table.field.warehouseAreas.flagLabelMange" |
| | | source="flagLabelMange" |
| | | validate={[required()]} |
| | | choices={[ |
| | | { id: 0, name: " 否" }, |
| | | { id: 1, name: " 是" }, |
| | | ]} |
| | | /> |
| | | </Grid> |
| | | <Grid item xs={6} display="flex" gap={1}> |
| | | <SelectInput |
| | | label="table.field.warehouseAreas.flagMix" |
| | | source="flagMix" |
| | | validate={[required()]} |
| | | choices={[ |
| | | { id: 0, name: "否" }, |
| | | { id: 1, name: "是" }, |
| | | ]} |
| | | /> |
| | | </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> |
| | | </> |
| | | ) |
| | | } |
| | | <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 WarehouseAreasCreate; |