优化excel导出

master
LiuJiaNan 2025-12-30 15:42:47 +08:00
parent 14aa36fb66
commit 85d7346394
3 changed files with 289 additions and 257 deletions

View File

@ -31,7 +31,7 @@
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-to-print": "^3.2.0", "react-to-print": "^3.2.0",
"zy-react-library": "^1.1.10" "zy-react-library": "^1.1.12"
}, },
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "^5.4.1", "@antfu/eslint-config": "^5.4.1",

View File

@ -1,8 +1,8 @@
import { Permission } from "@cqsjjb/jjb-common-decorator/permission"; import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
import { Connect } from "@cqsjjb/jjb-dva-runtime"; import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Button, Form, message, Modal, Space, Spin } from "antd"; import { Button, Checkbox, Form, message, Modal, Space } from "antd";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { useEffect, useRef, useState } from "react"; import { useEffect, useMemo, useRef, useState } from "react";
import { useReactToPrint } from "react-to-print"; import { useReactToPrint } from "react-to-print";
import FormBuilder from "zy-react-library/components/FormBuilder"; import FormBuilder from "zy-react-library/components/FormBuilder";
import AddIcon from "zy-react-library/components/Icon/AddIcon"; import AddIcon from "zy-react-library/components/Icon/AddIcon";
@ -18,7 +18,7 @@ import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
import { HIDDEN_RECTIFICATION_TYPE_ENUM, HIDDEN_SOURCE_ENUM, HIDDEN_STATE_ENUM } from "zy-react-library/enum/hidden/gwj"; import { HIDDEN_RECTIFICATION_TYPE_ENUM, HIDDEN_SOURCE_ENUM, HIDDEN_STATE_ENUM } from "zy-react-library/enum/hidden/gwj";
import useDownloadBlob from "zy-react-library/hooks/useDownloadBlob"; import useDownloadBlob from "zy-react-library/hooks/useDownloadBlob";
import useTable from "zy-react-library/hooks/useTable"; import useTable from "zy-react-library/hooks/useTable";
import { getLabelName } from "zy-react-library/utils"; import { getLabelName, getUnmatchedItems } from "zy-react-library/utils";
import { IS_RELATED_ENUM } from "~/enumerate/constant"; import { IS_RELATED_ENUM } from "~/enumerate/constant";
import { NS_LEDGER } from "~/enumerate/namespace"; import { NS_LEDGER } from "~/enumerate/namespace";
import "./index.less"; import "./index.less";
@ -28,7 +28,6 @@ function List(props) {
const [selectedRowKeys, setSelectedRowKeys] = useState([]); const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [exportByColumnModalOpen, setExportByColumnModalOpen] = useState(false); const [exportByColumnModalOpen, setExportByColumnModalOpen] = useState(false);
const [printModalOpen, setPrintModalOpen] = useState(false); const [printModalOpen, setPrintModalOpen] = useState(false);
const { loading: downloadBlobLoading, downloadBlob } = useDownloadBlob();
const { tableProps, getData } = useTable(props["ledgerList"], { const { tableProps, getData } = useTable(props["ledgerList"], {
form, form,
transform: formData => ({ transform: formData => ({
@ -51,254 +50,210 @@ function List(props) {
}); });
}; };
const onExportExcel = async () => {
const hiddenFindTime = form.getFieldValue("hiddenFindTime");
if (!hiddenFindTime) {
message.error("请选择隐患发现时间");
return;
}
if (hiddenFindTime.filter(Boolean).length === 0) {
message.error("请选择隐患发现时间");
return;
}
Modal.confirm({
title: "导出确认",
content: "确定要导出excel吗",
onOk: async () => {
await downloadBlob("/hidden/hidden/exportHidden", {
params: { hiddenFindTime: hiddenFindTime[0], hiddenFindTimeLe: hiddenFindTime[1] },
});
message.success("导出成功");
},
});
};
return ( return (
<Page isShowAllAction={false}> <Page isShowAllAction={false}>
<Spin spinning={downloadBlobLoading}> <Search
<Search options={[
options={[ { name: "source", label: "隐患来源", render: FORM_ITEM_RENDER_ENUM.SELECT, items: HIDDEN_SOURCE_ENUM },
{ name: "source", label: "隐患来源", render: FORM_ITEM_RENDER_ENUM.SELECT, items: HIDDEN_SOURCE_ENUM }, { name: "hiddenDesc", label: "隐患描述" },
{ name: "hiddenDesc", label: "隐患描述" }, { name: "hiddenFindTime", label: "隐患发现时间", render: FORM_ITEM_RENDER_ENUM.DATE_RANGE },
{ name: "hiddenFindTime", label: "隐患发现时间", render: FORM_ITEM_RENDER_ENUM.DATE_RANGE }, { name: "hiddenFindDept", label: "隐患发现部门", render: <DepartmentSelectTree /> },
{ name: "hiddenFindDept", label: "隐患发现部门", render: <DepartmentSelectTree /> }, {
{ name: "hiddenType",
name: "hiddenType", label: "隐患类型",
label: "隐患类型", render: <DictionarySelectTree dictValue="hiddenType" onlyLastLevel />,
render: <DictionarySelectTree dictValue="hiddenType" onlyLastLevel />, },
}, {
{ name: "hiddenLevel",
name: "hiddenLevel", label: "隐患级别",
label: "隐患级别", render: (
render: ( <HiddenLevelSelectTree isShowLarger={false} isShowMajor={false} />
<HiddenLevelSelectTree isShowLarger={false} isShowMajor={false} /> ),
), },
}, { name: "creatorName", label: "隐患发现人" },
{ name: "creatorName", label: "隐患发现人" }, {
{ name: "state",
name: "state", label: "隐患状态",
label: "隐患状态", render: FORM_ITEM_RENDER_ENUM.SELECT,
render: FORM_ITEM_RENDER_ENUM.SELECT, items: getUnmatchedItems({ list: HIDDEN_STATE_ENUM, value: ["98", "102"] }),
items: HIDDEN_STATE_ENUM.filter(item => !["98", "102"].includes(item.bianma)), },
}, { name: "confirmUserName", label: "确认人" },
{ name: "confirmUserName", label: "确认人" }, { name: "rectificationUserName", label: "整改人" },
{ name: "rectificationUserName", label: "整改人" }, { name: "rectificationDeptId", label: "整改部门", render: <DepartmentSelectTree /> },
{ name: "rectificationDeptId", label: "整改部门", render: <DepartmentSelectTree /> }, { name: "checkUserName", label: "验收人" },
{ name: "checkUserName", label: "验收人" }, {
{ name: "isRelated",
name: "isRelated", label: "是否相关方",
label: "是否相关方", render: FORM_ITEM_RENDER_ENUM.SELECT,
render: FORM_ITEM_RENDER_ENUM.SELECT, items: IS_RELATED_ENUM,
items: IS_RELATED_ENUM, },
}, {
{ name: "isAi",
name: "isAi", label: "是否使用AI",
label: "是否使用AI", render: FORM_ITEM_RENDER_ENUM.SELECT,
render: FORM_ITEM_RENDER_ENUM.SELECT, items: [{ bianma: "1", name: "是" }, { bianma: "0", name: "否" }],
items: [{ bianma: "1", name: "是" }, { bianma: "0", name: "否" }], },
}, ]}
]} form={form}
form={form} onFinish={getData}
onFinish={getData} />
/> <Table
<Table rowSelection={{
rowSelection={{ preserveSelectedRowKeys: true,
preserveSelectedRowKeys: true, selectedRowKeys,
selectedRowKeys, onChange: (selectedRowKeys) => {
onChange: (selectedRowKeys) => { setSelectedRowKeys(selectedRowKeys);
setSelectedRowKeys(selectedRowKeys); },
}, }}
}} toolBarRender={() => (
toolBarRender={() => ( <>
<> {props.permission("fgs-tz-add") && (
{props.permission("fgs-tz-add") && ( <Button
<Button type="primary"
type="primary" icon={<AddIcon />}
icon={<AddIcon />} onClick={() => {
onClick={() => { props.history.push("./add");
props.history.push("./add"); }}
}} >
> 新增
新增 </Button>
</Button> )}
)} {props.permission("fgs-tz-dy") && (
{props.permission("fgs-tz-dy") && ( <Button
<Button type="primary"
type="primary" icon={<PrintIcon />}
icon={<PrintIcon />} ghost
ghost onClick={() => {
onClick={() => { if (selectedRowKeys.length === 0) {
if (selectedRowKeys.length === 0) { message.error("请选中要打印的数据");
message.error("请选中要打印的数据"); return;
return;
}
setPrintModalOpen(true);
}}
>
打印
</Button>
)}
{props.permission("fgs-tz-dc") && (
<Button
type="primary"
icon={<ExportIcon />}
ghost
onClick={() => {
onExportExcel();
}}
>
导出
</Button>
)}
{props.permission("fgs-tz-aldc") && (
<Button
type="primary"
icon={<ExportIcon />}
ghost
onClick={() => {
const hiddenFindTime = form.getFieldValue("hiddenFindTime");
if (!hiddenFindTime) {
message.error("请选择隐患发现时间");
return;
}
if (hiddenFindTime.filter(Boolean).length === 0) {
message.error("请选择隐患发现时间");
return;
}
setExportByColumnModalOpen(true);
}}
>
按列导出
</Button>
)}
</>
)}
columns={[
{
title: "隐患来源",
dataIndex: "source",
render: (_, record) => getLabelName({ list: HIDDEN_SOURCE_ENUM, status: record.source }),
},
{ title: "隐患描述", dataIndex: "hiddenDesc" },
{ title: "隐患级别", dataIndex: "hiddenLevelName", width: 100 },
{ title: "隐患类型", dataIndex: "hiddenTypeName" },
{ title: "隐患发现部门", dataIndex: "hiddenFindDeptName", width: 180 },
{ title: "隐患发现人", dataIndex: "createName", width: 130 },
{
title: "隐患发现时间",
dataIndex: "hiddenFindTime",
width: 180,
render: (_, record) => record.hiddenFindTime ? dayjs(record.hiddenFindTime).format("YYYY-MM-DD HH:mm:ss") : "",
},
{
title: "整改类型",
dataIndex: "rectificationType",
width: 100,
render: (_, record) => getLabelName({
list: HIDDEN_RECTIFICATION_TYPE_ENUM,
status: record.rectificationType,
}),
},
{ title: "确认人", dataIndex: "confirmUserName", width: 100 },
{ title: "整改人", dataIndex: "rectifyUserName", width: 100 },
{
title: "整改时间",
dataIndex: "rectificationTime",
width: 180,
render: (_, record) => record.rectificationTime ? dayjs(record.rectificationTime).format("YYYY-MM-DD HH:mm:ss") : "",
},
{ title: "验收人", dataIndex: "hiddenYUserName", width: 100 },
{
title: "是否相关方",
dataIndex: "isRelated",
width: 150,
render: (_, record) => getLabelName({
list: IS_RELATED_ENUM,
status: record.isRelated,
}),
},
{
title: "隐患状态",
dataIndex: "state",
render: (_, record) => getLabelName({ list: HIDDEN_STATE_ENUM, status: record.state }),
},
{
title: "操作",
width: 220,
fixed: "right",
render: (_, record) => (
<Space>
<Button
type="link"
onClick={() => {
props.history.push(`../HiddenView?id=${record.id}&hiddenId=${record.hiddenId}`);
}}
>
查看
</Button>
{
(props.permission("fgs-tz-bj") && record.state === 201) && (
<Button
type="link"
onClick={() => {
props.history.push(`./add?id=${record.id}&hiddenId=${record.hiddenId}`);
}}
>
编辑
</Button>
)
} }
{ setPrintModalOpen(true);
(props.permission("fgs-tz-sc") && record.state === 100) && ( }}
<Button type="link" danger onClick={() => onDelete(record.id)}>删除</Button> >
) 打印
} </Button>
{props.permission("fgs-tz-gcjl") && ( )}
{props.permission("fgs-tz-aldc") && (
<Button
type="primary"
icon={<ExportIcon />}
ghost
onClick={() => {
setExportByColumnModalOpen(true);
}}
>
导出
</Button>
)}
</>
)}
columns={[
{
title: "隐患来源",
dataIndex: "source",
render: (_, record) => getLabelName({ list: HIDDEN_SOURCE_ENUM, status: record.source }),
},
{ title: "隐患描述", dataIndex: "hiddenDesc" },
{ title: "隐患级别", dataIndex: "hiddenLevelName", width: 100 },
{ title: "隐患类型", dataIndex: "hiddenTypeName" },
{ title: "隐患发现部门", dataIndex: "hiddenFindDeptName", width: 180 },
{ title: "隐患发现人", dataIndex: "createName", width: 130 },
{
title: "隐患发现时间",
dataIndex: "hiddenFindTime",
width: 180,
render: (_, record) => record.hiddenFindTime ? dayjs(record.hiddenFindTime).format("YYYY-MM-DD HH:mm:ss") : "",
},
{
title: "整改类型",
dataIndex: "rectificationType",
width: 100,
render: (_, record) => getLabelName({
list: HIDDEN_RECTIFICATION_TYPE_ENUM,
status: record.rectificationType,
}),
},
{ title: "确认人", dataIndex: "confirmUserName", width: 100 },
{ title: "整改人", dataIndex: "rectifyUserName", width: 100 },
{
title: "整改时间",
dataIndex: "rectificationTime",
width: 180,
render: (_, record) => record.rectificationTime ? dayjs(record.rectificationTime).format("YYYY-MM-DD HH:mm:ss") : "",
},
{ title: "验收人", dataIndex: "hiddenYUserName", width: 100 },
{
title: "是否相关方",
dataIndex: "isRelated",
width: 150,
render: (_, record) => getLabelName({
list: IS_RELATED_ENUM,
status: record.isRelated,
}),
},
{
title: "隐患状态",
dataIndex: "state",
render: (_, record) => getLabelName({ list: HIDDEN_STATE_ENUM, status: record.state }),
},
{
title: "操作",
width: 220,
fixed: "right",
render: (_, record) => (
<Space>
<Button
type="link"
onClick={() => {
props.history.push(`../HiddenView?id=${record.id}&hiddenId=${record.hiddenId}`);
}}
>
查看
</Button>
{
(props.permission("fgs-tz-bj") && record.state === 201) && (
<Button <Button
type="link" type="link"
onClick={() => { onClick={() => {
props.history.push(`../HiddenView?id=${record.id}&hiddenId=${record.hiddenId}&history=1`); props.history.push(`./add?id=${record.id}&hiddenId=${record.hiddenId}`);
}} }}
> >
过程记录 编辑
</Button> </Button>
)} )
</Space> }
), {
}, (props.permission("fgs-tz-sc") && record.state === 100) && (
]} <Button type="link" danger onClick={() => onDelete(record.id)}>删除</Button>
{...tableProps} )
/> }
</Spin> {props.permission("fgs-tz-gcjl") && (
<Button
type="link"
onClick={() => {
props.history.push(`../HiddenView?id=${record.id}&hiddenId=${record.hiddenId}&history=1`);
}}
>
过程记录
</Button>
)}
</Space>
),
},
]}
{...tableProps}
/>
{exportByColumnModalOpen && ( {exportByColumnModalOpen && (
<ExportByColumnModal <ExportByColumnModal
hiddenFindTime={form.getFieldValue("hiddenFindTime")} hiddenFindTime={form.getFieldValue("hiddenFindTime")}
selectedRowKeys={selectedRowKeys}
onCancel={() => setExportByColumnModalOpen(false)} onCancel={() => setExportByColumnModalOpen(false)}
/> />
)} )}
{printModalOpen && ( {printModalOpen && (
<PrintModal <PrintModal
data={selectedRowKeys} selectedRowKeys={selectedRowKeys}
onCancel={() => setPrintModalOpen(false)} onCancel={() => setPrintModalOpen(false)}
/> />
)} )}
@ -308,32 +263,89 @@ function List(props) {
const ExportByColumnModalComponent = (props) => { const ExportByColumnModalComponent = (props) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const exportFields = Form.useWatch("exportFields", form);
const { loading, downloadBlob } = useDownloadBlob(); const { loading, downloadBlob } = useDownloadBlob();
const [items, setItems] = useState([]); const [items, setItems] = useState([]);
const indeterminate = useMemo(
() => {
if (!exportFields)
return false;
return exportFields.length > 0 && exportFields.length < items.length;
},
[exportFields],
);
const getExportColumn = async () => { const getExportColumn = async () => {
const { data } = await props["hiddenExportColumn"](); const { data } = await props["hiddenExportColumn"]();
setItems(data.map(item => ({ bianma: item, name: item }))); setItems(data.map(item => ({ bianma: item, name: item })));
const defaultExportFields = data.filter(item => !item.includes("图片"));
form.setFieldsValue({ exportFields: [...defaultExportFields] });
}; };
useEffect(() => { useEffect(() => {
getExportColumn(); getExportColumn();
}, []); }, []);
const onSubmit = async (values) => { const onSubmit = async (values) => {
Modal.confirm({ const hiddenFindTime = props.hiddenFindTime;
title: "导出确认", const selectedRowKeys = props.selectedRowKeys;
content: "确定要导出excel吗",
onOk: async () => { // 检查导出字段是否包含"图片"
await downloadBlob("/hidden/hidden/exportHidden", { const hasPictureField = values.exportFields && values.exportFields.some(field => field.includes("图片"));
params: { hiddenFindTime: props.hiddenFindTime[0], hiddenFindTimeLe: props.hiddenFindTime[1], ...values },
}); if (hasPictureField) {
message.success("导出成功"); // 包含图片字段的验证逻辑
props.onCancel(); if (!selectedRowKeys || selectedRowKeys.length === 0) {
}, message.error("请选择要导出的数据");
}); return;
}
if (selectedRowKeys.length > 10) {
message.error("选择的数据超过10条请重新选择");
return;
}
// 执行导出
Modal.confirm({
title: "导出确认",
content: "确定要导出excel吗",
onOk: async () => {
await downloadBlob("/hidden/hidden/exportHidden", {
params: { ids: props.selectedRowKeys.join(","), ...values },
});
message.success("导出成功");
props.onCancel();
},
});
}
else {
// 不包含图片字段的验证逻辑
if (!hiddenFindTime || hiddenFindTime.length === 0) {
message.error("请选择隐患发现时间");
return;
}
// 执行导出
Modal.confirm({
title: "导出确认",
content: "确定要导出excel吗",
onOk: async () => {
await downloadBlob("/hidden/hidden/exportHidden", {
params: { hiddenFindTime: hiddenFindTime[0], hiddenFindTimeLe: hiddenFindTime[1], ...values },
});
message.success("导出成功");
props.onCancel();
},
});
}
}; };
return ( return (
<Modal <Modal
title="按列导出" title="导出"
width={600} width={800}
open open
maskClosable={false} maskClosable={false}
onCancel={props.onCancel} onCancel={props.onCancel}
@ -344,18 +356,38 @@ const ExportByColumnModalComponent = (props) => {
loading={loading} loading={loading}
form={form} form={form}
span={24} span={24}
labelCol={{ span: 8 }} labelCol={{ span: 6 }}
showActionButtons={false} showActionButtons={false}
onFinish={onSubmit} onFinish={onSubmit}
options={[ options={[
{
key: "indeterminate",
label: "",
render: (
<Checkbox
indeterminate={indeterminate}
onChange={(e) => {
const checked = e.target.checked;
if (checked) {
form.setFieldsValue({ exportFields: items.map(item => item.bianma) });
}
else {
form.setFieldsValue({ exportFields: [] });
}
}}
checked={items.length === (exportFields || []).length}
>
全选为保障导出效率导出带图片的excel最多10条
</Checkbox>
),
required: false,
},
{ {
name: "exportFields", name: "exportFields",
label: "导出内容", label: "导出内容",
render: FORM_ITEM_RENDER_ENUM.SELECT, render: FORM_ITEM_RENDER_ENUM.CHECKBOX,
items, items,
componentProps: { checkboxCol: 6,
mode: "multiple",
},
}, },
]} ]}
/> />
@ -384,7 +416,7 @@ const PrintModalComponent = (props) => {
const getData = async () => { const getData = async () => {
const { data } = await props["hiddenPrintList"]({ const { data } = await props["hiddenPrintList"]({
ids: props.data.join(","), ids: props.selectedRowKeys.join(","),
}); });
setList(data); setList(data);
}; };

View File

@ -17,7 +17,7 @@ import { HIDDEN_RECTIFICATION_TYPE_ENUM, HIDDEN_SOURCE_ENUM, HIDDEN_STATE_ENUM }
import useDownloadBlob from "zy-react-library/hooks/useDownloadBlob"; import useDownloadBlob from "zy-react-library/hooks/useDownloadBlob";
import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery"; import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
import useTable from "zy-react-library/hooks/useTable"; import useTable from "zy-react-library/hooks/useTable";
import { getLabelName } from "zy-react-library/utils"; import { getLabelName, getUnmatchedItems } from "zy-react-library/utils";
import { IS_RELATED_ENUM } from "~/enumerate/constant"; import { IS_RELATED_ENUM } from "~/enumerate/constant";
import { NS_AVERAGE } from "~/enumerate/namespace"; import { NS_AVERAGE } from "~/enumerate/namespace";
import "../../../../BranchCompany/Average/Ledger/List/index.less"; import "../../../../BranchCompany/Average/Ledger/List/index.less";
@ -86,7 +86,7 @@ function HiddenList(props) {
name: "state", name: "state",
label: "隐患状态", label: "隐患状态",
render: FORM_ITEM_RENDER_ENUM.SELECT, render: FORM_ITEM_RENDER_ENUM.SELECT,
items: HIDDEN_STATE_ENUM.filter(item => !["98", "102"].includes(item.bianma)), items: getUnmatchedItems({ list: HIDDEN_STATE_ENUM, value: ["98", "102"] }),
}, },
{ name: "confirmUserName", label: "确认人" }, { name: "confirmUserName", label: "确认人" },
{ name: "rectificationUserName", label: "整改人" }, { name: "rectificationUserName", label: "整改人" },