| New file |
| | |
| | | import React, { useMemo, useRef, useState } from "react"; |
| | | import DownloadIcon from "@mui/icons-material/GetApp"; |
| | | import PrintOutlinedIcon from "@mui/icons-material/PrintOutlined"; |
| | | import SaveIcon from '@mui/icons-material/Save'; |
| | | import { |
| | | Box, |
| | | Button as MuiButton, |
| | | CircularProgress, |
| | | Dialog, |
| | | DialogActions, |
| | | DialogContent, |
| | | DialogTitle, |
| | | Paper, |
| | | Table, |
| | | TableBody, |
| | | TableCell, |
| | | TableContainer, |
| | | TableHead, |
| | | TableRow, |
| | | Typography, |
| | | } from '@mui/material'; |
| | | import { |
| | | Button, |
| | | useDataProvider, |
| | | useListContext, |
| | | useNotify, |
| | | useStore, |
| | | useTranslate, |
| | | useUnselectAll, |
| | | } from "react-admin"; |
| | | import { useReactToPrint } from "react-to-print"; |
| | | import DialogCloseButton from "./DialogCloseButton"; |
| | | import { getValueBySource, resolveVisibleColumns } from "./listExportPrintUtils"; |
| | | |
| | | const PREVIEW_ROW_LIMIT = 200; |
| | | |
| | | const formatColumnLabel = (label, translate) => { |
| | | if (!label) { |
| | | return ''; |
| | | } |
| | | |
| | | if (typeof label !== 'string') { |
| | | return String(label); |
| | | } |
| | | |
| | | if (label.includes('.')) { |
| | | return translate(label, { _: label }); |
| | | } |
| | | |
| | | return label; |
| | | }; |
| | | |
| | | const formatValue = (value, fieldType) => { |
| | | if (value == null) { |
| | | return ''; |
| | | } |
| | | |
| | | if (fieldType === 'boolean') { |
| | | return value ? 'true' : 'false'; |
| | | } |
| | | |
| | | return String(value); |
| | | }; |
| | | |
| | | const padNumber = (value) => String(value).padStart(2, '0'); |
| | | |
| | | const formatDate = (date = new Date()) => ( |
| | | `${date.getFullYear()}年${padNumber(date.getMonth() + 1)}月${padNumber(date.getDate())}日` |
| | | ); |
| | | |
| | | const formatDateTime = (date = new Date()) => ( |
| | | `${date.getFullYear()}/${padNumber(date.getMonth() + 1)}/${padNumber(date.getDate())} ${padNumber(date.getHours())}:${padNumber(date.getMinutes())}:${padNumber(date.getSeconds())}` |
| | | ); |
| | | |
| | | const getPrintLayoutConfig = (columnCount) => { |
| | | if (columnCount >= 16) { |
| | | return { |
| | | bodyFontSize: 8, |
| | | headerFontSize: 8, |
| | | cellPaddingX: 0.35, |
| | | cellPaddingY: 0.4, |
| | | sequenceWidth: 36, |
| | | }; |
| | | } |
| | | |
| | | if (columnCount >= 12) { |
| | | return { |
| | | bodyFontSize: 9, |
| | | headerFontSize: 9, |
| | | cellPaddingX: 0.45, |
| | | cellPaddingY: 0.5, |
| | | sequenceWidth: 42, |
| | | }; |
| | | } |
| | | |
| | | return { |
| | | bodyFontSize: 10, |
| | | headerFontSize: 10, |
| | | cellPaddingX: 0.6, |
| | | cellPaddingY: 0.65, |
| | | sequenceWidth: 52, |
| | | }; |
| | | }; |
| | | |
| | | const getPrintOperator = () => { |
| | | try { |
| | | const user = JSON.parse(localStorage.getItem('user')); |
| | | return user?.fullName || user?.username || 'SYSTEM'; |
| | | } catch (error) { |
| | | return 'SYSTEM'; |
| | | } |
| | | }; |
| | | |
| | | const buildReportMeta = (reportTitle, count = 0) => ({ |
| | | reportTitle, |
| | | reportDate: formatDate(), |
| | | printedAt: formatDateTime(), |
| | | operator: getPrintOperator(), |
| | | count, |
| | | }); |
| | | |
| | | const getRecordKey = (record, index) => ( |
| | | record?.id ?? record?.barcode ?? record?.code ?? `row-${index}` |
| | | ); |
| | | |
| | | const PrintReportContent = ({ |
| | | contentRef, |
| | | rows, |
| | | reportTitle, |
| | | printMeta, |
| | | translatedColumns, |
| | | printLayoutConfig, |
| | | sequenceColumnWidth, |
| | | dataColumnWidth, |
| | | previewNotice, |
| | | }) => ( |
| | | <Box |
| | | ref={contentRef} |
| | | sx={{ |
| | | width: '277mm', |
| | | minHeight: '186mm', |
| | | mx: 'auto', |
| | | px: 1.5, |
| | | py: 2, |
| | | backgroundColor: '#fff', |
| | | color: '#111827', |
| | | boxSizing: 'border-box', |
| | | }} |
| | | > |
| | | <Typography |
| | | variant="h5" |
| | | sx={{ |
| | | mb: 1, |
| | | textAlign: 'center', |
| | | fontWeight: 700, |
| | | letterSpacing: '0.08em', |
| | | }} |
| | | > |
| | | {reportTitle} |
| | | </Typography> |
| | | <Box |
| | | sx={{ |
| | | mb: 1.5, |
| | | borderBottom: '2px solid #111827', |
| | | }} |
| | | /> |
| | | <Box |
| | | sx={{ |
| | | display: 'flex', |
| | | justifyContent: 'space-between', |
| | | gap: 2, |
| | | flexWrap: 'wrap', |
| | | mb: 2, |
| | | fontSize: 12, |
| | | color: '#374151', |
| | | }} |
| | | > |
| | | <Typography variant="body2">报表日期: {printMeta.reportDate}</Typography> |
| | | <Typography variant="body2">打印人: {printMeta.operator}</Typography> |
| | | <Typography variant="body2">打印时间: {printMeta.printedAt}</Typography> |
| | | <Typography variant="body2">记录数: {printMeta.count}</Typography> |
| | | </Box> |
| | | {previewNotice && ( |
| | | <Typography variant="body2" sx={{ mb: 1.5, color: '#6b7280' }}> |
| | | {previewNotice} |
| | | </Typography> |
| | | )} |
| | | <TableContainer |
| | | component={Paper} |
| | | sx={{ |
| | | boxShadow: 'none', |
| | | border: 'none', |
| | | backgroundColor: 'transparent', |
| | | }} |
| | | > |
| | | <Table |
| | | size="small" |
| | | sx={{ |
| | | width: '100%', |
| | | tableLayout: 'fixed', |
| | | '& .MuiTableCell-root': { |
| | | borderBottom: 'none', |
| | | fontSize: printLayoutConfig.bodyFontSize, |
| | | px: printLayoutConfig.cellPaddingX, |
| | | py: printLayoutConfig.cellPaddingY, |
| | | whiteSpace: 'normal', |
| | | wordBreak: 'break-all', |
| | | overflowWrap: 'anywhere', |
| | | lineHeight: 1.35, |
| | | verticalAlign: 'top', |
| | | boxSizing: 'border-box', |
| | | }, |
| | | '& .MuiTableHead-root .MuiTableCell-root': { |
| | | backgroundColor: '#f9fafb', |
| | | fontWeight: 700, |
| | | fontSize: printLayoutConfig.headerFontSize, |
| | | textAlign: 'center', |
| | | }, |
| | | '& .MuiTableRow-root': { |
| | | pageBreakInside: 'avoid', |
| | | breakInside: 'avoid', |
| | | }, |
| | | }} |
| | | > |
| | | <colgroup> |
| | | <col style={{ width: sequenceColumnWidth }} /> |
| | | {translatedColumns.map((column) => ( |
| | | <col key={column.source} style={{ width: dataColumnWidth }} /> |
| | | ))} |
| | | </colgroup> |
| | | <TableHead> |
| | | <TableRow> |
| | | <TableCell align="center"> |
| | | 序号 |
| | | </TableCell> |
| | | {translatedColumns.map((column) => ( |
| | | <TableCell key={column.source}> |
| | | {column.labelText} |
| | | </TableCell> |
| | | ))} |
| | | </TableRow> |
| | | </TableHead> |
| | | <TableBody> |
| | | {rows.map((record, index) => ( |
| | | <TableRow key={getRecordKey(record, index)}> |
| | | <TableCell align="center"> |
| | | {padNumber(index + 1)} |
| | | </TableCell> |
| | | {translatedColumns.map((column) => ( |
| | | <TableCell key={column.source}> |
| | | {formatValue(getValueBySource(record, column.source), column.fieldType)} |
| | | </TableCell> |
| | | ))} |
| | | </TableRow> |
| | | ))} |
| | | </TableBody> |
| | | </Table> |
| | | </TableContainer> |
| | | </Box> |
| | | ); |
| | | |
| | | const ListExportPrintButton = ({ |
| | | storeKey, |
| | | columns = [], |
| | | title, |
| | | fileName, |
| | | maxResults = 1000, |
| | | }) => { |
| | | const { |
| | | filter, |
| | | selectedIds = [], |
| | | filterValues = {}, |
| | | resource, |
| | | sort, |
| | | total = 0, |
| | | } = useListContext(); |
| | | const [hiddenColumns] = useStore( |
| | | storeKey, |
| | | columns.filter((column) => column.hidden).map((column) => column.source) |
| | | ); |
| | | const [columnRanks] = useStore(`${storeKey}_columnRanks`, []); |
| | | const dataProvider = useDataProvider(); |
| | | const notify = useNotify(); |
| | | const translate = useTranslate(); |
| | | const unselectAll = useUnselectAll(resource); |
| | | const previewContentRef = useRef(null); |
| | | const fullPrintContentRef = useRef(null); |
| | | const [printOpen, setPrintOpen] = useState(false); |
| | | const [printLoading, setPrintLoading] = useState(false); |
| | | const [printRows, setPrintRows] = useState([]); |
| | | const [renderFullPrintContent, setRenderFullPrintContent] = useState(false); |
| | | |
| | | const defaultHiddenColumns = useMemo( |
| | | () => columns.filter((column) => column.hidden).map((column) => column.source), |
| | | [columns] |
| | | ); |
| | | |
| | | const visibleColumns = useMemo( |
| | | () => resolveVisibleColumns(storeKey, defaultHiddenColumns, columns, hiddenColumns, columnRanks), |
| | | [storeKey, defaultHiddenColumns, columns, hiddenColumns, columnRanks] |
| | | ); |
| | | |
| | | const mergedFilter = useMemo( |
| | | () => (filter ? { ...filterValues, ...filter } : filterValues), |
| | | [filter, filterValues] |
| | | ); |
| | | |
| | | const translatedTitle = useMemo( |
| | | () => formatColumnLabel(title || resource, translate), |
| | | [title, resource, translate] |
| | | ); |
| | | |
| | | const reportTitle = useMemo(() => `${translatedTitle}报表`, [translatedTitle]); |
| | | const [printMeta, setPrintMeta] = useState(() => buildReportMeta(reportTitle, 0)); |
| | | |
| | | const translatedColumns = useMemo( |
| | | () => visibleColumns.map((column) => ({ |
| | | ...column, |
| | | labelText: formatColumnLabel(column.label, translate), |
| | | })), |
| | | [visibleColumns, translate] |
| | | ); |
| | | const previewRows = useMemo( |
| | | () => printRows.slice(0, PREVIEW_ROW_LIMIT), |
| | | [printRows] |
| | | ); |
| | | const previewNotice = printRows.length > PREVIEW_ROW_LIMIT |
| | | ? `当前仅预览前 ${PREVIEW_ROW_LIMIT} 条,打印将包含全部 ${printRows.length} 条记录` |
| | | : ''; |
| | | const printLayoutConfig = useMemo( |
| | | () => getPrintLayoutConfig(translatedColumns.length), |
| | | [translatedColumns.length] |
| | | ); |
| | | const sequenceColumnWidth = `${printLayoutConfig.sequenceWidth}px`; |
| | | const dataColumnWidth = translatedColumns.length > 0 |
| | | ? `calc((100% - ${sequenceColumnWidth}) / ${translatedColumns.length})` |
| | | : 'auto'; |
| | | |
| | | const isDisabled = total === 0 || translatedColumns.length === 0; |
| | | |
| | | const getPerPage = () => { |
| | | if (selectedIds.length > 0) { |
| | | return Math.min(selectedIds.length, maxResults); |
| | | } |
| | | |
| | | if (total > 0) { |
| | | return Math.min(total, maxResults); |
| | | } |
| | | |
| | | return maxResults; |
| | | }; |
| | | |
| | | const downloadBlob = (response) => { |
| | | const url = window.URL.createObjectURL( |
| | | new Blob([response.data], { type: response.headers["content-type"] }), |
| | | ); |
| | | const link = document.createElement("a"); |
| | | link.href = url; |
| | | link.setAttribute("download", `${fileName || resource}.xlsx`); |
| | | document.body.appendChild(link); |
| | | link.click(); |
| | | link.remove(); |
| | | window.URL.revokeObjectURL(url); |
| | | }; |
| | | |
| | | const handleExport = (event) => { |
| | | if (translatedColumns.length === 0) { |
| | | notify('暂无可导出的列', { type: 'warning' }); |
| | | return; |
| | | } |
| | | |
| | | dataProvider |
| | | .export(resource, { |
| | | sort, |
| | | ids: selectedIds, |
| | | filter: mergedFilter, |
| | | pagination: { page: 1, perPage: getPerPage() }, |
| | | meta: { |
| | | ...buildReportMeta(reportTitle, selectedIds.length > 0 ? selectedIds.length : total), |
| | | columns: translatedColumns.map((column) => ({ |
| | | source: column.source, |
| | | label: column.labelText, |
| | | })), |
| | | }, |
| | | }) |
| | | .then((response) => { |
| | | downloadBlob(response); |
| | | unselectAll(); |
| | | }) |
| | | .catch((error) => { |
| | | console.error(error); |
| | | notify("ra.notification.http_error", { type: "error" }); |
| | | }); |
| | | |
| | | if (typeof event?.stopPropagation === 'function') { |
| | | event.stopPropagation(); |
| | | } |
| | | }; |
| | | |
| | | const loadPrintRows = async () => { |
| | | if (translatedColumns.length === 0) { |
| | | notify('暂无可打印的列', { type: 'warning' }); |
| | | return; |
| | | } |
| | | |
| | | setPrintOpen(true); |
| | | setPrintLoading(true); |
| | | try { |
| | | let rows = []; |
| | | if (selectedIds.length > 0) { |
| | | const response = await dataProvider.getMany(resource, { ids: selectedIds }); |
| | | rows = response.data || []; |
| | | } else { |
| | | const response = await dataProvider.getList(resource, { |
| | | sort, |
| | | filter: mergedFilter, |
| | | pagination: { page: 1, perPage: getPerPage() }, |
| | | }); |
| | | rows = response.data || []; |
| | | } |
| | | setPrintRows(rows); |
| | | setPrintMeta(buildReportMeta(reportTitle, rows.length)); |
| | | } catch (error) { |
| | | console.error(error); |
| | | notify("ra.notification.http_error", { type: "error" }); |
| | | setPrintOpen(false); |
| | | } finally { |
| | | setPrintLoading(false); |
| | | } |
| | | }; |
| | | |
| | | const handlePrintDialogClose = () => { |
| | | setPrintOpen(false); |
| | | setPrintRows([]); |
| | | }; |
| | | |
| | | const triggerPrint = useReactToPrint({ |
| | | content: () => fullPrintContentRef.current, |
| | | documentTitle: translatedTitle, |
| | | onAfterPrint: () => { |
| | | setRenderFullPrintContent(false); |
| | | }, |
| | | pageStyle: ` |
| | | @page { |
| | | size: A4 landscape; |
| | | margin: 12mm 10mm; |
| | | } |
| | | html, body { |
| | | width: 297mm; |
| | | min-height: 210mm; |
| | | } |
| | | body { |
| | | -webkit-print-color-adjust: exact; |
| | | print-color-adjust: exact; |
| | | margin: 0; |
| | | } |
| | | `, |
| | | }); |
| | | |
| | | const handlePrint = async () => { |
| | | if (printLoading || printRows.length === 0) { |
| | | return; |
| | | } |
| | | |
| | | setRenderFullPrintContent(true); |
| | | await new Promise((resolve) => setTimeout(resolve, 0)); |
| | | if (typeof triggerPrint === 'function') { |
| | | triggerPrint(); |
| | | } else { |
| | | setRenderFullPrintContent(false); |
| | | } |
| | | }; |
| | | |
| | | return ( |
| | | <> |
| | | <Button |
| | | onClick={handleExport} |
| | | label="ra.action.export" |
| | | disabled={isDisabled} |
| | | > |
| | | <DownloadIcon /> |
| | | </Button> |
| | | <Button |
| | | onClick={loadPrintRows} |
| | | label="toolbar.print" |
| | | disabled={isDisabled} |
| | | > |
| | | <PrintOutlinedIcon /> |
| | | </Button> |
| | | <Dialog open={printOpen} maxWidth="xl" fullWidth onClose={handlePrintDialogClose}> |
| | | <DialogCloseButton onClose={handlePrintDialogClose} /> |
| | | <DialogTitle>{translatedTitle}</DialogTitle> |
| | | <DialogContent dividers> |
| | | {printLoading ? ( |
| | | <Box sx={{ py: 8, display: 'flex', justifyContent: 'center' }}> |
| | | <CircularProgress size={28} /> |
| | | </Box> |
| | | ) : printRows.length === 0 ? ( |
| | | <Box sx={{ py: 8, textAlign: 'center' }}> |
| | | <Typography color="text.secondary">暂无可打印数据</Typography> |
| | | </Box> |
| | | ) : ( |
| | | <PrintReportContent |
| | | contentRef={previewContentRef} |
| | | rows={previewRows} |
| | | reportTitle={reportTitle} |
| | | printMeta={printMeta} |
| | | translatedColumns={translatedColumns} |
| | | printLayoutConfig={printLayoutConfig} |
| | | sequenceColumnWidth={sequenceColumnWidth} |
| | | dataColumnWidth={dataColumnWidth} |
| | | previewNotice={previewNotice} |
| | | /> |
| | | )} |
| | | </DialogContent> |
| | | <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper' }}> |
| | | <MuiButton |
| | | onClick={handlePrint} |
| | | disabled={printLoading || printRows.length === 0} |
| | | variant="contained" |
| | | startIcon={<SaveIcon />} |
| | | > |
| | | {translate('toolbar.confirm')} |
| | | </MuiButton> |
| | | </DialogActions> |
| | | </Dialog> |
| | | {renderFullPrintContent && ( |
| | | <Box sx={{ position: 'fixed', left: '-10000px', top: 0, zIndex: -1 }}> |
| | | <PrintReportContent |
| | | contentRef={fullPrintContentRef} |
| | | rows={printRows} |
| | | reportTitle={reportTitle} |
| | | printMeta={printMeta} |
| | | translatedColumns={translatedColumns} |
| | | printLayoutConfig={printLayoutConfig} |
| | | sequenceColumnWidth={sequenceColumnWidth} |
| | | dataColumnWidth={dataColumnWidth} |
| | | /> |
| | | </Box> |
| | | )} |
| | | </> |
| | | ); |
| | | }; |
| | | |
| | | export default ListExportPrintButton; |
| New file |
| | |
| | | const EXTEND_FIELD_SOURCE_REGEXP = /^extendFields\.\[(.+)\]$/; |
| | | |
| | | const getExtendFieldKey = (source) => { |
| | | const match = EXTEND_FIELD_SOURCE_REGEXP.exec(source || ''); |
| | | return match ? match[1] : null; |
| | | }; |
| | | |
| | | const reorderColumns = (columns = [], columnRanks = []) => { |
| | | if (!Array.isArray(columnRanks) || columnRanks.length === 0) { |
| | | return columns; |
| | | } |
| | | |
| | | return columns.reduce((accumulator, column, index) => { |
| | | const rank = columnRanks.indexOf(index); |
| | | if (rank === -1) { |
| | | accumulator[index] = column; |
| | | } else { |
| | | accumulator[rank] = column; |
| | | } |
| | | return accumulator; |
| | | }, []).filter(Boolean); |
| | | }; |
| | | |
| | | export const resolveVisibleColumns = ( |
| | | storeKey, |
| | | defaultHiddenColumns = [], |
| | | columns = [], |
| | | hiddenColumns = defaultHiddenColumns, |
| | | columnRanks = [] |
| | | ) => { |
| | | if (!storeKey || !Array.isArray(columns)) { |
| | | return []; |
| | | } |
| | | |
| | | const visibleColumns = reorderColumns(columns, columnRanks); |
| | | const effectiveHiddenColumns = Array.isArray(hiddenColumns) ? hiddenColumns : defaultHiddenColumns; |
| | | |
| | | return visibleColumns.filter((column) => { |
| | | if (!column?.source) { |
| | | return false; |
| | | } |
| | | return !effectiveHiddenColumns.includes(column.source); |
| | | }); |
| | | }; |
| | | |
| | | export const getValueBySource = (record, source) => { |
| | | if (!record || !source) { |
| | | return ''; |
| | | } |
| | | |
| | | const extendFieldKey = getExtendFieldKey(source); |
| | | if (extendFieldKey) { |
| | | return record.extendFields?.[extendFieldKey] ?? ''; |
| | | } |
| | | |
| | | return source.split('.').reduce((value, key) => { |
| | | if (value == null) { |
| | | return undefined; |
| | | } |
| | | return value[key]; |
| | | }, record) ?? ''; |
| | | }; |
| | |
| | | import React, { useState, useRef, useEffect, useMemo, useCallback } from "react"; |
| | | import { useNavigate } from 'react-router-dom'; |
| | | import React, { useState } from "react"; |
| | | import { |
| | | List, |
| | | DatagridConfigurable, |
| | | SearchInput, |
| | | TopToolbar, |
| | | ColumnsButton, |
| | | 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, |
| | | useRefresh, |
| | | Button |
| | | } from 'react-admin'; |
| | | import { Box, Typography, Card, Stack } from '@mui/material'; |
| | | import { styled } from '@mui/material/styles'; |
| | | import { Box } from '@mui/material'; |
| | | import WarehouseAreasCreate from "./WarehouseAreasCreate"; |
| | | import WarehouseAreasPanel from "./WarehouseAreasPanel"; |
| | | import EmptyData from "../components/EmptyData"; |
| | | import MyCreateButton from "../components/MyCreateButton"; |
| | | import MyExportButton from '../components/MyExportButton'; |
| | | import PageDrawer from "../components/PageDrawer"; |
| | | import BatchModal from "./BatchModal"; |
| | | import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting'; |
| | | import * as Common from '@/utils/common'; |
| | | import EditIcon from '@mui/icons-material/Edit'; |
| | | import StickyDataTable from "@/page/components/StickyDataTable"; |
| | | |
| | | const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({ |
| | | '& .css-1vooibu-MuiSvgIcon-root': { |
| | | height: '.9em' |
| | | }, |
| | | '& .RaDatagrid-row': { |
| | | cursor: 'auto' |
| | | }, |
| | | '& .column-name': { |
| | | }, |
| | | '& .opt': { |
| | | width: 200 |
| | | }, |
| | | '& .MuiTableCell-root': { |
| | | whiteSpace: 'nowrap', |
| | | overflow: 'visible', |
| | | textOverflow: 'unset' |
| | | } |
| | | })); |
| | | import ListExportPrintButton from "../components/ListExportPrintButton"; |
| | | |
| | | const filters = [ |
| | | <SearchInput source="condition" placeholder="搜索库区名称" alwaysOn />, |
| | | <SearchInput key="condition" source="condition" placeholder="搜索库区名称" alwaysOn />, |
| | | <ReferenceInput |
| | | key="warehouseId" |
| | | source="warehouseId" |
| | | label="table.field.loc.warehouseId" |
| | | reference="warehouse" |
| | |
| | | filterToQuery={(val) => ({ name: val })} |
| | | /> |
| | | </ReferenceInput>, |
| | | // <TextInput source="uuid" label="table.field.warehouseAreas.uuid" />, |
| | | <TextInput source="code" label="table.field.warehouseAreas.code" />, |
| | | <TextInput source="name" label="table.field.warehouseAreas.name" />, |
| | | <ReferenceInput source="shipperId" label="table.field.warehouseAreas.shipperId" reference="shipper"> |
| | | <AutocompleteInput label="table.field.warehouseAreas.shipperId" optionText="name" filterToQuery={(val) => ({ name: val })} /> |
| | | <TextInput key="code" source="code" label="table.field.warehouseAreas.code" />, |
| | | <TextInput key="name" source="name" label="table.field.warehouseAreas.name" />, |
| | | <ReferenceInput |
| | | key="shipperId" |
| | | source="shipperId" |
| | | label="table.field.warehouseAreas.shipperId" |
| | | reference="shipper" |
| | | > |
| | | <AutocompleteInput |
| | | label="table.field.warehouseAreas.shipperId" |
| | | optionText="name" |
| | | filterToQuery={(val) => ({ name: val })} |
| | | /> |
| | | </ReferenceInput>, |
| | | <NumberInput source="supplierId" label="table.field.warehouseAreas.supplierId" />, |
| | | // <SelectInput source="flagMinus" label="table.field.warehouseAreas.flagMinus" |
| | | // choices={[ |
| | | // { id: 0, name: '否' }, |
| | | // { id: 1, name: '是' }, |
| | | // ]} |
| | | // />, |
| | | // <SelectInput source="flagLabelMange" label="table.field.warehouseAreas.flagLabelMange" |
| | | // choices={[ |
| | | // { id: 0, name: ' 否' }, |
| | | // { id: 1, name: ' 是' }, |
| | | // ]} |
| | | // />, |
| | | // <SelectInput source="flagMix" label="table.field.warehouseAreas.flagMix" |
| | | // choices={[ |
| | | // { id: 0, name: '否' }, |
| | | // { id: 1, name: '是' }, |
| | | // ]} |
| | | // />, |
| | | // <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 |
| | | // />, |
| | | ] |
| | | <NumberInput key="supplierId" source="supplierId" label="table.field.warehouseAreas.supplierId" />, |
| | | ]; |
| | | |
| | | const HIDDEN_COLUMN_SOURCES = [ |
| | | 'id', |
| | | 'updateTime', |
| | | 'updateBy', |
| | | 'createTime', |
| | | 'createBy', |
| | | 'longitude', |
| | | 'latgitude', |
| | | 'length', |
| | | 'width', |
| | | 'height', |
| | | 'shipperId$', |
| | | 'supplierId', |
| | | 'sort', |
| | | ]; |
| | | |
| | | const createColumnDef = (source, label, fieldType = 'text', extra = {}) => ({ |
| | | source, |
| | | label, |
| | | fieldType, |
| | | hidden: HIDDEN_COLUMN_SOURCES.includes(source), |
| | | ...extra, |
| | | }); |
| | | |
| | | const COLUMN_DEFS = [ |
| | | createColumnDef('id', 'id', 'number'), |
| | | createColumnDef('sort', 'table.field.warehouseAreas.sort', 'number'), |
| | | createColumnDef('warehouseId$', 'table.field.warehouseAreas.wareId'), |
| | | createColumnDef('code', 'table.field.warehouseAreas.code'), |
| | | createColumnDef('name', 'table.field.warehouseAreas.name'), |
| | | createColumnDef('type$', 'table.field.warehouseAreas.type'), |
| | | createColumnDef('shipperId$', 'table.field.warehouseAreas.shipperId'), |
| | | createColumnDef('supplierId', 'table.field.warehouseAreas.supplierId', 'number'), |
| | | createColumnDef('flagMix$', 'table.field.warehouseAreas.flagMix'), |
| | | createColumnDef('flagMinus$', 'table.field.warehouseAreas.flagMinus'), |
| | | createColumnDef('updateBy', 'common.field.updateBy', 'text', { |
| | | component: 'reference', |
| | | reference: 'user', |
| | | childSource: 'nickname', |
| | | sortable: false, |
| | | }), |
| | | createColumnDef('updateTime', 'common.field.updateTime', 'date', { |
| | | component: 'date', |
| | | showTime: true, |
| | | }), |
| | | createColumnDef('createBy', 'common.field.createBy', 'text', { |
| | | component: 'reference', |
| | | reference: 'user', |
| | | childSource: 'nickname', |
| | | sortable: false, |
| | | }), |
| | | createColumnDef('createTime', 'common.field.createTime', 'date', { |
| | | component: 'date', |
| | | showTime: true, |
| | | }), |
| | | createColumnDef('memo', 'common.field.memo', 'text', { |
| | | sortable: false, |
| | | }), |
| | | ]; |
| | | |
| | | const renderColumnField = (column) => { |
| | | if (column.component === 'reference') { |
| | | return ( |
| | | <ReferenceField |
| | | key={column.source} |
| | | source={column.source} |
| | | label={column.label} |
| | | reference={column.reference} |
| | | link={false} |
| | | sortable={column.sortable} |
| | | > |
| | | <TextField source={column.childSource} /> |
| | | </ReferenceField> |
| | | ); |
| | | } |
| | | |
| | | if (column.component === 'date' || column.fieldType === 'date') { |
| | | return ( |
| | | <DateField |
| | | key={column.source} |
| | | source={column.source} |
| | | label={column.label} |
| | | showTime={column.showTime} |
| | | /> |
| | | ); |
| | | } |
| | | |
| | | if (column.fieldType === 'number') { |
| | | return ( |
| | | <NumberField |
| | | key={column.source} |
| | | source={column.source} |
| | | label={column.label} |
| | | /> |
| | | ); |
| | | } |
| | | |
| | | return ( |
| | | <TextField |
| | | key={column.source} |
| | | source={column.source} |
| | | label={column.label} |
| | | sortable={column.sortable} |
| | | /> |
| | | ); |
| | | }; |
| | | |
| | | const exportPrintButton = ( |
| | | <ListExportPrintButton |
| | | storeKey="warehouseAreas" |
| | | columns={COLUMN_DEFS} |
| | | title="menu.warehouseAreas" |
| | | fileName="warehouseAreas" |
| | | /> |
| | | ); |
| | | |
| | | const WarehouseAreasList = () => { |
| | | const translate = useTranslate(); |
| | | const [createDialog, setCreateDialog] = useState(false); |
| | | const [drawerVal, setDrawerVal] = useState(false); |
| | | |
| | |
| | | }), |
| | | marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0, |
| | | }} |
| | | title={"menu.warehouseAreas"} |
| | | empty={<EmptyData onClick={() => { setCreateDialog(true) }} />} |
| | | title="menu.warehouseAreas" |
| | | empty={<EmptyData onClick={() => { setCreateDialog(true); }} />} |
| | | filters={filters} |
| | | sort={{ field: "warehouseId", order: "desc" }} |
| | | actions={( |
| | | <TopToolbar> |
| | | <FilterButton /> |
| | | <MyCreateButton onClick={() => { setCreateDialog(true) }} /> |
| | | <ColumnsButton storeKey='warehouseAreas' /> |
| | | <MyExportButton /> |
| | | <MyCreateButton onClick={() => { setCreateDialog(true); }} /> |
| | | <ColumnsButton storeKey="warehouseAreas" /> |
| | | {exportPrintButton} |
| | | </TopToolbar> |
| | | )} |
| | | perPage={DEFAULT_PAGE_SIZE} |
| | | > |
| | | <StickyDataTable |
| | | storeKey='warehouseAreas' |
| | | bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />} |
| | | rowClick={(id, resource, record) => false} |
| | | storeKey="warehouseAreas" |
| | | bulkActionButtons={ |
| | | <> |
| | | {exportPrintButton} |
| | | <BulkDeleteButton mutationMode={OPERATE_MODE} /> |
| | | </> |
| | | } |
| | | rowClick={() => false} |
| | | stickyRight={['opt']} |
| | | hiddenColumns={['id', 'updateTime', 'updateBy', 'createTime', 'createBy', 'longitude', 'latgitude', 'length', 'width', 'height', 'shipperId$', 'supplierId', 'sort']} |
| | | hiddenColumns={HIDDEN_COLUMN_SOURCES} |
| | | > |
| | | <NumberField source="id" /> |
| | | <NumberField source="sort" label="table.field.warehouseAreas.sort" /> |
| | | <TextField source="warehouseId$" label="table.field.warehouseAreas.wareId" /> |
| | | <TextField source="code" label="table.field.warehouseAreas.code" /> |
| | | <TextField source="name" label="table.field.warehouseAreas.name" /> |
| | | <TextField source="type$" label="table.field.warehouseAreas.type"/> |
| | | <TextField source="shipperId$" label="table.field.warehouseAreas.shipperId" /> |
| | | <NumberField source="supplierId" label="table.field.warehouseAreas.supplierId" /> |
| | | <TextField source="flagMix$" label="table.field.warehouseAreas.flagMix" sortable={false} /> |
| | | <TextField source="flagMinus$" label="table.field.warehouseAreas.flagMinus" sortable={false} /> |
| | | <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} /> |
| | | {COLUMN_DEFS.map((column) => renderColumnField(column))} |
| | | <WrapperField cellClassName="opt" label="common.field.opt"> |
| | | <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} /> |
| | | <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} /> |
| | | </WrapperField> |
| | | |
| | | {/* <TextField source="flagLabelMange$" label="table.field.warehouseAreas.flagLabelMange" sortable={false} /> */} |
| | | {/* <TextField source="uuid" label="table.field.warehouseAreas.uuid" /> */} |
| | | {/* <ReferenceField source="shipperId" label="table.field.warehouseAreas.shipperId" reference="shipper" link={false} sortable={false}> |
| | | <TextField source="name" /> |
| | | </ReferenceField> */} |
| | | </StickyDataTable> |
| | | |
| | | </List> |
| | | <WarehouseAreasCreate |
| | | open={createDialog} |
| | | setOpen={setCreateDialog} |
| | | /> |
| | | <PageDrawer |
| | | title='WarehouseAreas Detail' |
| | | title="WarehouseAreas Detail" |
| | | drawerVal={drawerVal} |
| | | setDrawerVal={setDrawerVal} |
| | | > |
| | | </PageDrawer> |
| | | /> |
| | | </Box> |
| | | ) |
| | | } |
| | | ); |
| | | }; |
| | | |
| | | export default WarehouseAreasList; |
| | | |
| | | |
| | | const MixButton = () => { |
| | | const record = useRecordContext(); |
| | | const notify = useNotify(); |
| | | const refresh = useRefresh(); |
| | | |
| | | |
| | | const [createDialog, setCreateDialog] = useState(false); |
| | | |
| | | return ( |
| | | <> |
| | | <Button onClick={() => setCreateDialog(true)} label={"toolbar.batchMix"}> |
| | | <Button onClick={() => setCreateDialog(true)} label="toolbar.batchMix"> |
| | | <EditIcon /> |
| | | </Button> |
| | | |
| | | <BatchModal |
| | | open={createDialog} |
| | | setOpen={setCreateDialog} |
| | | fieldType={'flagMix'} |
| | | fieldType="flagMix" |
| | | /> |
| | | </> |
| | | |
| | | ) |
| | | } |
| | | ); |
| | | }; |
| | | |
| | | const WareButton = () => { |
| | | const record = useRecordContext(); |
| | | const notify = useNotify(); |
| | | const refresh = useRefresh(); |
| | | |
| | | |
| | | const [createDialog, setCreateDialog] = useState(false); |
| | | |
| | | return ( |
| | | <> |
| | | <Button onClick={() => setCreateDialog(true)} label={"toolbar.batchWarehouse"}> |
| | | <Button onClick={() => setCreateDialog(true)} label="toolbar.batchWarehouse"> |
| | | <EditIcon /> |
| | | </Button> |
| | | |
| | | <BatchModal |
| | | open={createDialog} |
| | | setOpen={setCreateDialog} |
| | | fieldType={'wareId'} |
| | | fieldType="wareId" |
| | | /> |
| | | </> |
| | | |
| | | ) |
| | | } |
| | | ); |
| | | }; |
| | | |
| | | const StatusButton = () => { |
| | | const record = useRecordContext(); |
| | | const notify = useNotify(); |
| | | const refresh = useRefresh(); |
| | | |
| | | |
| | | const [createDialog, setCreateDialog] = useState(false); |
| | | |
| | | return ( |
| | | <> |
| | | <Button onClick={() => setCreateDialog(true)} label={"toolbar.batchStatus"}> |
| | | <Button onClick={() => setCreateDialog(true)} label="toolbar.batchStatus"> |
| | | <EditIcon /> |
| | | </Button> |
| | | |
| | | <BatchModal |
| | | open={createDialog} |
| | | setOpen={setCreateDialog} |
| | | fieldType={'status'} |
| | | fieldType="status" |
| | | /> |
| | | </> |
| | | |
| | | ) |
| | | } |
| | | ); |
| | | }; |
| | |
| | | import React, { useState, useEffect } from "react"; |
| | | import React, { useEffect, useState } from "react"; |
| | | import { |
| | | List, |
| | | SearchInput, |
| | |
| | | import { Box, LinearProgress } from '@mui/material'; |
| | | import WarehouseAreasItemCreate from "./WarehouseAreasItemCreate"; |
| | | import request from '@/utils/request'; |
| | | import MyExportButton from '../components/MyExportButton'; |
| | | import { DEFAULT_PAGE_SIZE, PAGE_DRAWER_WIDTH } from '@/config/setting'; |
| | | import StickyDataTable from "../components/StickyDataTable"; |
| | | import WarehouseIsptResult from "./WarehouseIsptResult"; |
| | | import useTableLayout from '@/utils/useTableLayout'; |
| | | import ListExportPrintButton from "../components/ListExportPrintButton"; |
| | | |
| | | const baseFilters = [ |
| | | <SearchInput key="condition" source="condition" alwaysOn />, |
| | |
| | | <NumberInput key="weight" source="weight" label="table.field.warehouseAreasItem.weight" />, |
| | | <TextInput key="prodTime" source="prodTime" label="table.field.warehouseAreasItem.prodTime" />, |
| | | <TextInput key="splrBtch" source="splrBtch" label="table.field.warehouseAreasItem.splrBtch" />, |
| | | |
| | | <TextInput key="memo" label="common.field.memo" source="memo" />, |
| | | <SelectInput |
| | | key="status" |
| | |
| | | |
| | | const baseFilterSources = new Set(baseFilters.map((item) => item.props.source).filter(Boolean)); |
| | | |
| | | const hiddenColumns = [ |
| | | const hiddenColumnSources = [ |
| | | 'prodTime', 'platOrderCode', 'id', 'createTime', 'memo', 'areaId', 'brand', |
| | | 'weight', 'splrId', 'projectCode', 'statusBool', 'extendFields.[priceUnitId]', 'isptResult$', |
| | | 'extendFields.[inStockType]', 'matnrId', 'trackCode', 'workQty', 'batch', 'shipperId', |
| | | 'isptResult', 'createBy$', 'extendFields.[baseUnitId]' |
| | | ]; |
| | | |
| | | const baseColumns = [ |
| | | <NumberField key="id" source="id" />, |
| | | <TextField key="areaName" source="areaName" label="收货区名称" />, |
| | | <TextField key="asnCode" source="asnCode" label="table.field.warehouseAreasItem.asnCode" />, |
| | | <TextField key="platWorkCode" source="platWorkCode" label="table.field.asnOrderItem.platWorkCode" />, |
| | | <TextField key="platItemId" source="platItemId" label="table.field.deliveryItem.platItemId" />, |
| | | <NumberField key="matnrId" source="matnrId" label="table.field.warehouseAreasItem.matnrId" />, |
| | | <TextField key="matnrCode" source="matnrCode" label="table.field.warehouseAreasItem.matnrCode" />, |
| | | <TextField key="maktx" source="maktx" label="table.field.warehouseAreasItem.matnrName" />, |
| | | <TextField key="splrBatch" source="splrBatch" label="table.field.warehouseAreasItem.splrBtch" />, |
| | | <TextField key="batch" source="batch" label="table.field.warehouseAreasItem.batch" />, |
| | | <TextField key="trackCode" source="trackCode" label="table.field.warehouseAreasItem.barcode" />, |
| | | <TextField key="unit" source="unit" label="table.field.warehouseAreasItem.unit" />, |
| | | <NumberField key="anfme" source="anfme" label="table.field.warehouseAreasItem.anfme" />, |
| | | <NumberField key="workQty" source="workQty" label="table.field.warehouseAreasItem.workQty" />, |
| | | <NumberField key="ableQty" source="ableQty" label="table.field.warehouseAreasItem.qty" />, |
| | | <TextField key="platOrderCode" source="platOrderCode" label="table.field.asnOrderItem.platOrderCode" />, |
| | | <TextField key="projectCode" source="projectCode" label="table.field.asnOrderItem.projectCode" />, |
| | | <TextField key="brand" source="brand" label="table.field.warehouseAreasItem.brand" />, |
| | | <TextField key="shipperId" source="shipperId" label="table.field.warehouseAreasItem.shipperId" />, |
| | | <TextField key="splrId" source="splrId" label="table.field.warehouseAreasItem.splrId" />, |
| | | <TextField key="isptResult" source="isptResult$" label="table.field.warehouseAreasItem.isptResult" sortable={false} />, |
| | | <NumberField key="weight" source="weight" label="table.field.warehouseAreasItem.weight" />, |
| | | <TextField key="prodTime" source="prodTime" label="table.field.warehouseAreasItem.prodTime" />, |
| | | const createColumnDef = (source, label, fieldType = 'text', options = {}) => ({ |
| | | source, |
| | | label, |
| | | fieldType, |
| | | hidden: hiddenColumnSources.includes(source), |
| | | sortable: options.sortable, |
| | | }); |
| | | |
| | | const baseColumnDefs = [ |
| | | createColumnDef('id', 'table.field.warehouseAreasItem.id', 'number'), |
| | | createColumnDef('areaName', 'table.field.warehouseAreasItem.areaName'), |
| | | createColumnDef('asnCode', 'table.field.warehouseAreasItem.asnCode'), |
| | | createColumnDef('platWorkCode', 'table.field.asnOrderItem.platWorkCode'), |
| | | createColumnDef('platItemId', 'table.field.deliveryItem.platItemId'), |
| | | createColumnDef('matnrId', 'table.field.warehouseAreasItem.matnrId', 'number'), |
| | | createColumnDef('matnrCode', 'table.field.warehouseAreasItem.matnrCode'), |
| | | createColumnDef('maktx', 'table.field.warehouseAreasItem.matnrName'), |
| | | createColumnDef('splrBatch', 'table.field.warehouseAreasItem.splrBtch'), |
| | | createColumnDef('batch', 'table.field.warehouseAreasItem.batch'), |
| | | createColumnDef('trackCode', 'table.field.warehouseAreasItem.barcode'), |
| | | createColumnDef('unit', 'table.field.warehouseAreasItem.unit'), |
| | | createColumnDef('anfme', 'table.field.warehouseAreasItem.anfme', 'number'), |
| | | createColumnDef('workQty', 'table.field.warehouseAreasItem.workQty', 'number'), |
| | | createColumnDef('ableQty', 'table.field.warehouseAreasItem.qty', 'number'), |
| | | createColumnDef('platOrderCode', 'table.field.asnOrderItem.platOrderCode'), |
| | | createColumnDef('projectCode', 'table.field.asnOrderItem.projectCode'), |
| | | createColumnDef('brand', 'table.field.warehouseAreasItem.brand'), |
| | | createColumnDef('shipperId', 'table.field.warehouseAreasItem.shipperId'), |
| | | createColumnDef('splrId', 'table.field.warehouseAreasItem.splrId'), |
| | | createColumnDef('isptResult$', 'table.field.warehouseAreasItem.isptResult', 'text', { sortable: false }), |
| | | createColumnDef('weight', 'table.field.warehouseAreasItem.weight', 'number'), |
| | | createColumnDef('prodTime', 'table.field.warehouseAreasItem.prodTime'), |
| | | ]; |
| | | |
| | | const trailingColumns = [ |
| | | <TextField key="updateBy" source="updateBy$" label="common.field.updateBy" />, |
| | | <DateField key="updateTime" source="updateTime" label="common.field.updateTime" showTime />, |
| | | <TextField key="createBy" source="createBy$" label="common.field.createBy" />, |
| | | <DateField key="createTime" source="createTime" label="common.field.createTime" showTime />, |
| | | <BooleanField key="statusBool" source="statusBool" label="common.field.status" sortable={false} />, |
| | | <TextField key="memo" source="memo" label="common.field.memo" sortable={false} />, |
| | | const trailingColumnDefs = [ |
| | | createColumnDef('updateBy$', 'common.field.updateBy'), |
| | | createColumnDef('updateTime', 'common.field.updateTime', 'date'), |
| | | createColumnDef('createBy$', 'common.field.createBy'), |
| | | createColumnDef('createTime', 'common.field.createTime', 'date'), |
| | | createColumnDef('statusBool', 'common.field.status', 'boolean', { sortable: false }), |
| | | createColumnDef('memo', 'common.field.memo', 'text', { sortable: false }), |
| | | ]; |
| | | |
| | | const buildDynamicFilter = (field) => ( |
| | | <TextInput key={field.fields} source={field.fields} label={field.fieldsAlise} /> |
| | | ); |
| | | |
| | | const buildDynamicColumn = (field) => ( |
| | | <TextField key={field.fields} source={`extendFields.[${field.fields}]`} label={field.fieldsAlise} /> |
| | | const buildDynamicColumnDef = (field) => createColumnDef( |
| | | `extendFields.[${field.fields}]`, |
| | | field.fieldsAlise |
| | | ); |
| | | |
| | | const buildFieldElement = (column) => { |
| | | const commonProps = { |
| | | key: column.source, |
| | | source: column.source, |
| | | label: column.label, |
| | | }; |
| | | |
| | | if (column.sortable === false) { |
| | | commonProps.sortable = false; |
| | | } |
| | | |
| | | switch (column.fieldType) { |
| | | case 'number': |
| | | return <NumberField {...commonProps} />; |
| | | case 'date': |
| | | return <DateField {...commonProps} showTime />; |
| | | case 'boolean': |
| | | return <BooleanField {...commonProps} />; |
| | | default: |
| | | return <TextField {...commonProps} />; |
| | | } |
| | | }; |
| | | |
| | | const WarehouseAreasItemList = () => { |
| | | const [itemInfo, setItemInfo] = useState({}) |
| | | const notify = useNotify(); |
| | | const [itemInfo, setItemInfo] = useState({}); |
| | | const [createDialog, setCreateDialog] = useState(false); |
| | | const [drawerVal, setDrawerVal] = useState(false); |
| | | const [dynamicFilters, setDynamicFilters] = useState([]); |
| | | const [columnDefs, setColumnDefs] = useState([]); |
| | | |
| | | useEffect(() => { |
| | | let active = true; |
| | | |
| | | const getDynamicFields = async () => { |
| | | try { |
| | | const { data: { code, data, msg } } = await request.get("/fields/enable/list"); |
| | | if (!active) { |
| | | return; |
| | | } |
| | | if (code === 200) { |
| | | const dynamicColumnDefs = data.map(buildDynamicColumnDef); |
| | | const nextDynamicFilters = data |
| | | .filter((field) => !baseFilterSources.has(field.fields)) |
| | | .map(buildDynamicFilter); |
| | | |
| | | setColumnDefs([...baseColumnDefs, ...dynamicColumnDefs, ...trailingColumnDefs]); |
| | | setDynamicFilters(nextDynamicFilters); |
| | | } else { |
| | | setColumnDefs([...baseColumnDefs, ...trailingColumnDefs]); |
| | | notify(msg); |
| | | } |
| | | } catch (error) { |
| | | if (active) { |
| | | setColumnDefs([...baseColumnDefs, ...trailingColumnDefs]); |
| | | notify('请求出错'); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | getDynamicFields(); |
| | | |
| | | return () => { |
| | | active = false; |
| | | setDynamicFilters([]); |
| | | }; |
| | | }, [notify]); |
| | | |
| | | return ( |
| | | <Box display="flex"> |
| | |
| | | actions={( |
| | | <TopToolbar> |
| | | <FilterButton /> |
| | | <ColumnsButton storeKey='warehouseAreasItem' /> |
| | | <MyExportButton /> |
| | | {columnDefs.length > 0 && ( |
| | | <ColumnsButton storeKey='warehouseAreasItem' /> |
| | | )} |
| | | {columnDefs.length > 0 && ( |
| | | <ListExportPrintButton |
| | | storeKey='warehouseAreasItem' |
| | | columns={columnDefs} |
| | | title='menu.warehouseAreasItem' |
| | | /> |
| | | )} |
| | | </TopToolbar> |
| | | )} |
| | | filters={[...baseFilters, ...dynamicFilters]} |
| | |
| | | > |
| | | <DynamicFields |
| | | drawerOpen={!!drawerVal} |
| | | onDynamicFiltersChange={setDynamicFilters} |
| | | columnDefs={columnDefs} |
| | | /> |
| | | </List> |
| | | <WarehouseAreasItemCreate |
| | |
| | | setDrawerVal={setDrawerVal} |
| | | > |
| | | </WarehouseIsptResult> |
| | | {/* <PageDrawer |
| | | title='WarehouseAreasItem Detail' |
| | | drawerVal={drawerVal} |
| | | setDrawerVal={setDrawerVal} |
| | | > |
| | | </PageDrawer> */} |
| | | </Box> |
| | | ) |
| | | } |
| | |
| | | export default WarehouseAreasItemList; |
| | | |
| | | |
| | | const DynamicFields = ({ drawerOpen, onDynamicFiltersChange }) => { |
| | | const notify = useNotify(); |
| | | const [columns, setColumns] = useState([]); |
| | | const DynamicFields = ({ drawerOpen, columnDefs }) => { |
| | | const { isLoading } = useListContext(); |
| | | const { boxMaxWidth, boxMaxHeight } = useTableLayout(drawerOpen); |
| | | |
| | | useEffect(() => { |
| | | let active = true; |
| | | |
| | | const getDynamicFields = async () => { |
| | | try { |
| | | const { data: { code, data, msg }, } = await request.get("/fields/enable/list"); |
| | | if (!active) { |
| | | return; |
| | | } |
| | | if (code === 200) { |
| | | const dynamicColumns = data.map(buildDynamicColumn); |
| | | const nextDynamicFilters = data |
| | | .filter((field) => !baseFilterSources.has(field.fields)) |
| | | .map(buildDynamicFilter); |
| | | |
| | | setColumns([...baseColumns, ...dynamicColumns, ...trailingColumns]); |
| | | onDynamicFiltersChange(nextDynamicFilters); |
| | | } else { |
| | | notify(msg); |
| | | } |
| | | } catch (error) { |
| | | if (active) { |
| | | notify('请求出错'); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | getDynamicFields(); |
| | | |
| | | return () => { |
| | | active = false; |
| | | onDynamicFiltersChange([]); |
| | | }; |
| | | }, [notify, onDynamicFiltersChange]); |
| | | const columns = columnDefs.map(buildFieldElement); |
| | | |
| | | return ( |
| | | <Box sx={{ |
| | |
| | | {columns.length > 0 && |
| | | <StickyDataTable |
| | | storeKey='warehouseAreasItem' |
| | | bulkActionButtons={false} |
| | | bulkActionButtons={( |
| | | <ListExportPrintButton |
| | | storeKey='warehouseAreasItem' |
| | | columns={columnDefs} |
| | | title='menu.warehouseAreasItem' |
| | | /> |
| | | )} |
| | | rowClick={false} |
| | | hiddenColumns={hiddenColumns} |
| | | hiddenColumns={hiddenColumnSources} |
| | | > |
| | | {columns} |
| | | </StickyDataTable>} |
| New file |
| | |
| | | package com.vincent.rsf.server.common.service; |
| | | |
| | | import com.vincent.rsf.server.common.domain.BaseParam; |
| | | import com.vincent.rsf.server.common.utils.ExcelUtil; |
| | | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | public interface ListExportHandler<T, P extends BaseParam> { |
| | | List<T> listByIds(List<Long> ids); |
| | | |
| | | List<T> listByFilter(Map<String, Object> sanitizedMap, P baseParam); |
| | | |
| | | default void fillExportFields(List<T> records) { |
| | | } |
| | | |
| | | Map<String, Object> toExportRow(T record, List<ExcelUtil.ExportColumn> columns); |
| | | |
| | | String defaultReportTitle(); |
| | | } |
| New file |
| | |
| | | package com.vincent.rsf.server.common.service; |
| | | |
| | | import com.vincent.rsf.framework.exception.CoolException; |
| | | import com.vincent.rsf.server.common.domain.BaseParam; |
| | | import com.vincent.rsf.server.common.utils.ExcelUtil; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.Set; |
| | | import java.util.function.Function; |
| | | |
| | | @Service |
| | | public class ListExportService { |
| | | private static final Set<String> EXPORT_ONLY_KEYS = Set.of( |
| | | "columns", |
| | | "reportTitle", |
| | | "reportDate", |
| | | "printedAt", |
| | | "operator", |
| | | "count", |
| | | "report_title", |
| | | "report_date", |
| | | "printed_at" |
| | | ); |
| | | |
| | | public <T, P extends BaseParam> void export( |
| | | Map<String, Object> map, |
| | | Function<Map<String, Object>, P> paramBuilder, |
| | | ListExportHandler<T, P> exportHandler, |
| | | HttpServletResponse response |
| | | ) throws Exception { |
| | | Map<String, Object> sanitizedMap = sanitizeExportMap(map); |
| | | P baseParam = paramBuilder.apply(sanitizedMap); |
| | | List<ExcelUtil.ExportColumn> columns = buildExportColumns(map); |
| | | if (columns.isEmpty()) { |
| | | throw new CoolException("导出列不能为空"); |
| | | } |
| | | |
| | | List<T> records = getExportRecords(sanitizedMap, baseParam, exportHandler); |
| | | exportHandler.fillExportFields(records); |
| | | |
| | | List<Map<String, Object>> rows = records.stream() |
| | | .map(record -> exportHandler.toExportRow(record, columns)) |
| | | .toList(); |
| | | |
| | | ExcelUtil.ExportMeta exportMeta = buildExportMeta(map, rows.size(), exportHandler.defaultReportTitle()); |
| | | ExcelUtil.build(ExcelUtil.create(rows, columns, exportMeta), response); |
| | | } |
| | | |
| | | private Map<String, Object> sanitizeExportMap(Map<String, Object> map) { |
| | | Map<String, Object> exportMap = new HashMap<>(map); |
| | | EXPORT_ONLY_KEYS.forEach(exportMap::remove); |
| | | exportMap.remove("meta"); |
| | | |
| | | sanitizeNestedMap(exportMap, "filter"); |
| | | sanitizeNestedMap(exportMap, "filterValues"); |
| | | return exportMap; |
| | | } |
| | | |
| | | private void sanitizeNestedMap(Map<String, Object> exportMap, String key) { |
| | | Object nestedObject = exportMap.get(key); |
| | | if (nestedObject instanceof Map<?, ?> nestedMap) { |
| | | Map<String, Object> sanitizedMap = new HashMap<>(); |
| | | for (Map.Entry<?, ?> entry : nestedMap.entrySet()) { |
| | | String nestedKey = String.valueOf(entry.getKey()); |
| | | if (!EXPORT_ONLY_KEYS.contains(nestedKey)) { |
| | | sanitizedMap.put(nestedKey, entry.getValue()); |
| | | } |
| | | } |
| | | exportMap.put(key, sanitizedMap); |
| | | } |
| | | } |
| | | |
| | | private List<ExcelUtil.ExportColumn> buildExportColumns(Map<String, Object> map) { |
| | | Object columnsObject = map.get("columns"); |
| | | if (Objects.isNull(columnsObject)) { |
| | | Object metaObject = map.get("meta"); |
| | | if (metaObject instanceof Map<?, ?> metaMap) { |
| | | columnsObject = metaMap.get("columns"); |
| | | } |
| | | } |
| | | |
| | | if (!(columnsObject instanceof List<?> rawColumns)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | List<ExcelUtil.ExportColumn> columns = new ArrayList<>(); |
| | | for (Object rawColumn : rawColumns) { |
| | | if (!(rawColumn instanceof Map<?, ?> columnMap)) { |
| | | continue; |
| | | } |
| | | Object source = columnMap.get("source"); |
| | | Object label = columnMap.get("label"); |
| | | if (Objects.isNull(source) || Objects.isNull(label)) { |
| | | continue; |
| | | } |
| | | columns.add(new ExcelUtil.ExportColumn(String.valueOf(source), String.valueOf(label))); |
| | | } |
| | | return columns; |
| | | } |
| | | |
| | | private <T, P extends BaseParam> List<T> getExportRecords( |
| | | Map<String, Object> sanitizedMap, |
| | | P baseParam, |
| | | ListExportHandler<T, P> exportHandler |
| | | ) { |
| | | List<Long> ids = parseExportIds(sanitizedMap.get("ids")); |
| | | if (!ids.isEmpty()) { |
| | | return exportHandler.listByIds(ids); |
| | | } |
| | | return exportHandler.listByFilter(sanitizedMap, baseParam); |
| | | } |
| | | |
| | | private List<Long> parseExportIds(Object idsObject) { |
| | | if (idsObject instanceof List<?> ids && !ids.isEmpty()) { |
| | | return ids.stream() |
| | | .map(String::valueOf) |
| | | .map(Long::valueOf) |
| | | .toList(); |
| | | } |
| | | if (idsObject instanceof Object[] ids && ids.length > 0) { |
| | | List<Long> exportIds = new ArrayList<>(); |
| | | for (Object id : ids) { |
| | | exportIds.add(Long.valueOf(String.valueOf(id))); |
| | | } |
| | | return exportIds; |
| | | } |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | private ExcelUtil.ExportMeta buildExportMeta(Map<String, Object> map, int count, String defaultReportTitle) { |
| | | Object metaObject = map.get("meta"); |
| | | if (!(metaObject instanceof Map<?, ?> metaMap)) { |
| | | return new ExcelUtil.ExportMeta(defaultReportTitle, "", "", "", count); |
| | | } |
| | | |
| | | String reportTitle = getMetaValue(metaMap, "reportTitle", defaultReportTitle); |
| | | String reportDate = getMetaValue(metaMap, "reportDate", ""); |
| | | String printedAt = getMetaValue(metaMap, "printedAt", ""); |
| | | String operator = getMetaValue(metaMap, "operator", ""); |
| | | return new ExcelUtil.ExportMeta(reportTitle, reportDate, printedAt, operator, count); |
| | | } |
| | | |
| | | private String getMetaValue(Map<?, ?> metaMap, String key, String defaultValue) { |
| | | Object value = metaMap.get(key); |
| | | return Objects.isNull(value) ? defaultValue : String.valueOf(value); |
| | | } |
| | | } |
| | |
| | | import org.apache.poi.hssf.usermodel.HSSFWorkbook; |
| | | import org.apache.poi.ss.usermodel.*; |
| | | import org.apache.poi.xssf.usermodel.XSSFWorkbook; |
| | | import org.apache.poi.ss.util.CellRangeAddress; |
| | | |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import java.io.IOException; |
| | |
| | | import java.net.URLEncoder; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.*; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | |
| | | /** |
| | | * Created by vincent on 2/17/2024 |
| | | */ |
| | | @Slf4j |
| | | public class ExcelUtil { |
| | | private static final Pattern EXTEND_FIELD_SOURCE_PATTERN = Pattern.compile("^extendFields\\.\\[(.+)]$"); |
| | | |
| | | public static void build(Workbook workbook, HttpServletResponse response) { |
| | | response.reset(); |
| | | Http.cors(response); |
| | |
| | | } catch (IllegalAccessException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | if (value != null) { |
| | | if (value instanceof Date) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | row.createCell(cellIndex).setCellValue(sdf.format((Date) value)); |
| | | } else { |
| | | row.createCell(cellIndex).setCellValue(value.toString()); |
| | | } |
| | | } |
| | | writeCellValue(row, cellIndex, value); |
| | | cellIndex++; |
| | | } |
| | | } |
| | |
| | | return workbook; |
| | | } |
| | | |
| | | public static Workbook create(List<Map<String, Object>> rows, List<ExportColumn> columns) { |
| | | return create(rows, columns, null); |
| | | } |
| | | |
| | | public static Workbook create(List<Map<String, Object>> rows, List<ExportColumn> columns, ExportMeta exportMeta) { |
| | | XSSFWorkbook workbook = new XSSFWorkbook(); |
| | | Sheet sheet = workbook.createSheet("export"); |
| | | int titleColumnCount = Math.max(columns.size(), 4); |
| | | int currentRowIndex = 0; |
| | | |
| | | CellStyle titleStyle = createTitleStyle(workbook); |
| | | CellStyle subHeaderStyle = createSubHeaderStyle(workbook); |
| | | CellStyle headerStyle = createHeaderStyle(workbook); |
| | | CellStyle bodyStyle = createBodyStyle(workbook); |
| | | |
| | | if (exportMeta != null && StringUtils.isNotBlank(exportMeta.getReportTitle())) { |
| | | Row titleRow = sheet.createRow(currentRowIndex++); |
| | | titleRow.setHeightInPoints(24); |
| | | Cell titleCell = titleRow.createCell(0); |
| | | titleCell.setCellValue(exportMeta.getReportTitle()); |
| | | titleCell.setCellStyle(titleStyle); |
| | | sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, titleColumnCount - 1)); |
| | | |
| | | Row subHeaderRow = sheet.createRow(currentRowIndex++); |
| | | writeSubHeaderCell(subHeaderRow, 0, getSubHeaderText("报表日期", exportMeta.getReportDate()), subHeaderStyle); |
| | | writeSubHeaderCell(subHeaderRow, 1, getSubHeaderText("打印人", exportMeta.getOperator()), subHeaderStyle); |
| | | writeSubHeaderCell(subHeaderRow, 2, getSubHeaderText("打印时间", exportMeta.getPrintedAt()), subHeaderStyle); |
| | | writeSubHeaderCell(subHeaderRow, 3, getSubHeaderText("记录数", String.valueOf(exportMeta.getCount())), subHeaderStyle); |
| | | |
| | | currentRowIndex++; |
| | | } |
| | | |
| | | Row header = sheet.createRow(currentRowIndex++); |
| | | for (int index = 0; index < columns.size(); index++) { |
| | | Cell headerCell = header.createCell(index); |
| | | headerCell.setCellValue(columns.get(index).getLabel()); |
| | | headerCell.setCellStyle(headerStyle); |
| | | } |
| | | |
| | | int rowIndex = currentRowIndex; |
| | | for (Map<String, Object> rowData : rows) { |
| | | Row row = sheet.createRow(rowIndex++); |
| | | for (int columnIndex = 0; columnIndex < columns.size(); columnIndex++) { |
| | | Object value = getRowValue(rowData, columns.get(columnIndex).getSource()); |
| | | writeCellValue(row, columnIndex, value, bodyStyle); |
| | | } |
| | | } |
| | | |
| | | for (int columnIndex = 0; columnIndex < columns.size(); columnIndex++) { |
| | | sheet.autoSizeColumn(columnIndex); |
| | | } |
| | | |
| | | return workbook; |
| | | } |
| | | |
| | | private static Object getRowValue(Map<String, Object> rowData, String source) { |
| | | if (rowData == null || StringUtils.isBlank(source)) { |
| | | return null; |
| | | } |
| | | |
| | | if (rowData.containsKey(source)) { |
| | | return rowData.get(source); |
| | | } |
| | | |
| | | Matcher matcher = EXTEND_FIELD_SOURCE_PATTERN.matcher(source); |
| | | if (matcher.matches()) { |
| | | Object extendFields = rowData.get("extendFields"); |
| | | if (extendFields instanceof Map<?, ?> extendFieldMap) { |
| | | return extendFieldMap.get(matcher.group(1)); |
| | | } |
| | | } |
| | | |
| | | return rowData.get(source); |
| | | } |
| | | |
| | | private static void writeCellValue(Row row, int cellIndex, Object value) { |
| | | writeCellValue(row, cellIndex, value, null); |
| | | } |
| | | |
| | | private static void writeCellValue(Row row, int cellIndex, Object value, CellStyle cellStyle) { |
| | | Cell cell = row.createCell(cellIndex); |
| | | if (cellStyle != null) { |
| | | cell.setCellStyle(cellStyle); |
| | | } |
| | | if (value == null) { |
| | | return; |
| | | } |
| | | if (value instanceof Date) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | cell.setCellValue(sdf.format((Date) value)); |
| | | return; |
| | | } |
| | | cell.setCellValue(value.toString()); |
| | | } |
| | | |
| | | private static void writeSubHeaderCell(Row row, int cellIndex, String value, CellStyle cellStyle) { |
| | | Cell cell = row.createCell(cellIndex); |
| | | cell.setCellValue(value); |
| | | cell.setCellStyle(cellStyle); |
| | | } |
| | | |
| | | private static String getSubHeaderText(String label, String value) { |
| | | return label + ": " + StringUtils.defaultString(value); |
| | | } |
| | | |
| | | private static CellStyle createTitleStyle(Workbook workbook) { |
| | | CellStyle cellStyle = workbook.createCellStyle(); |
| | | cellStyle.setAlignment(HorizontalAlignment.CENTER); |
| | | cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); |
| | | |
| | | Font font = workbook.createFont(); |
| | | font.setBold(true); |
| | | font.setFontHeightInPoints((short) 14); |
| | | cellStyle.setFont(font); |
| | | return cellStyle; |
| | | } |
| | | |
| | | private static CellStyle createSubHeaderStyle(Workbook workbook) { |
| | | CellStyle cellStyle = workbook.createCellStyle(); |
| | | cellStyle.setAlignment(HorizontalAlignment.LEFT); |
| | | cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); |
| | | |
| | | Font font = workbook.createFont(); |
| | | font.setFontHeightInPoints((short) 10); |
| | | cellStyle.setFont(font); |
| | | return cellStyle; |
| | | } |
| | | |
| | | private static CellStyle createHeaderStyle(Workbook workbook) { |
| | | CellStyle cellStyle = workbook.createCellStyle(); |
| | | cellStyle.setAlignment(HorizontalAlignment.CENTER); |
| | | cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); |
| | | |
| | | Font font = workbook.createFont(); |
| | | font.setBold(true); |
| | | font.setFontHeightInPoints((short) 10); |
| | | cellStyle.setFont(font); |
| | | return cellStyle; |
| | | } |
| | | |
| | | private static CellStyle createBodyStyle(Workbook workbook) { |
| | | CellStyle cellStyle = workbook.createCellStyle(); |
| | | cellStyle.setAlignment(HorizontalAlignment.LEFT); |
| | | cellStyle.setVerticalAlignment(VerticalAlignment.TOP); |
| | | cellStyle.setWrapText(true); |
| | | return cellStyle; |
| | | } |
| | | |
| | | public static class ExportColumn { |
| | | private final String source; |
| | | private final String label; |
| | | |
| | | public ExportColumn(String source, String label) { |
| | | this.source = source; |
| | | this.label = label; |
| | | } |
| | | |
| | | public String getSource() { |
| | | return source; |
| | | } |
| | | |
| | | public String getLabel() { |
| | | return label; |
| | | } |
| | | } |
| | | |
| | | public static class ExportMeta { |
| | | private final String reportTitle; |
| | | private final String reportDate; |
| | | private final String printedAt; |
| | | private final String operator; |
| | | private final int count; |
| | | |
| | | public ExportMeta(String reportTitle, String reportDate, String printedAt, String operator, int count) { |
| | | this.reportTitle = reportTitle; |
| | | this.reportDate = reportDate; |
| | | this.printedAt = printedAt; |
| | | this.operator = operator; |
| | | this.count = count; |
| | | } |
| | | |
| | | public String getReportTitle() { |
| | | return reportTitle; |
| | | } |
| | | |
| | | public String getReportDate() { |
| | | return reportDate; |
| | | } |
| | | |
| | | public String getPrintedAt() { |
| | | return printedAt; |
| | | } |
| | | |
| | | public String getOperator() { |
| | | return operator; |
| | | } |
| | | |
| | | public int getCount() { |
| | | return count; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 添加导入excel配置参数 |
| | | * 注:默认配置可满足当前需求 |
| | |
| | | package com.vincent.rsf.server.manager.controller; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.vincent.rsf.framework.common.Cools; |
| | | import com.vincent.rsf.framework.common.R; |
| | | import com.vincent.rsf.framework.exception.CoolException; |
| | | import com.vincent.rsf.server.common.utils.ExcelUtil; |
| | | import com.vincent.rsf.server.common.annotation.OperationLog; |
| | | import com.vincent.rsf.server.common.domain.BaseParam; |
| | | import com.vincent.rsf.server.common.domain.KeyValVo; |
| | | import com.vincent.rsf.server.common.domain.PageParam; |
| | | import com.vincent.rsf.server.common.service.ListExportHandler; |
| | | import com.vincent.rsf.server.common.service.ListExportService; |
| | | import com.vincent.rsf.server.common.utils.ExcelUtil; |
| | | import com.vincent.rsf.server.manager.controller.params.WarehouseAreaParam; |
| | | import com.vincent.rsf.server.manager.entity.Loc; |
| | | import com.vincent.rsf.server.manager.entity.WarehouseAreas; |
| | |
| | | import com.vincent.rsf.server.system.controller.BaseController; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import org.springframework.beans.BeanWrapper; |
| | | import org.springframework.beans.BeanWrapperImpl; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.web.bind.annotation.*; |
| | |
| | | |
| | | @Autowired |
| | | private LocService locService; |
| | | |
| | | @Autowired |
| | | private ListExportService listExportService; |
| | | |
| | | private final ListExportHandler<WarehouseAreas, BaseParam> warehouseAreasExportHandler = new ListExportHandler<>() { |
| | | @Override |
| | | public List<WarehouseAreas> listByIds(List<Long> ids) { |
| | | return warehouseAreasService.listByIds(ids); |
| | | } |
| | | |
| | | @Override |
| | | public List<WarehouseAreas> listByFilter(Map<String, Object> sanitizedMap, BaseParam baseParam) { |
| | | PageParam<WarehouseAreas, BaseParam> pageParam = new PageParam<>(baseParam, WarehouseAreas.class); |
| | | QueryWrapper<WarehouseAreas> queryWrapper = pageParam.buildWrapper(true); |
| | | return warehouseAreasService.list(queryWrapper); |
| | | } |
| | | |
| | | @Override |
| | | public Map<String, Object> toExportRow(WarehouseAreas record, List<ExcelUtil.ExportColumn> columns) { |
| | | BeanWrapper beanWrapper = new BeanWrapperImpl(record); |
| | | Map<String, Object> row = new LinkedHashMap<>(); |
| | | |
| | | for (ExcelUtil.ExportColumn column : columns) { |
| | | if (beanWrapper.isReadableProperty(column.getSource())) { |
| | | row.put(column.getSource(), beanWrapper.getPropertyValue(column.getSource())); |
| | | } |
| | | } |
| | | |
| | | return row; |
| | | } |
| | | |
| | | @Override |
| | | public String defaultReportTitle() { |
| | | return "仓库库区报表"; |
| | | } |
| | | }; |
| | | |
| | | @PreAuthorize("hasAuthority('manager:warehouseAreas:list')") |
| | | @PostMapping("/warehouseAreas/page") |
| | |
| | | @PreAuthorize("hasAuthority('manager:warehouseAreas:list')") |
| | | @PostMapping("/warehouseAreas/export") |
| | | public void export(@RequestBody Map<String, Object> map, HttpServletResponse response) throws Exception { |
| | | ExcelUtil.build(ExcelUtil.create(warehouseAreasService.list(), WarehouseAreas.class), response); |
| | | listExportService.export( |
| | | map, |
| | | exportMap -> buildParam(exportMap, BaseParam.class), |
| | | warehouseAreasExportHandler, |
| | | response |
| | | ); |
| | | } |
| | | |
| | | } |
| | |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.vincent.rsf.framework.common.Cools; |
| | | import com.vincent.rsf.framework.common.R; |
| | | import com.vincent.rsf.server.common.utils.ExcelUtil; |
| | | import com.vincent.rsf.server.common.annotation.OperationLog; |
| | | import com.vincent.rsf.server.common.domain.BaseParam; |
| | | import com.vincent.rsf.server.common.domain.KeyValVo; |
| | | import com.vincent.rsf.server.common.domain.PageParam; |
| | | import com.vincent.rsf.server.common.service.ListExportHandler; |
| | | import com.vincent.rsf.server.common.service.ListExportService; |
| | | import com.vincent.rsf.server.common.utils.ExcelUtil; |
| | | import com.vincent.rsf.server.common.utils.FieldsUtils; |
| | | import com.vincent.rsf.server.manager.entity.WarehouseAreasItem; |
| | | import com.vincent.rsf.server.manager.service.WarehouseAreasItemService; |
| | | import com.vincent.rsf.server.system.controller.BaseController; |
| | | import io.swagger.annotations.Api; |
| | | import org.springframework.beans.BeanWrapper; |
| | | import org.springframework.beans.BeanWrapperImpl; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.web.bind.annotation.*; |
| | |
| | | @Api(tags = "库区库存明细") |
| | | @RestController |
| | | public class WarehouseAreasItemController extends BaseController { |
| | | |
| | | @Autowired |
| | | private WarehouseAreasItemService warehouseAreasItemService; |
| | | |
| | | @Autowired |
| | | private ListExportService listExportService; |
| | | |
| | | private final ListExportHandler<WarehouseAreasItem, BaseParam> warehouseAreasItemExportHandler = new ListExportHandler<>() { |
| | | @Override |
| | | public List<WarehouseAreasItem> listByIds(List<Long> ids) { |
| | | return warehouseAreasItemService.listByIds(ids); |
| | | } |
| | | |
| | | @Override |
| | | public List<WarehouseAreasItem> listByFilter(Map<String, Object> sanitizedMap, BaseParam baseParam) { |
| | | PageParam<WarehouseAreasItem, BaseParam> pageParam = new PageParam<>(baseParam, WarehouseAreasItem.class); |
| | | QueryWrapper<WarehouseAreasItem> queryWrapper = pageParam.buildWrapper(true); |
| | | FieldsUtils.setFieldsFilters(queryWrapper, pageParam, WarehouseAreasItem.class); |
| | | return warehouseAreasItemService.list(queryWrapper); |
| | | } |
| | | |
| | | @Override |
| | | public void fillExportFields(List<WarehouseAreasItem> records) { |
| | | fillExtendFields(records); |
| | | } |
| | | |
| | | @Override |
| | | public Map<String, Object> toExportRow(WarehouseAreasItem record, List<ExcelUtil.ExportColumn> columns) { |
| | | return buildExportRow(record, columns); |
| | | } |
| | | |
| | | @Override |
| | | public String defaultReportTitle() { |
| | | return "收货库存报表"; |
| | | } |
| | | }; |
| | | |
| | | @PreAuthorize("hasAuthority('manager:warehouseAreasItem:list')") |
| | | @PostMapping("/warehouseAreasItem/page") |
| | |
| | | @PreAuthorize("hasAuthority('manager:warehouseAreasItem:list')") |
| | | @PostMapping("/warehouseAreasItem/export") |
| | | public void export(@RequestBody Map<String, Object> map, HttpServletResponse response) throws Exception { |
| | | ExcelUtil.build(ExcelUtil.create(warehouseAreasItemService.list(), WarehouseAreasItem.class), response); |
| | | listExportService.export( |
| | | map, |
| | | exportMap -> buildParam(exportMap, BaseParam.class), |
| | | warehouseAreasItemExportHandler, |
| | | response |
| | | ); |
| | | } |
| | | |
| | | private void fillExtendFields(List<WarehouseAreasItem> records) { |
| | | for (WarehouseAreasItem record : records) { |
| | | if (!Objects.isNull(record.getFieldsIndex())) { |
| | | Map<String, String> fields = FieldsUtils.getFields(record.getFieldsIndex()); |
| | | record.setExtendFields(fields); |
| | | } |
| | | } |
| | | } |
| | | private Map<String, Object> buildExportRow(WarehouseAreasItem record, List<ExcelUtil.ExportColumn> columns) { |
| | | BeanWrapper beanWrapper = new BeanWrapperImpl(record); |
| | | Map<String, Object> row = new LinkedHashMap<>(); |
| | | row.put("extendFields", record.getExtendFields()); |
| | | |
| | | for (ExcelUtil.ExportColumn column : columns) { |
| | | if (column.getSource().startsWith("extendFields.[")) { |
| | | continue; |
| | | } |
| | | if (beanWrapper.isReadableProperty(column.getSource())) { |
| | | row.put(column.getSource(), beanWrapper.getPropertyValue(column.getSource())); |
| | | } |
| | | } |
| | | |
| | | return row; |
| | | } |
| | | |
| | | } |