zhou zhou
21 小时以前 51ba2a9f70863036c720156cd8b9e0c2be08139b
Revert "#打印+导出"

This reverts commit 6e5ff559023efd2d24fdca2adcb7268d06420e46.
12个文件已删除
6个文件已修改
3029 ■■■■■ 已修改文件
rsf-admin/src/page/components/MyExportButton.jsx 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/components/listReport/ListReportActions.jsx 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/components/listReport/ListReportPreviewDialog.jsx 607 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/components/listReport/MyPrintButton.jsx 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/components/listReport/listReportUtils.js 162 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/components/listReport/useListReportOutput.js 292 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/warehouseAreasItem/WarehouseAreasItemList.jsx 385 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/warehouseAreasItem/WarehouseAreasItemPrintPreview.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/warehouseAreasItem/warehouseAreasItemOutputUtils.jsx 493 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/domain/report/ReportColumnMeta.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/domain/report/ReportMeta.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/domain/report/ReportQueryRequest.java 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/domain/report/ReportQueryResponse.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/support/report/ListReportSupport.java 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/utils/ExcelUtil.java 354 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WarehouseAreasItemController.java 97 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/WarehouseAreasItemService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WarehouseAreasItemServiceImpl.java 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/components/MyExportButton.jsx
@@ -1,4 +1,5 @@
import * as React from "react";
import { useCallback } from "react";
import DownloadIcon from "@mui/icons-material/GetApp";
import {
  Button,
@@ -7,11 +8,6 @@
  useListContext,
  useUnselectAll,
} from "react-admin";
import { useListReportActionParams } from "./listReport/useListReportOutput";
import {
  downloadBlobFile,
  resolveReportMeta,
} from "./listReport/listReportUtils";
const MyExportButton = (props) => {
  const {
@@ -22,73 +18,62 @@
    icon = defaultIcon,
    exporter: customExporter,
    meta,
    reportConfig,
    onExport,
    loading = false,
    filename,
    ...rest
  } = props;
  const { filter, selectedIds, filterValues, resource, sort, total } = useListContext();
  const { visibleColumns, params } = useListReportActionParams(reportConfig, { ids });
  const unSelect = useUnselectAll(resource);
  const dataProvider = useDataProvider();
  const notify = useNotify();
  const handleClick = async (event) => {
    try {
      const hasReportConfig = Boolean(reportConfig?.resource && Array.isArray(reportConfig?.columns));
      if (hasReportConfig) {
        const actionParams = {
          ...params,
          columns: visibleColumns,
        };
        if (typeof onExport === "function") {
          await onExport(actionParams, event);
        } else {
          const resolvedResource = reportConfig.resource || params.resource;
          const response = await dataProvider.export(resolvedResource, {
            sort: actionParams.sort,
            ids: actionParams.ids,
            filter: actionParams.filter
              ? { ...actionParams.filterValues, ...actionParams.filter }
              : actionParams.filterValues,
            pagination: { page: 1, perPage: maxResults },
            meta,
            columns: visibleColumns,
            reportMeta: resolveReportMeta(reportConfig, actionParams),
          });
          downloadBlobFile(
            response,
            filename || reportConfig.exportFileName || `${resolvedResource}.xlsx`,
          );
        }
      } else {
        const response = await dataProvider.export(resource, {
  const handleClick =
  // useCallback(
    (event) => {
      dataProvider
        .export(resource, {
          sort,
          ids: ids ?? selectedIds,
          ids: selectedIds,
          filter: filter ? { ...filterValues, ...filter } : filterValues,
          pagination: { page: 1, perPage: maxResults },
          meta,
        })
        .then((res) => {
          const url = window.URL.createObjectURL(
            new Blob([res.data], { type: res.headers["content-type"] }),
          );
          const link = document.createElement("a");
          link.href = url;
          link.setAttribute("download", `${resource}.xlsx`);
          document.body.appendChild(link);
          link.click();
          link.remove();
          unSelect();
        })
        .catch((error) => {
          console.error(error);
          notify("ra.notification.http_error", { type: "error" });
        });
        downloadBlobFile(response, filename || `${resource}.xlsx`);
      }
      unSelect();
      if (typeof onClick === "function") {
        onClick(event);
      }
    } catch (error) {
      console.error(error);
      notify("ra.notification.http_error", { type: "error" });
    }
  };
  const disabled = total === 0 || loading || (reportConfig?.columns && visibleColumns.length === 0);
    // [
    //   dataProvider,
    //   filter,
    //   filterValues,
    //   maxResults,
    //   notify,
    //   onClick,
    //   resource,
    //   sort,
    //   meta,
    // ],
  // );
  return (
    <Button
      onClick={handleClick}
      label={label}
      disabled={disabled}
      disabled={total === 0}
      {...sanitizeRestProps(rest)}
    >
      {icon}
rsf-admin/src/page/components/listReport/ListReportActions.jsx
File was deleted
rsf-admin/src/page/components/listReport/ListReportPreviewDialog.jsx
File was deleted
rsf-admin/src/page/components/listReport/MyPrintButton.jsx
File was deleted
rsf-admin/src/page/components/listReport/listReportUtils.js
File was deleted
rsf-admin/src/page/components/listReport/useListReportOutput.js
File was deleted
rsf-admin/src/page/warehouseAreasItem/WarehouseAreasItemList.jsx
@@ -1,228 +1,267 @@
import React, { useEffect, useMemo, useState } from "react";
import React, { useState, useRef, useEffect, useMemo, useCallback } from "react";
import { useNavigate } from 'react-router-dom';
import {
    DatagridConfigurable,
    List,
    useListContext,
    useNotify,
    DatagridConfigurable,
    SearchInput,
    TopToolbar,
    SelectColumnsButton,
    EditButton,
    FilterButton,
    CreateButton,
    ExportButton,
    BulkDeleteButton,
    WrapperField,
    useRecordContext,
    useTranslate,
} from "react-admin";
import { Box, LinearProgress } from "@mui/material";
import { styled } from "@mui/material/styles";
import { DEFAULT_PAGE_SIZE } from "@/config/setting";
import ListReportActions, {
    ListReportBulkActions,
} from "@/page/components/listReport/ListReportActions";
import ListReportPreviewDialog from "@/page/components/listReport/ListReportPreviewDialog";
import { useListReportOutput } from "@/page/components/listReport/useListReportOutput";
import { buildListReportRequestPayload } from "@/page/components/listReport/listReportUtils";
import request from "@/utils/request";
import WarehouseIsptResult from "./WarehouseIsptResult";
import {
    buildWarehouseAreasItemBaseFilters,
    buildWarehouseAreasItemDynamicFilters,
    buildWarehouseAreasItemReportConfig,
} from "./warehouseAreasItemOutputUtils.jsx";
    useNotify,
    useListContext,
    FunctionField,
    TextField,
    NumberField,
    DateField,
    BooleanField,
    ReferenceField,
    TextInput,
    DateTimeInput,
    DateInput,
    SelectInput,
    NumberInput,
    ReferenceInput,
    ReferenceArrayInput,
    useRefresh,
    AutocompleteInput,
    DeleteButton,
} from 'react-admin';
import { Box, Typography, Card, Stack, LinearProgress } from '@mui/material';
import { styled } from '@mui/material/styles';
import WarehouseAreasItemCreate from "./WarehouseAreasItemCreate";
import WarehouseAreasItemPanel from "./WarehouseAreasItemPanel";
import EmptyData from "../components/EmptyData";
import request from '@/utils/request';
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 WarehouseIsptResult from "./WarehouseIsptResult"
const StyledDatagrid = styled(DatagridConfigurable)(() => ({
    "& .css-1vooibu-MuiSvgIcon-root": {
        height: ".9em",
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
    '& .css-1vooibu-MuiSvgIcon-root': {
        height: '.9em'
    },
    "& .RaDatagrid-row": {
        cursor: "auto",
    '& .RaDatagrid-row': {
        cursor: 'auto'
    },
    "& .opt": {
        width: 200,
    '& .column-name': {
    },
    "& .MuiTableCell-root": {
        whiteSpace: "nowrap",
        overflow: "visible",
        textOverflow: "unset",
    '& .opt': {
        width: 200
    },
    '& .MuiTableCell-root': {
    whiteSpace: 'nowrap',
    overflow: 'visible',
    textOverflow: 'unset'
  }
}));
const filters = [
    <SearchInput source="condition" alwaysOn />,
    <NumberInput source="areaId" label="table.field.warehouseAreasItem.areaId" />,
    <TextInput source="asnCode" label="table.field.warehouseAreasItem.asnCode" />,
    <TextInput source="areaName" label="table.field.warehouseAreasItem.areaName" />,
    <NumberInput source="matnrId" label="table.field.warehouseAreasItem.matnrId" />,
    <TextInput source="matnrName" label="table.field.warehouseAreasItem.matnrName" />,
    <TextInput source="matnrCode" label="table.field.warehouseAreasItem.matnrCode" />,
    <TextInput source="barcode" label="table.field.warehouseAreasItem.barcode" />,
    <NumberInput source="anfme" label="table.field.warehouseAreasItem.anfme" />,
    <TextInput source="batch" label="table.field.warehouseAreasItem.batch" />,
    <TextInput source="platOrderCode" label="table.field.asnOrderItem.platOrderCode" />,
    <TextInput source="platWorkCode" label="table.field.asnOrderItem.platWorkCode" />,
    <TextInput source="projectCode" label="table.field.asnOrderItem.projectCode" />,
    <TextInput source="unit" label="table.field.warehouseAreasItem.unit" />,
    <TextInput source="stockUnit" label="table.field.warehouseAreasItem.stockUnit" />,
    <TextInput source="brand" label="table.field.warehouseAreasItem.brand" />,
    <ReferenceInput source="shipperId" label="table.field.warehouseAreasItem.shipperId" reference="companys">
        <AutocompleteInput label="table.field.warehouseAreasItem.shipperId" optionText="name" filterToQuery={(val) => ({ name: val })} />
    </ReferenceInput>,
    <TextInput source="splrId" label="table.field.warehouseAreasItem.splrId" />,
    <NumberInput source="weight" label="table.field.warehouseAreasItem.weight" />,
    <TextInput source="prodTime" label="table.field.warehouseAreasItem.prodTime" />,
    <TextInput source="splrBtch" label="table.field.warehouseAreasItem.splrBtch" />,
    <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 WarehouseAreasItemList = () => {
    const translate = useTranslate();
    const notify = useNotify();
    const [itemInfo] = useState({});
    const [itemInfo, setItemInfo] = useState({})
    const [createDialog, setCreateDialog] = useState(false);
    const [drawerVal, setDrawerVal] = useState(false);
    const { dynamicFields, dynamicFieldsLoading } = useWarehouseAreasItemDynamicFields(notify);
    const filters = useMemo(
        () => [
            ...buildWarehouseAreasItemBaseFilters(),
            ...buildWarehouseAreasItemDynamicFilters(dynamicFields),
        ],
        [dynamicFields]
    );
    const reportConfig = useMemo(
        () => buildWarehouseAreasItemReportConfig(translate, dynamicFields),
        [dynamicFields, translate]
    );
    const buildOutputPayload = params => buildListReportRequestPayload({
        ...params,
        reportMeta: reportConfig.buildReportMeta?.(params),
    });
    const {
        exportLoading,
        previewOpen,
        previewRows,
        previewColumns,
        previewMeta,
        previewDataset,
        previewLoading,
        previewPrefetching,
        openPrintPreview,
        closePrintPreview,
        exportReport,
    } = useListReportOutput({
        reportConfig,
        buildRequestPayload: buildOutputPayload,
        notify,
    });
    const reportLoading = dynamicFieldsLoading || exportLoading || previewLoading;
    return (
        <Box display="flex">
            <List
                title="menu.warehouseAreasItem"
                title={"menu.warehouseAreasItem"}
                empty={false}
                filters={filters}
                sort={{ field: "create_time", order: "desc" }}
                sx={{
                    flexGrow: 1,
                    transition: theme =>
                        theme.transitions.create(["all"], {
                    transition: (theme) =>
                        theme.transitions.create(['all'], {
                            duration: theme.transitions.duration.enteringScreen,
                        }),
                }}
                actions={(
                    <ListReportActions
                        reportConfig={reportConfig}
                        loading={reportLoading}
                        onExport={exportReport}
                        onPrintPreview={openPrintPreview}
                    />
                    <TopToolbar>
                        <FilterButton />
                        <SelectColumnsButton preferenceKey='warehouseAreasItem' />
                        <MyExportButton />
                    </TopToolbar>
                )}
                perPage={DEFAULT_PAGE_SIZE}
            >
                <DynamicFields
                    reportConfig={reportConfig}
                    loading={dynamicFieldsLoading}
                    onExport={exportReport}
                    onPrintPreview={openPrintPreview}
                />
                    drawerVal={drawerVal}
                    setDrawerVal={setDrawerVal}
                    itemInfo={itemInfo}
                    setItemInfo={setItemInfo} />
            </List>
            <WarehouseAreasItemCreate
                open={createDialog}
                setOpen={setCreateDialog}
            />
            <WarehouseIsptResult
                record={itemInfo}
                drawerVal={drawerVal}
                from="warehosueItem"
                setDrawerVal={setDrawerVal}
            />
            <ListReportPreviewDialog
                open={previewOpen}
                onClose={closePrintPreview}
                rows={previewRows}
                columns={previewColumns}
                reportMeta={previewMeta}
                totalRows={previewDataset.total}
                loading={previewLoading}
                allRowsLoaded={previewDataset.fullyLoaded}
                loadedTransportPages={previewDataset.loadedPages}
                totalTransportPages={previewDataset.transportPages}
                prefetching={previewPrefetching}
                dialogTitle="收货库存打印预览"
                defaultOrientation={reportConfig.defaultOrientation}
            />
            >
            </WarehouseIsptResult>
            {/* <PageDrawer
                title='WarehouseAreasItem Detail'
                drawerVal={drawerVal}
                setDrawerVal={setDrawerVal}
            >
            </PageDrawer> */}
        </Box>
    );
};
    )
}
export default WarehouseAreasItemList;
const DynamicFields = ({ reportConfig, loading, onExport, onPrintPreview }) => {
const DynamicFields = (props) => {
    const { drawerVal, setDrawerVal, itemInfo, setItemInfo } = props
    const translate = useTranslate();
    const notify = useNotify();
    const [columns, setColumns] = useState([]);
    const { isLoading } = useListContext();
    const refresh = useRefresh();
    useEffect(() => {
        getDynamicFields();
    }, []);
    const getDynamicFields = async () => {
        const { data: { code, data, msg }, } = await request.get("/fields/enable/list");
        if (code == 200) {
            const arr = [
                <NumberField key="id" source="id" />,
                // <NumberField key="areaId" source="areaId" label="table.field.warehouseAreasItem.areaId" />,
                <TextField key="areaName" source="areaName" label="收货区名称" />,    //table.field.warehouseAreasItem.areaName
                <TextField key="asnCode" source="asnCode" label="table.field.warehouseAreasItem.asnCode" />,
                <TextField source="platWorkCode" label="table.field.asnOrderItem.platWorkCode" />,
                <TextField 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 source="platOrderCode" label="table.field.asnOrderItem.platOrderCode" />,
                <TextField source="projectCode" label="table.field.asnOrderItem.projectCode" />,
                // <MyField source="isptQty" label="table.field.qlyIsptItem.anfme"
                //     onClick={(event, record, val) => {
                //         event.stopPropagation();
                //         setItemInfo(record)
                //         setDrawerVal(!!drawerVal && drawerVal === val ? null : val);
                //     }}
                // />,
                // <TextField key="stockUnit" source="stockUnit" label="table.field.warehouseAreasItem.stockUnit" />,
                <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 fields = data.map(el => <TextField key={el.fields} source={`extendFields.[${el.fields}]`} label={el.fieldsAlise} />)
            const lastArr = [
                <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} />,
            ]
            setColumns([...arr, ...fields, ...lastArr]);
            //filters添加过滤字段
            data.map(el => {
                var i = 0;
                filters.map((item) => {
                    if (item.key === el.fields) {
                        i = 1;
                    }
                })
                i === 0 && filters.push(<TextInput key={el.fields} source={el.fields} label={el.fieldsAlise} />)
            })
        } else {
            notify(msg);
        }
    }
    return (
        <Box sx={{ position: "relative", minHeight: "82vh" }}>
            {(isLoading || loading) && (
        <Box sx={{ position: 'relative', minHeight: "82vh", }}>
            {isLoading && (
                <LinearProgress
                    sx={{
                        height: "2px",
                        position: "absolute",
                        position: 'absolute',
                        top: 0,
                        left: 0,
                        right: 0,
                    }}
                />
            )}
            {reportConfig.columns.length > 0 && (
            {columns.length > 0 &&
                <StyledDatagrid
                    preferenceKey={reportConfig.preferenceKey}
                    bulkActionButtons={(
                        <ListReportBulkActions
                            reportConfig={reportConfig}
                            loading={loading}
                            onExport={onExport}
                            onPrintPreview={onPrintPreview}
                        />
                    )}
                    rowClick={false}
                    omit={reportConfig.omit}
                    preferenceKey='warehouseAreasItem'
                    bulkActionButtons={false}
                    rowClick={(id, resource, record) => false}
                    omit={['prodTime','platOrderCode','id', 'createTime', 'memo', 'areaId', 'brand',
                         'weight', 'splrId', 'projectCode','statusBool', 'extendFields.[priceUnitId]', 'isptResult$', 'extendFields.[inStockType]',
                         'matnrId', 'trackCode', 'workQty', 'batch', 'shipperId', 'isptResult', 'createBy$', 'createTime', 'extendFields.[baseUnitId]']}
                >
                    {reportConfig.columns.map(column => column.element)}
                </StyledDatagrid>
            )}
                    {columns.map((column) => column)}
                </StyledDatagrid>}
        </Box>
    );
};
const useWarehouseAreasItemDynamicFields = notify => {
    const [dynamicFields, setDynamicFields] = useState([]);
    const [dynamicFieldsLoading, setDynamicFieldsLoading] = useState(true);
    useEffect(() => {
        let active = true;
        const loadDynamicFields = async () => {
            setDynamicFieldsLoading(true);
            try {
                const { data: { code, data, msg } } = await request.get("/fields/enable/list");
                if (!active) {
                    return;
                }
                if (code === 200) {
                    setDynamicFields(Array.isArray(data) ? data : []);
                    return;
                }
                notify(msg, { type: "warning" });
            } catch (error) {
                if (!active) {
                    return;
                }
                console.error(error);
                notify("ra.notification.http_error", { type: "error" });
            } finally {
                if (active) {
                    setDynamicFieldsLoading(false);
                }
            }
        };
        loadDynamicFields();
        return () => {
            active = false;
        };
    }, [notify]);
    return {
        dynamicFields,
        dynamicFieldsLoading,
    };
};
    )
}
rsf-admin/src/page/warehouseAreasItem/WarehouseAreasItemPrintPreview.jsx
File was deleted
rsf-admin/src/page/warehouseAreasItem/warehouseAreasItemOutputUtils.jsx
File was deleted
rsf-server/src/main/java/com/vincent/rsf/server/common/domain/report/ReportColumnMeta.java
File was deleted
rsf-server/src/main/java/com/vincent/rsf/server/common/domain/report/ReportMeta.java
File was deleted
rsf-server/src/main/java/com/vincent/rsf/server/common/domain/report/ReportQueryRequest.java
File was deleted
rsf-server/src/main/java/com/vincent/rsf/server/common/domain/report/ReportQueryResponse.java
File was deleted
rsf-server/src/main/java/com/vincent/rsf/server/common/support/report/ListReportSupport.java
File was deleted
rsf-server/src/main/java/com/vincent/rsf/server/common/utils/ExcelUtil.java
@@ -15,12 +15,10 @@
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.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
@@ -133,262 +131,6 @@
        return workbook;
    }
    public static Workbook create(List<?> list, List<ColumnMeta> columns) {
        return create(list, columns, null);
    }
    public static Workbook create(List<?> list, List<ColumnMeta> columns, ReportMeta reportMeta) {
        XSSFWorkbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("export");
        List<ColumnMeta> safeColumns = columns == null ? Collections.emptyList() : columns;
        int sheetColumnCount = safeColumns.size() + 1;
        configureA4PrintLayout(sheet);
        CellStyle titleStyle = createTitleStyle(workbook);
        CellStyle metaLabelStyle = createMetaLabelStyle(workbook);
        CellStyle metaValueStyle = createMetaValueStyle(workbook);
        CellStyle headerStyle = createHeaderStyle(workbook);
        CellStyle bodyStyle = createBodyStyle(workbook);
        CellStyle serialStyle = createCenteredBodyStyle(workbook);
        int rowIndex = 0;
        if (reportMeta != null) {
            Row titleRow = sheet.createRow(rowIndex++);
            titleRow.setHeightInPoints(28);
            Cell titleCell = titleRow.createCell(0);
            titleCell.setCellValue(StringUtils.defaultIfBlank(reportMeta.getTitle(), "报表"));
            titleCell.setCellStyle(titleStyle);
            sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, Math.max(0, sheetColumnCount - 1)));
            Row metaRow = sheet.createRow(rowIndex++);
            int metaCol = 0;
            metaCol = writeMetaPair(metaRow, metaCol, "报表日期", reportMeta.getReportDate(), metaLabelStyle, metaValueStyle);
            writeMetaPair(metaRow, metaCol, "打印人", reportMeta.getPrintedBy(), metaLabelStyle, metaValueStyle);
            rowIndex++;
        }
        int headerRowIndex = rowIndex;
        Row header = sheet.createRow(rowIndex++);
        Cell serialHeaderCell = header.createCell(0);
        serialHeaderCell.setCellValue("序号");
        serialHeaderCell.setCellStyle(headerStyle);
        for (int i = 0; i < safeColumns.size(); i++) {
            ColumnMeta column = safeColumns.get(i);
            Cell headerCell = header.createCell(i + 1);
            headerCell.setCellValue(
                    StringUtils.isBlank(column.getLabel()) ? column.getSource() : column.getLabel()
            );
            headerCell.setCellStyle(headerStyle);
        }
        if (list != null) {
            int serialNo = 1;
            for (Object rowObj : list) {
                Row row = sheet.createRow(rowIndex++);
                Cell serialCell = row.createCell(0);
                serialCell.setCellValue(String.format("%03d", serialNo++));
                serialCell.setCellStyle(serialStyle);
                for (int i = 0; i < safeColumns.size(); i++) {
                    Object value = getColumnValue(rowObj, safeColumns.get(i).getSource());
                    Cell cell = row.createCell(i + 1);
                    cell.setCellStyle(bodyStyle);
                    if (value != null) {
                        if (value instanceof Date) {
                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                            cell.setCellValue(sdf.format((Date) value));
                        } else {
                            cell.setCellValue(value.toString());
                        }
                    }
                }
            }
        }
        for (int i = 0; i <= safeColumns.size(); i++) {
            sheet.autoSizeColumn(i);
            sheet.setColumnWidth(i, Math.min(sheet.getColumnWidth(i) + 1024, 12000));
        }
        sheet.setRepeatingRows(CellRangeAddress.valueOf((headerRowIndex + 1) + ":" + (headerRowIndex + 1)));
        return workbook;
    }
    private static void configureA4PrintLayout(Sheet sheet) {
        sheet.setAutobreaks(true);
        sheet.setFitToPage(true);
        sheet.setHorizontallyCenter(true);
        sheet.setDisplayGridlines(false);
        PrintSetup printSetup = sheet.getPrintSetup();
        printSetup.setPaperSize(PrintSetup.A4_PAPERSIZE);
        printSetup.setLandscape(true);
        printSetup.setFitWidth((short) 1);
        printSetup.setFitHeight((short) 0);
        sheet.setMargin(Sheet.LeftMargin, 0.3);
        sheet.setMargin(Sheet.RightMargin, 0.3);
        sheet.setMargin(Sheet.TopMargin, 0.4);
        sheet.setMargin(Sheet.BottomMargin, 0.4);
    }
    private static int writeMetaPair(Row row, int startCol, String label, String value, CellStyle labelStyle, CellStyle valueStyle) {
        Cell labelCell = row.createCell(startCol);
        labelCell.setCellValue(label + ":");
        labelCell.setCellStyle(labelStyle);
        Cell valueCell = row.createCell(startCol + 1);
        valueCell.setCellValue(StringUtils.defaultString(value));
        valueCell.setCellStyle(valueStyle);
        return startCol + 2;
    }
    private static CellStyle createTitleStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setBorderBottom(BorderStyle.THICK);
        Font font = workbook.createFont();
        font.setBold(true);
        font.setFontHeightInPoints((short) 16);
        style.setFont(font);
        return style;
    }
    private static CellStyle createMetaLabelStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.LEFT);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setBorderBottom(BorderStyle.THIN);
        Font font = workbook.createFont();
        font.setBold(true);
        style.setFont(font);
        return style;
    }
    private static CellStyle createMetaValueStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.LEFT);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setBorderBottom(BorderStyle.THIN);
        return style;
    }
    private static CellStyle createHeaderStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        Font font = workbook.createFont();
        font.setBold(true);
        style.setFont(font);
        return style;
    }
    private static CellStyle createBodyStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.LEFT);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        return style;
    }
    private static CellStyle createCenteredBodyStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        return style;
    }
    private static Object getColumnValue(Object rowObj, String source) {
        if (rowObj == null || StringUtils.isBlank(source)) {
            return null;
        }
        if (rowObj instanceof Map) {
            return getValueFromMap((Map<?, ?>) rowObj, source);
        }
        String extendFieldKey = extractExtendFieldKey(source);
        if (extendFieldKey != null) {
            Object extendFields = getBeanValue(rowObj, "extendFields");
            if (extendFields instanceof Map) {
                return ((Map<?, ?>) extendFields).get(extendFieldKey);
            }
            return null;
        }
        return getBeanValue(rowObj, source);
    }
    private static Object getValueFromMap(Map<?, ?> rowObj, String source) {
        String extendFieldKey = extractExtendFieldKey(source);
        if (extendFieldKey != null) {
            Object extendFields = rowObj.get("extendFields");
            if (extendFields instanceof Map) {
                return ((Map<?, ?>) extendFields).get(extendFieldKey);
            }
            return null;
        }
        return rowObj.get(source);
    }
    private static String extractExtendFieldKey(String source) {
        if (source == null || !source.startsWith("extendFields.[")) {
            return null;
        }
        int startIndex = source.indexOf('[');
        int endIndex = source.indexOf(']');
        if (startIndex < 0 || endIndex <= startIndex) {
            return null;
        }
        return source.substring(startIndex + 1, endIndex);
    }
    private static Object getBeanValue(Object rowObj, String source) {
        Object value = invokeGetter(rowObj, source);
        if (value != null) {
            return value;
        }
        Field field = findField(rowObj.getClass(), source);
        if (field == null) {
            return null;
        }
        try {
            field.setAccessible(true);
            return field.get(rowObj);
        } catch (IllegalAccessException ignore) {
            return null;
        }
    }
    private static Object invokeGetter(Object target, String source) {
        String suffix = Character.toUpperCase(source.charAt(0)) + source.substring(1);
        String[] methodNames = new String[] { "get" + suffix, "is" + suffix };
        for (String methodName : methodNames) {
            try {
                Method method = target.getClass().getMethod(methodName);
                return method.invoke(target);
            } catch (Exception ignore) {
            }
        }
        return null;
    }
    private static Field findField(Class<?> clazz, String source) {
        Class<?> current = clazz;
        while (current != null && current != Object.class) {
            try {
                return current.getDeclaredField(source);
            } catch (NoSuchFieldException ignore) {
                current = current.getSuperclass();
            }
        }
        return null;
    }
    /**
     * 添加导入excel配置参数
     * 注:默认配置可满足当前需求
@@ -479,102 +221,6 @@
            return true;
        }
        return false;
    }
    public static class ColumnMeta {
        private String key;
        private String source;
        private String label;
        private Boolean extendField;
        public String getKey() {
            return key;
        }
        public ColumnMeta setKey(String key) {
            this.key = key;
            return this;
        }
        public String getSource() {
            return source;
        }
        public ColumnMeta setSource(String source) {
            this.source = source;
            return this;
        }
        public String getLabel() {
            return label;
        }
        public ColumnMeta setLabel(String label) {
            this.label = label;
            return this;
        }
        public Boolean getExtendField() {
            return extendField;
        }
        public ColumnMeta setExtendField(Boolean extendField) {
            this.extendField = extendField;
            return this;
        }
    }
    public static class ReportMeta {
        private String title;
        private String companyName;
        private String printedBy;
        private String reportDate;
        private String reportDateValue;
        public String getTitle() {
            return title;
        }
        public ReportMeta setTitle(String title) {
            this.title = title;
            return this;
        }
        public String getCompanyName() {
            return companyName;
        }
        public ReportMeta setCompanyName(String companyName) {
            this.companyName = companyName;
            return this;
        }
        public String getReportDate() {
            return reportDate;
        }
        public ReportMeta setReportDate(String reportDate) {
            this.reportDate = reportDate;
            return this;
        }
        public String getReportDateValue() {
            return reportDateValue;
        }
        public ReportMeta setReportDateValue(String reportDateValue) {
            this.reportDateValue = reportDateValue;
            return this;
        }
        public String getPrintedBy() {
            return printedBy;
        }
        public ReportMeta setPrintedBy(String printedBy) {
            this.printedBy = printedBy;
            return this;
        }
    }
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WarehouseAreasItemController.java
@@ -11,9 +11,6 @@
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.domain.report.ReportQueryRequest;
import com.vincent.rsf.server.common.domain.report.ReportQueryResponse;
import com.vincent.rsf.server.common.support.report.ListReportSupport;
import com.vincent.rsf.server.common.utils.FieldsUtils;
import com.vincent.rsf.server.manager.entity.WarehouseAreasItem;
import com.vincent.rsf.server.manager.service.WarehouseAreasItemService;
@@ -36,10 +33,21 @@
    @PreAuthorize("hasAuthority('manager:warehouseAreasItem:list')")
    @PostMapping("/warehouseAreasItem/page")
    public R page(@RequestBody Map<String, Object> map) {
        PageParam<WarehouseAreasItem, BaseParam> pageParam = buildPageParam(map, true);
        QueryWrapper<WarehouseAreasItem> queryWrapper = buildFilterQueryWrapper(pageParam);
        BaseParam baseParam = buildParam(map, BaseParam.class);
        PageParam<WarehouseAreasItem, BaseParam> pageParam = new PageParam<>(baseParam, WarehouseAreasItem.class);
        QueryWrapper<WarehouseAreasItem> queryWrapper = pageParam.buildWrapper(true);
        /**拼接扩展字段过滤*/
        FieldsUtils.setFieldsFilters(queryWrapper,pageParam, WarehouseAreasItem.class);
        /**拼接扩展字段*/
        PageParam<WarehouseAreasItem, BaseParam> page = warehouseAreasItemService.page(pageParam, queryWrapper);
        warehouseAreasItemService.fillExtendFields(page.getRecords());
        List<WarehouseAreasItem> records = page.getRecords();
        for (WarehouseAreasItem record : records) {
            if (!Objects.isNull(record.getFieldsIndex())) {
                Map<String, String> fields = FieldsUtils.getFields(record.getFieldsIndex());
                record.setExtendFields(fields);
            }
        }
        page.setRecords(records);
        return R.ok().add(page);
    }
@@ -47,10 +55,19 @@
    @PreAuthorize("hasAuthority('manager:warehouseAreasItem:list')")
    @PostMapping("/warehouseAreasItem/ispts/page")
    public R getIsptPage(@RequestBody Map<String, Object> map) {
        PageParam<WarehouseAreasItem, BaseParam> pageParam = buildPageParam(map, true);
        BaseParam baseParam = buildParam(map, BaseParam.class);
        PageParam<WarehouseAreasItem, BaseParam> pageParam = new PageParam<>(baseParam, WarehouseAreasItem.class);
        QueryWrapper<WarehouseAreasItem> queryWrapper = pageParam.buildWrapper(true);
        /**拼接扩展字段*/
        IPage<WarehouseAreasItem> page = warehouseAreasItemService.pageByItemId(pageParam, queryWrapper);
        warehouseAreasItemService.fillExtendFields(page.getRecords());
        List<WarehouseAreasItem> records = page.getRecords();
        for (WarehouseAreasItem record : records) {
            if (!Objects.isNull(record.getFieldsIndex())) {
                Map<String, String> fields = FieldsUtils.getFields(record.getFieldsIndex());
                record.setExtendFields(fields);
            }
        }
        page.setRecords(records);
        return R.ok().add(page);
    }
@@ -124,69 +141,7 @@
    @PreAuthorize("hasAuthority('manager:warehouseAreasItem:list')")
    @PostMapping("/warehouseAreasItem/export")
    public void export(@RequestBody Map<String, Object> map, HttpServletResponse response) throws Exception {
        ReportQueryRequest request = ReportQueryRequest.fromMap(map);
        List<WarehouseAreasItem> records = createListReportSupport().queryRecords(request);
        List<ExcelUtil.ColumnMeta> columns = ListReportSupport.toExcelColumns(request.getColumns());
        ExcelUtil.ReportMeta reportMeta = ListReportSupport.toExcelReportMeta(request.getReportMeta());
        if (columns.isEmpty()) {
            ExcelUtil.build(ExcelUtil.create(records, WarehouseAreasItem.class), response);
            return;
        }
        ExcelUtil.build(ExcelUtil.create(records, columns, reportMeta), response);
    }
    @PreAuthorize("hasAuthority('manager:warehouseAreasItem:list')")
    @PostMapping("/warehouseAreasItem/print/query")
    public R printQuery(@RequestBody Map<String, Object> map) {
        ReportQueryResponse<WarehouseAreasItem> result = createListReportSupport()
                .queryPage(ReportQueryRequest.fromMap(map));
        return R.ok().add(result);
    }
    private PageParam<WarehouseAreasItem, BaseParam> buildPageParam(Map<String, Object> map, boolean includeFilters) {
        return buildPageParam(ReportQueryRequest.fromMap(map), includeFilters);
    }
    private PageParam<WarehouseAreasItem, BaseParam> buildPageParam(ReportQueryRequest request, boolean includeFilters) {
        BaseParam baseParam = buildParam(request.toPageParamMap(includeFilters), BaseParam.class);
        return new PageParam<>(baseParam, WarehouseAreasItem.class);
    }
    private QueryWrapper<WarehouseAreasItem> buildFilterQueryWrapper(PageParam<WarehouseAreasItem, BaseParam> pageParam) {
        QueryWrapper<WarehouseAreasItem> queryWrapper = pageParam.buildWrapper(true);
        FieldsUtils.setFieldsFilters(queryWrapper, pageParam, WarehouseAreasItem.class);
        return queryWrapper;
    }
    private QueryWrapper<WarehouseAreasItem> buildOutputQueryWrapper(ReportQueryRequest request) {
        List<Long> ids = request.getIds();
        PageParam<WarehouseAreasItem, BaseParam> pageParam = buildPageParam(request, ids.isEmpty());
        QueryWrapper<WarehouseAreasItem> queryWrapper = ids.isEmpty()
                ? buildFilterQueryWrapper(pageParam)
                : new QueryWrapper<>();
        if (!ids.isEmpty()) {
            queryWrapper.in("id", ids);
        }
        ListReportSupport.applyOrderBy(queryWrapper, pageParam.getWhere().getOrderBy());
        return queryWrapper;
    }
    private ListReportSupport<WarehouseAreasItem> createListReportSupport() {
        return new ListReportSupport<>(
                this::buildOutputQueryWrapper,
                new ListReportSupport.RecordLoader<>() {
                    @Override
                    public List<WarehouseAreasItem> list(QueryWrapper<WarehouseAreasItem> queryWrapper) {
                        return warehouseAreasItemService.listForOutput(queryWrapper);
                    }
                    @Override
                    public IPage<WarehouseAreasItem> page(Page<WarehouseAreasItem> page, QueryWrapper<WarehouseAreasItem> queryWrapper) {
                        return warehouseAreasItemService.pageForOutput(page, queryWrapper);
                    }
                }
        );
        ExcelUtil.build(ExcelUtil.create(warehouseAreasItemService.list(), WarehouseAreasItem.class), response);
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/WarehouseAreasItemService.java
@@ -3,7 +3,6 @@
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.vincent.rsf.server.common.domain.BaseParam;
import com.vincent.rsf.server.common.domain.PageParam;
@@ -17,10 +16,4 @@
    List<WarehouseAreasItem> getList();
    IPage<WarehouseAreasItem> pageByItemId(PageParam<WarehouseAreasItem, BaseParam> pageParam, QueryWrapper<WarehouseAreasItem> queryWrapper);
    List<WarehouseAreasItem> listForOutput(QueryWrapper<WarehouseAreasItem> queryWrapper);
    IPage<WarehouseAreasItem> pageForOutput(Page<WarehouseAreasItem> page, QueryWrapper<WarehouseAreasItem> queryWrapper);
    void fillExtendFields(List<WarehouseAreasItem> records);
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/WarehouseAreasItemServiceImpl.java
@@ -2,7 +2,6 @@
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vincent.rsf.server.common.domain.BaseParam;
import com.vincent.rsf.server.common.domain.PageParam;
import com.vincent.rsf.server.common.utils.FieldsUtils;
@@ -21,7 +20,12 @@
    @Override
    public List<WarehouseAreasItem> getList() {
        List<WarehouseAreasItem> areasItems = this.list();
        fillExtendFields(areasItems);
        for (WarehouseAreasItem areasItem : areasItems) {
            if (Objects.isNull(areasItem.getFieldsIndex())) {
                continue;
            }
            areasItem.setExtendFields(FieldsUtils.getFields(areasItem.getFieldsIndex()));
        }
        return areasItems;
    }
@@ -29,32 +33,5 @@
    public IPage<WarehouseAreasItem> pageByItemId(PageParam<WarehouseAreasItem, BaseParam> pageParam, QueryWrapper<WarehouseAreasItem> queryWrapper) {
        IPage<WarehouseAreasItem> itemIPage = this.baseMapper.pageByItemId(pageParam, queryWrapper);
        return itemIPage;
    }
    @Override
    public List<WarehouseAreasItem> listForOutput(QueryWrapper<WarehouseAreasItem> queryWrapper) {
        List<WarehouseAreasItem> records = this.list(queryWrapper);
        fillExtendFields(records);
        return records;
    }
    @Override
    public IPage<WarehouseAreasItem> pageForOutput(Page<WarehouseAreasItem> page, QueryWrapper<WarehouseAreasItem> queryWrapper) {
        IPage<WarehouseAreasItem> outputPage = this.page(page, queryWrapper);
        fillExtendFields(outputPage.getRecords());
        return outputPage;
    }
    @Override
    public void fillExtendFields(List<WarehouseAreasItem> records) {
        if (records == null || records.isEmpty()) {
            return;
        }
        for (WarehouseAreasItem record : records) {
            if (Objects.isNull(record.getFieldsIndex())) {
                continue;
            }
            record.setExtendFields(FieldsUtils.getFields(record.getFieldsIndex()));
        }
    }
}