💥 feat(模块): 添加了个很棒的功能

This commit is contained in:
Ylj 2025-03-16 16:46:38 +08:00
parent 9c4cbcec92
commit 230cbb8434
3 changed files with 438 additions and 3 deletions

View File

@ -0,0 +1,56 @@
/* 打印样式 */
@media print {
/* 隐藏不需要打印的元素 */
.ant-pro-card-header,
.ant-pro-table-search,
.ant-pro-table-list-toolbar,
.ant-pagination,
.ant-btn,
.ant-pro-table-list-toolbar-container {
display: none !important;
}
/* 调整表格样式 */
table {
width: 100%;
border-collapse: collapse;
}
th,
td {
border: 1px solid #000;
padding: 8px;
text-align: left;
}
/* 页面设置 */
@page {
margin: 1cm;
}
/* 确保内容不会被截断 */
.print-wrapper {
overflow: visible !important;
}
/* 处理分页 */
.page-break {
page-break-after: always;
}
/* 表格标题样式 */
.print-title {
font-size: 18px;
font-weight: bold;
text-align: center;
margin-bottom: 20px;
}
/* 页眉页脚样式 */
.print-header,
.print-footer {
margin: 20px 0;
white-space: pre-wrap;
}
}

View File

@ -1,12 +1,14 @@
import { ConnectState } from "@/models/global"; import { ConnectState } from "@/models/global";
import { ActionType, ProTable } from "@ant-design/pro-components"; import { ActionType, ProTable } from "@ant-design/pro-components";
import ProForm, { FormInstance, ProFormList, ProFormText } from "@ant-design/pro-form"; import ProForm, { FormInstance, ProFormList, ProFormText } from "@ant-design/pro-form";
import { Col, Row, Image, Button } from "antd"; import { Col, Row, Image, Button, Input, Modal } from "antd";
import moment from "moment"; import moment from "moment";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { connect } from "umi"; import { connect } from "umi";
import { handleGetExamineTypeTreeList } from "../../index/service"; import { handleGetExamineTypeTreeList } from "../../index/service";
import session from "@/utils/session"; import session from "@/utils/session";
import { TextAreaRef } from "antd/lib/input/TextArea";
import './printStyle.css';
type DetailProps = { type DetailProps = {
@ -19,8 +21,43 @@ const RecordDetail = ({ parentRow, show }: DetailProps) => {
const actionRef = useRef<ActionType>(); const actionRef = useRef<ActionType>();
const tableFormRef = useRef<FormInstance>(); const tableFormRef = useRef<FormInstance>();
// 表格数据
const [proTableData, setTableData] = useState<any>([])
const [formRes, setFormRes] = useState<any>() const [formRes, setFormRes] = useState<any>()
// 打印相关状态
const [printModalVisible, setPrintModalVisible] = useState<boolean>(false)
const [headerContent, setHeaderContent] = useState<string>('')
const [footerContent, setFooterContent] = useState<string>('')
const headerRef = useRef<TextAreaRef>(null)
const footerRef = useRef<TextAreaRef>(null)
const columns: any = [
{
title: "考核分类",
dataIndex: ""
},
{
title: "考核子类",
dataIndex: "title",
render: (_, record) => {
return record?.question.title ? record?.question.title : ""
}
},
{
title: "考核结果",
dataIndex: "title",
render: (_, record) => {
let str: string = ''
if (record.choiceResponse && record?.choiceResponse.length > 0) {
record.choiceResponse.forEach((item: any, index: number) => {
str += `${index > 0 ? '' : ''}答案${index + 1}${item}`
})
}
return str || ""
}
}
]
useEffect(() => { useEffect(() => {
if (show) { if (show) {
@ -40,6 +77,302 @@ const RecordDetail = ({ parentRow, show }: DetailProps) => {
} }
}, [show]) }, [show])
// 递归 只有当没有子集的时候 才会把问题的数组 到question 数组中
const handeGetTableData = async (resList: any, options: any) => {
// resList 需要判断是否有子集的数组
if (resList && resList.length > 0) {
resList.forEach((item: any) => {
if (item.children && item.children.length > 0) {
handeGetTableData(item.children, options)
} else {
if (options && options.length > 0) {
options.forEach((optionItem: any) => {
if (optionItem.question.categoryId === item.id) {
if (item.question && item.question.length > 0) {
item.question.push(optionItem)
} else {
item.question = [optionItem]
}
}
})
}
}
})
}
return resList
}
// 把需要打印的数组拿到一层中来
const handleGetTableRes = (list: any) => {
let res: any = [];
if (list && list.length > 0) {
list.forEach((item: any) => {
if (item.question && item.question.length > 0) {
// 如果当前项有question字段且不为空将其添加到结果数组
item.question.forEach((questionItem: any) => {
res.push(questionItem);
});
}
if (item.children && item.children.length > 0) {
// 如果有子项,递归处理子项并合并结果
const childResults = handleGetTableRes(item.children);
if (childResults && childResults.length > 0) {
res = [...res, ...childResults];
}
}
});
}
return res;
}
// 处理表格数据,为合并单元格做准备
const processTableDataForMerge = (data: any[]) => {
if (!data || data.length === 0) return [];
// 深拷贝数据,避免修改原始数据
const processedData = JSON.parse(JSON.stringify(data));
// 添加分类信息
processedData.forEach((item: any) => {
// 从categoryId获取分类名称
if (item.question && item.question.categoryId) {
// 这里需要根据实际情况获取分类名称
// 可以从缓存或其他地方获取
const categoryInfo = getCategoryInfo(item.question.categoryId);
item.categoryName = categoryInfo?.name || '';
item.parentCategoryName = categoryInfo?.parentName || '';
}
});
// 计算合并信息
let currentCategory = '';
let currentSubCategory = '';
let categorySpan = 0;
let subCategorySpan = 0;
processedData.forEach((item: any, index: number) => {
// 处理考核分类合并
if (item.parentCategoryName === currentCategory) {
categorySpan++;
item._categoryMerged = true; // 标记为已合并
} else {
// 更新前一个分类的合并信息
if (categorySpan > 0 && index > 0) {
processedData[index - categorySpan]._categoryRowSpan = categorySpan + 1;
}
currentCategory = item.parentCategoryName;
categorySpan = 0;
item._categoryRowSpan = 1; // 默认占一行
}
// 处理考核子类合并
if (item.categoryName === currentSubCategory) {
subCategorySpan++;
item._subCategoryMerged = true; // 标记为已合并
} else {
// 更新前一个子类的合并信息
if (subCategorySpan > 0 && index > 0) {
processedData[index - subCategorySpan]._subCategoryRowSpan = subCategorySpan + 1;
}
currentSubCategory = item.categoryName;
subCategorySpan = 0;
item._subCategoryRowSpan = 1; // 默认占一行
}
});
// 处理最后一组数据的合并信息
if (categorySpan > 0 && processedData.length > 0) {
const targetIndex = processedData.length - categorySpan - 1;
if (targetIndex >= 0 && targetIndex < processedData.length && processedData[targetIndex]) {
processedData[targetIndex]._categoryRowSpan = categorySpan + 1;
}
}
if (subCategorySpan > 0 && processedData.length > 0) {
const targetIndex = processedData.length - subCategorySpan - 1;
if (targetIndex >= 0 && targetIndex < processedData.length && processedData[targetIndex]) {
processedData[targetIndex]._subCategoryRowSpan = subCategorySpan + 1;
}
}
return processedData;
};
// 获取分类信息的辅助函数
const getCategoryInfo = (categoryId: number) => {
// 这里需要根据实际情况实现
// 可以从缓存或其他地方获取分类信息
// 示例实现
const categoriesTypeObj = session.get('categoriesTypeObj') || {};
const categoriesIdObj = session.get('categoriesIdObj') || {};
let parentName = '';
let name = '';
// 查找父分类
for (let key in categoriesIdObj) {
const list = categoriesIdObj[key];
if (list && list.length > 0 && list.indexOf(Number(categoryId)) !== -1) {
parentName = categoriesTypeObj[key] || '';
break;
}
}
// 获取当前分类名称
name = categoriesTypeObj[categoryId] || '';
return { name, parentName };
};
// 打印表格方法
const handlePrintTable = () => {
// 创建打印内容
const printWindow = window.open('', '_blank');
if (!printWindow) {
Modal.error({ title: '打印失败', content: '无法创建打印窗口,请检查浏览器设置。' });
return;
}
// 获取表格数据
const tableData = proTableData || [];
// 构建HTML内容
let printContent = `
<html>
<head>
<title></title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.print-header, .print-footer { margin: 20px 0; white-space: pre-wrap; }
table { width: 100%; border-collapse: collapse; margin: 20px 0; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
.info-section { margin-bottom: 20px; }
.info-item { margin-bottom: 10px; }
.info-label { font-weight: bold; display: inline-block; width: 100px; }
.image-container { display: flex; flex-wrap: wrap; margin-top: 10px; }
.image-item { margin-right: 10px; margin-bottom: 10px; }
@media print {
button { display: none; }
}
</style>
</head>
<body>
`;
// 添加自定义页眉
if (headerContent) {
printContent += `<div class="print-header">${headerContent}</div>`;
}
// 添加基本信息
printContent += `
<div class="info-section">
<div class="info-item"><span class="info-label">:</span> ${formRes?.serverPartName || ''}</div>
<div class="info-item"><span class="info-label">:</span> ${formRes?.placeName || ''}</div>
<div class="info-item"><span class="info-label">:</span> ${formRes?.uploadResult || ''}</div>
<div class="info-item"><span class="info-label">:</span> ${formRes?.userName || ''}</div>
<div class="info-item"><span class="info-label">:</span> ${formRes?.submittedAt || ''}</div>
</div>
`;
// 添加图片信息
if (formRes?.imgsList && formRes.imgsList.length > 0) {
printContent += `
<div class="info-section">
<div class="info-label">:</div>
<div class="image-container">
`;
formRes.imgsList.forEach((item: string) => {
printContent += `<div class="image-item"><img src="${item}" style="width: 150px; height: 150px;" /></div>`;
});
printContent += `
</div>
</div>
`;
}
// 添加表格
printContent += `
<table>
<thead>
<tr>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
`;
// 添加表格数据行
tableData.forEach((record: any) => {
printContent += '<tr>';
// 考核分类列 - 处理合并单元格
if (record._categoryMerged) {
// 如果已合并,不显示单元格
} else {
printContent += `<td ${record._categoryRowSpan && record._categoryRowSpan > 1 ? `rowspan="${record._categoryRowSpan}"` : ''}>${record.parentCategoryName || ''}</td>`;
}
// 考核子类列 - 处理合并单元格
if (record._subCategoryMerged) {
// 如果已合并,不显示单元格
} else {
printContent += `<td ${record._subCategoryRowSpan && record._subCategoryRowSpan > 1 ? `rowspan="${record._subCategoryRowSpan}"` : ''}>${record.question?.title || ''}</td>`;
}
// 考核结果列
let resultStr = '';
if (record.choiceResponse && record.choiceResponse.length > 0) {
record.choiceResponse.forEach((item: any, index: number) => {
resultStr += `${index > 0 ? '' : ''}答案${index + 1}${item}`;
});
}
printContent += `<td>${resultStr || ''}</td>`;
printContent += '</tr>';
});
printContent += `
</tbody>
</table>
`;
// 添加自定义页脚
if (footerContent) {
printContent += `<div class="print-footer">${footerContent}</div>`;
}
// 添加打印按钮
printContent += `
<div style="text-align: center; margin-top: 20px;">
<button onclick="window.print();" style="padding: 8px 16px;"></button>
<button onclick="window.close();" style="padding: 8px 16px; margin-left: 10px;"></button>
</div>
`;
printContent += `
</body>
</html>
`;
// 写入打印窗口并打印
printWindow.document.open();
printWindow.document.write(printContent);
printWindow.document.close();
// 等待图片加载完成后打印
setTimeout(() => {
printWindow.focus();
// 自动打印可以取消注释下面的代码
// printWindow.print();
}, 500);
};
return ( return (
<div> <div>
<ProForm <ProForm
@ -117,9 +450,11 @@ const RecordDetail = ({ parentRow, show }: DetailProps) => {
actionRef={actionRef} actionRef={actionRef}
formRef={tableFormRef} formRef={tableFormRef}
search={false} search={false}
columns={columns}
toolbar={{ toolbar={{
actions: [ actions: [
<Button type="primary" onClick={(e) => { <Button type="primary" onClick={(e) => {
setPrintModalVisible(true)
}}> }}>
</Button> </Button>
@ -143,6 +478,19 @@ const RecordDetail = ({ parentRow, show }: DetailProps) => {
}) })
} }
let tableData = await handeGetTableData(typeData, res)
console.log('tableData', tableData);
// 拿到整个数据之后 递归取出tableData中有 question 数据的那一层数据变为一个数组
let tableRes = await handleGetTableRes(tableData)
console.log('tableRes', tableRes);
// 处理表格数据,为合并单元格做准备
let processedData = processTableDataForMerge(tableRes);
setTableData(processedData)
if (processedData && processedData.length > 0) {
return { data: processedData, success: true }
}
return []
// let categoriesObj: any = {} // 子父级关系的缓存对象 // let categoriesObj: any = {} // 子父级关系的缓存对象
@ -198,11 +546,42 @@ const RecordDetail = ({ parentRow, show }: DetailProps) => {
}} }}
/> />
<Modal
title="打印设置"
open={printModalVisible}
onOk={() => {
handlePrintTable();
setPrintModalVisible(false);
}}
onCancel={() => setPrintModalVisible(false)}
width={600}
>
<div style={{ marginBottom: 16 }}>
<div style={{ marginBottom: 8 }}></div>
<Input.TextArea
ref={headerRef}
rows={4}
value={headerContent}
onChange={(e) => setHeaderContent(e.target.value)}
placeholder="请输入要在打印页面顶部显示的内容"
/>
</div>
<div>
<div style={{ marginBottom: 8 }}></div>
<Input.TextArea
ref={footerRef}
rows={4}
value={footerContent}
onChange={(e) => setFooterContent(e.target.value)}
placeholder="请输入要在打印页面底部显示的内容"
/>
</div>
</Modal>
</div> </div>
) )
} }
export default connect(({ user }: ConnectState) => ({ export default connect(({ user }: ConnectState) => ({
currentUser: user.data currentUser: user.data
}))(RecordDetail); }))(RecordDetail);

View File

@ -32,7 +32,7 @@ export async function retrieveUserAuthority(params: any) {
//获取菜单数据 //获取菜单数据
export async function retrieveMenuData(params: any) { export async function retrieveMenuData(params: any) {
const data = await request.get('/menus', params) // const data = await request.get('/menus', params)
// return data // return data
return [ return [
{ {