Compare commits
11 Commits
2984cb5c7a
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 787648827c | |||
| d226e9d5b1 | |||
| f40170207a | |||
| 0b6fac8161 | |||
| fe309da1e5 | |||
| e8f47684fb | |||
| 2db0932f22 | |||
| 7bc3a28b6c | |||
| faf44eb8da | |||
| ad59aaef2d | |||
| 7440c3d980 |
4
.env.development
Normal file
4
.env.development
Normal file
@ -0,0 +1,4 @@
|
||||
# 本地后端地址
|
||||
REACT_APP_BACKEND_ADDRESS=http://localhost:8080
|
||||
# 超时时间
|
||||
REACT_APP_BACKEND_TIMEOUT=10000
|
||||
4
.env.production
Normal file
4
.env.production
Normal file
@ -0,0 +1,4 @@
|
||||
# 远程后端地址
|
||||
REACT_APP_BACKEND_ADDRESS=http://43.138.83.20:10001
|
||||
# 超时时间
|
||||
REACT_APP_BACKEND_TIMEOUT=10000
|
||||
@ -1,3 +1,3 @@
|
||||
window.BACKEND_ADDRESS = "http://localhost:8080";
|
||||
//window.BACKEND_ADDRESS = "http://43.138.83.20:10001";
|
||||
//window.BACKEND_ADDRESS = "http://localhost:8080";
|
||||
window.BACKEND_ADDRESS = "http://43.138.83.20:10001";
|
||||
window.BACKEND_TIMEOUT = 10000;
|
||||
@ -1,7 +1,10 @@
|
||||
const baseWebConfig ={
|
||||
baseUrl: 'http://localhost:8080',
|
||||
//baseUrl: 'http://43.138.83.20:10001',
|
||||
timeout: 10000,
|
||||
}
|
||||
|
||||
export default baseWebConfig;
|
||||
// baseWebConfig.js
|
||||
const baseWebConfig = {
|
||||
// 从环境变量读取baseUrl(本地开发用localhost,build用ip:10001)
|
||||
baseUrl: process.env.REACT_APP_BACKEND_ADDRESS,
|
||||
// 读取超时时间(转成数字类型)
|
||||
timeout: Number(process.env.REACT_APP_BACKEND_TIMEOUT)
|
||||
};
|
||||
console.log('当前环境 baseUrl:', baseWebConfig.baseUrl);
|
||||
console.log('当前超时时间:', baseWebConfig.timeout);
|
||||
export default baseWebConfig;
|
||||
158
src/page/Dashboard/DataManager/AddDataManageDrawer.jsx
Normal file
158
src/page/Dashboard/DataManager/AddDataManageDrawer.jsx
Normal file
@ -0,0 +1,158 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, Drawer, Flex, Form, Input, Select, Typography } from "antd";
|
||||
import CourseTypeTag from "../../../component/Workload/CourseTypeTag";
|
||||
|
||||
const AddDataManageDrawer = props => {
|
||||
const { open, setOpen, commonAxios, fetchWorkload, messageApi } = props;
|
||||
|
||||
// 表单布局配置
|
||||
const formLayout = {
|
||||
labelCol: { span: 5 },
|
||||
wrapperCol: { span: 20 },
|
||||
};
|
||||
|
||||
const [form] = Form.useForm();
|
||||
const { Title } = Typography;
|
||||
|
||||
// 课程性质选项
|
||||
const courseNatureOptions = [
|
||||
{ label: '公共课', value: '01' },
|
||||
{ label: '专业课', value: '02' },
|
||||
{ label: '校选课', value: '03' },
|
||||
];
|
||||
|
||||
// 当抽屉关闭时重置表单
|
||||
React.useEffect(() => {
|
||||
if (!open) {
|
||||
form.resetFields();
|
||||
}
|
||||
}, [open, form]);
|
||||
|
||||
// 提交添加表单
|
||||
const onSubmit = (values) => {
|
||||
commonAxios.post('/api/v1/workload/addWorkload', values).then(response => {
|
||||
const result = response.data.data || false;
|
||||
if (result) {
|
||||
messageApi.success('添加工作量信息成功');
|
||||
setOpen(false);
|
||||
fetchWorkload(); // 刷新列表
|
||||
} else {
|
||||
messageApi.error('添加工作量信息失败');
|
||||
}
|
||||
}).catch(error => {
|
||||
messageApi.error('网络错误,添加失败');
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
title={'添加工作量'}
|
||||
destroyOnClose
|
||||
>
|
||||
<div>
|
||||
<Title level={5}>添加工作量信息</Title>
|
||||
<Form
|
||||
form={form}
|
||||
{...formLayout}
|
||||
onFinish={onSubmit}
|
||||
>
|
||||
<Form.Item
|
||||
label="学期"
|
||||
name="semesterInfo"
|
||||
rules={[{ required: true, message: '请输入学期' }]}
|
||||
>
|
||||
<Input placeholder="请输入学期(示例:2023-2024-1)"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="授课名称"
|
||||
name="courseName"
|
||||
rules={[{ required: true, message: '请输入授课名称' }]}
|
||||
>
|
||||
<Input placeholder="请输入授课名称"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="姓名"
|
||||
name="teacherName"
|
||||
rules={[{ required: true, message: '请输入姓名' }]}
|
||||
>
|
||||
<Input placeholder="请输入姓名"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="工号"
|
||||
name="stuffNumber"
|
||||
rules={[{ required: true, message: '请输入工号' }]}
|
||||
>
|
||||
<Input placeholder="请输入工号"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="职称"
|
||||
name="jobTitle"
|
||||
rules={[{ required: true, message: '请输入职称' }]}
|
||||
>
|
||||
<Input placeholder="请输入职称"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="课程性质"
|
||||
name="courseNature"
|
||||
rules={[{ required: true, message: '请选择课程性质' }]}
|
||||
>
|
||||
<Select
|
||||
placeholder="请选择课程性质"
|
||||
options={courseNatureOptions}
|
||||
formatLabel={(option) => <CourseTypeTag courseNature={option.value} />}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="授课专业"
|
||||
name="teachingMajor"
|
||||
rules={[{ required: true, message: '请输入授课专业' }]}
|
||||
>
|
||||
<Input placeholder="请输入授课专业"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="学生数"
|
||||
name="actualClassSize"
|
||||
rules={[
|
||||
{ required: true, message: '请输入学生数' }
|
||||
]}
|
||||
>
|
||||
<Input type="number" placeholder="请输入学生数"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="授课对象"
|
||||
name="teachingGrade"
|
||||
rules={[{ required: true, message: '请输入授课对象' }]}
|
||||
>
|
||||
<Input placeholder="请输入授课对象"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="工作量"
|
||||
name="totalClassHours"
|
||||
rules={[
|
||||
{ required: true, message: '请输入工作量' }
|
||||
]}
|
||||
>
|
||||
<Input type="number" placeholder="请输入工作量"/>
|
||||
</Form.Item>
|
||||
<Flex justify={"center"} align={"center"}>
|
||||
<Button onClick={() => setOpen(false)} style={{ marginRight: 8 }}>取消</Button>
|
||||
<Button htmlType={'submit'} type={'primary'}>添加</Button>
|
||||
</Flex>
|
||||
</Form>
|
||||
</div>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
AddDataManageDrawer.propTypes = {
|
||||
open: PropTypes.bool.isRequired,
|
||||
setOpen: PropTypes.func.isRequired,
|
||||
commonAxios: PropTypes.func.isRequired,
|
||||
fetchWorkload: PropTypes.func.isRequired,
|
||||
messageApi: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default AddDataManageDrawer;
|
||||
@ -2,7 +2,9 @@ import React, {useState} from 'react';
|
||||
import {Button, Flex, message, Popconfirm, Table, Typography} from "antd";
|
||||
import ManageTableColumn from "./ManageTableColumn";
|
||||
import ImportDataDrawer from "./ImportDataDrawer";
|
||||
import EditDataManageDrawer from './EditDataManageDrawer';
|
||||
import creatMessageCommonAxios from "../../../http/CreatMessageCommonAxios";
|
||||
import AddDataManageDrawer from './AddDataManageDrawer'; // 导入新增的组件
|
||||
|
||||
const DataManageTable = props => {
|
||||
|
||||
@ -13,6 +15,12 @@ const DataManageTable = props => {
|
||||
|
||||
const [selectIds, setSelectIds] = useState([]);
|
||||
|
||||
// 新增编辑抽屉相关状态
|
||||
const [editDrawerOpen, setEditDrawerOpen] = useState(false);
|
||||
const [currentEditData, setCurrentEditData] = useState({});
|
||||
// 添加添加数据抽屉的状态
|
||||
const [addDrawerOpen, setAddDrawerOpen] = useState(false);
|
||||
|
||||
const rowSelection = {
|
||||
type: 'checkbox',
|
||||
onChange: (selectedRowKeys, selectedRows) => {
|
||||
@ -34,7 +42,12 @@ const DataManageTable = props => {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 编辑按钮点击处理(关键:此函数将打开抽屉)
|
||||
const handleEdit = (record) => {
|
||||
console.log("编辑数据:", record); // 用于调试,确认是否触发
|
||||
setCurrentEditData(record);
|
||||
setEditDrawerOpen(true); // 打开抽屉
|
||||
};
|
||||
const [importDataOpen, setImportDataOpen] = useState(false);
|
||||
|
||||
const importDataDrawerOnClose = () => {
|
||||
@ -48,20 +61,38 @@ const DataManageTable = props => {
|
||||
open={importDataOpen}
|
||||
onClose={importDataDrawerOnClose}
|
||||
fetchWorkloadData={fetWorkload}
|
||||
/>
|
||||
{/* 编辑抽屉 */}
|
||||
<EditDataManageDrawer
|
||||
open={editDrawerOpen}
|
||||
setOpen={setEditDrawerOpen}
|
||||
commonAxios={commonAxios}
|
||||
fetchWorkload={fetWorkload}
|
||||
messageApi={messageApi}
|
||||
initialValues={currentEditData}
|
||||
/>
|
||||
{/* 添加数据抽屉 */}
|
||||
<AddDataManageDrawer
|
||||
open={addDrawerOpen}
|
||||
setOpen={setAddDrawerOpen}
|
||||
commonAxios={commonAxios}
|
||||
fetchWorkload={fetWorkload}
|
||||
messageApi={messageApi}
|
||||
/>
|
||||
<Flex justify={"space-between"} align={"center"} gap={"middle"}>
|
||||
<h3>数据管理</h3>
|
||||
<Flex justify={"flex-end"} align={"center"} gap={"middle"}>
|
||||
<Typography.Text>共{workloadData.total}条数据</Typography.Text>
|
||||
{/* 添加"添加数据"按钮 */}
|
||||
<Button type={"primary"} onClick={() => setAddDrawerOpen(true)}>添加数据</Button>
|
||||
<Button type={"primary"} onClick={() => setImportDataOpen(true)}>导入</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
{/* 关键修复:传递 handleEdit 到表格列 */}
|
||||
<Table
|
||||
rowSelection={
|
||||
rowSelection
|
||||
}
|
||||
rowSelection={rowSelection}
|
||||
rowKey={(record) => record.id}
|
||||
columns={ManageTableColumn(commonAxios, messageApi, fetWorkload)}
|
||||
columns={ManageTableColumn(commonAxios, messageApi, fetWorkload, handleEdit)} // 新增 handleEdit 参数
|
||||
dataSource={workloadData.list}
|
||||
pagination={false}
|
||||
/>
|
||||
|
||||
162
src/page/Dashboard/DataManager/EditDataManageDrawer.jsx
Normal file
162
src/page/Dashboard/DataManager/EditDataManageDrawer.jsx
Normal file
@ -0,0 +1,162 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, Drawer, Flex, Form, Input, Select, Typography } from "antd";
|
||||
import CourseTypeTag from "../../../component/Workload/CourseTypeTag";
|
||||
|
||||
const EditDataManageDrawer = props => {
|
||||
const { open, setOpen, commonAxios, fetchWorkload, messageApi, initialValues } = props;
|
||||
|
||||
// 表单布局配置,与添加组件保持一致
|
||||
const formLayout = {
|
||||
labelCol: { span: 5 },
|
||||
wrapperCol: { span: 20 },
|
||||
};
|
||||
|
||||
const [form] = Form.useForm();
|
||||
const { Title } = Typography;
|
||||
|
||||
// 课程性质选项(根据实际业务调整)
|
||||
const courseNatureOptions = [
|
||||
{ label: '公共课', value: '01' },
|
||||
{ label: '专业课', value: '02' },
|
||||
{ label: '校选课', value: '03' },
|
||||
];
|
||||
|
||||
// 当抽屉打开且有初始值时,填充表单数据
|
||||
React.useEffect(() => {
|
||||
if (open && initialValues) {
|
||||
form.setFieldsValue({
|
||||
semesterInfo: initialValues.semesterInfo,
|
||||
courseName: initialValues.courseName,
|
||||
teacherName: initialValues.teacherName,
|
||||
courseNature: initialValues.courseNature,
|
||||
teachingMajor: initialValues.teachingMajor,
|
||||
actualClassSize: initialValues.actualClassSize,
|
||||
teachingGrade: initialValues.teachingGrade,
|
||||
totalClassHours: initialValues.totalClassHours
|
||||
});
|
||||
} else {
|
||||
form.resetFields();
|
||||
}
|
||||
}, [open, initialValues, form]);
|
||||
|
||||
// 提交编辑表单
|
||||
const onSubmit = (values) => {
|
||||
// 拼接ID用于后端识别更新对象
|
||||
const updateData = { ...values, id: initialValues.id, stuffNumber: initialValues.stuffNumber };
|
||||
commonAxios.put('/api/v1/workload/updateWordload', updateData).then(response => {
|
||||
const result = response.data.data || false;
|
||||
if (result) {
|
||||
messageApi.success('编辑工作量信息成功');
|
||||
setOpen(false);
|
||||
fetchWorkload(); // 刷新列表
|
||||
} else {
|
||||
messageApi.error('编辑工作量信息失败');
|
||||
}
|
||||
}).catch(error => {
|
||||
messageApi.error('网络错误,编辑失败');
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
title={'编辑工作量'}
|
||||
destroyOnClose
|
||||
>
|
||||
<div>
|
||||
<Title level={5}>编辑工作量信息</Title>
|
||||
<Form
|
||||
form={form}
|
||||
{...formLayout}
|
||||
onFinish={onSubmit}
|
||||
>
|
||||
<Form.Item
|
||||
label="学期"
|
||||
name="semesterInfo"
|
||||
rules={[{ required: true, message: '请输入学期' }]}
|
||||
>
|
||||
<Input placeholder="请输入学期"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="授课名称"
|
||||
name="courseName"
|
||||
rules={[{ required: true, message: '请输入授课名称' }]}
|
||||
>
|
||||
<Input placeholder="请输入授课名称"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="姓名"
|
||||
name="teacherName"
|
||||
rules={[{ required: true, message: '请输入姓名' }]}
|
||||
>
|
||||
<Input placeholder="请输入姓名"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="课程性质"
|
||||
name="courseNature"
|
||||
rules={[{ required: true, message: '请选择课程性质' }]}
|
||||
>
|
||||
<Select
|
||||
placeholder="请选择课程性质"
|
||||
options={courseNatureOptions}
|
||||
// 保持与表格中一致的标签显示
|
||||
formatLabel={(option) => <CourseTypeTag courseNature={option.value} />}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="授课专业"
|
||||
name="teachingMajor"
|
||||
rules={[{ required: true, message: '请输入授课专业' }]}
|
||||
>
|
||||
<Input placeholder="请输入授课专业"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="学生数"
|
||||
name="actualClassSize"
|
||||
rules={[
|
||||
{ required: true, message: '请输入学生数' },
|
||||
//{ type: 'number', message: '请输入数字' }
|
||||
]}
|
||||
>
|
||||
<Input type="number" placeholder="请输入学生数"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="授课对象"
|
||||
name="teachingGrade"
|
||||
rules={[{ required: true, message: '请输入授课对象' }]}
|
||||
>
|
||||
<Input placeholder="请输入授课对象"/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="工作量"
|
||||
name="totalClassHours"
|
||||
rules={[
|
||||
{ required: true, message: '请输入工作量' },
|
||||
//{ type: 'number', message: '请输入数字' }
|
||||
]}
|
||||
>
|
||||
<Input type="number" placeholder="请输入工作量"/>
|
||||
</Form.Item>
|
||||
<Flex justify={"center"} align={"center"}>
|
||||
<Button onClick={() => setOpen(false)} style={{ marginRight: 8 }}>取消</Button>
|
||||
<Button htmlType={'submit'} type={'primary'}>保存</Button>
|
||||
</Flex>
|
||||
</Form>
|
||||
</div>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
// 属性校验,与添加组件保持一致
|
||||
EditDataManageDrawer.propTypes = {
|
||||
open: PropTypes.bool.isRequired,
|
||||
setOpen: PropTypes.func.isRequired,
|
||||
commonAxios: PropTypes.func.isRequired,
|
||||
fetchWorkload: PropTypes.func.isRequired,
|
||||
messageApi: PropTypes.object.isRequired,
|
||||
initialValues: PropTypes.object // 编辑的初始数据
|
||||
};
|
||||
|
||||
export default EditDataManageDrawer;
|
||||
@ -1,7 +1,8 @@
|
||||
import {Button, Space} from "antd";
|
||||
import { EditOutlined } from "@ant-design/icons"; // 引入编辑图标(解决第一个错误)
|
||||
import CourseTypeTag from "../../../component/Workload/CourseTypeTag";
|
||||
|
||||
const ManageTableColumn = (commonAxios, messageApi, fetchWorkload) => [
|
||||
const ManageTableColumn = (commonAxios, messageApi, fetchWorkload, handleEdit) => [
|
||||
//{
|
||||
// title: 'ID',
|
||||
// dataIndex: 'id',
|
||||
@ -67,24 +68,39 @@ const ManageTableColumn = (commonAxios, messageApi, fetchWorkload) => [
|
||||
title: '操作',
|
||||
dataIndex: 'operation',
|
||||
key: 'operation',
|
||||
render: (_, record) => (
|
||||
<Space size={"middle"}>
|
||||
<Button danger onClick={() => {
|
||||
let id = record.id;
|
||||
let param = [];
|
||||
param.push(id);
|
||||
let url = `/api/v1/workload/delete`
|
||||
commonAxios.delete(url, {data: param}).then(res => {
|
||||
if (res.data.data && res.data.data === true) {
|
||||
messageApi.success("删除成功");
|
||||
fetchWorkload()
|
||||
} else {
|
||||
messageApi.warning('您要删除的数据不存在或已被删除!');
|
||||
}
|
||||
})
|
||||
}}>删除</Button>
|
||||
</Space>
|
||||
)
|
||||
render: (_, record) => {
|
||||
// 确保handleEdit存在再调用,避免参数未传递时出错
|
||||
const handleEditClick = () => {
|
||||
if (typeof handleEdit === 'function') {
|
||||
handleEdit(record);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Space size={"middle"}>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<EditOutlined />}
|
||||
onClick={handleEditClick}
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
<Button danger onClick={() => {
|
||||
let id = record.id;
|
||||
let param = [id];
|
||||
let url = `/api/v1/workload/delete`;
|
||||
commonAxios.delete(url, {data: param}).then(res => {
|
||||
if (res.data.data && res.data.data === true) {
|
||||
messageApi.success("删除成功");
|
||||
fetchWorkload();
|
||||
} else {
|
||||
messageApi.warning('您要删除的数据不存在或已被删除!');
|
||||
}
|
||||
});
|
||||
}}>删除</Button>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@ -154,8 +154,22 @@ function QueryConditionBox(props) {
|
||||
</Row>
|
||||
<Flex justify={"space-between"} align={"center"}>
|
||||
<Flex justify={"start"} align={"center"}>
|
||||
<Button icon={<PlusOutlined/>}
|
||||
onClick={() => navigate('/generate-certificate')}>生成新报告</Button>
|
||||
{/*修改生成新证明按钮的点击事件*/}
|
||||
<Button
|
||||
icon={<PlusOutlined />}
|
||||
onClick={() => {
|
||||
const selectedStaffNumbers = form.getFieldValue('staffNumber') || [];
|
||||
const baseUrl = '/generate-certificate';
|
||||
// 携带工号和来源标记(用于区分跳转场景)
|
||||
if (selectedStaffNumbers.length > 0) {
|
||||
navigate(`${baseUrl}?staffNumber=${selectedStaffNumbers[0]}&from=print`);
|
||||
} else {
|
||||
navigate(baseUrl);
|
||||
}
|
||||
}}
|
||||
>
|
||||
生成新证明
|
||||
</Button>
|
||||
</Flex>
|
||||
<Flex justify={"center"} align={"center"} gap={"large"}>
|
||||
<Button type={"primary"} htmlType={"submit"} icon={<SearchOutlined/>}>搜索</Button>
|
||||
|
||||
@ -31,6 +31,29 @@ const CardAction = (record, messageApi, navigator) => {
|
||||
|
||||
});
|
||||
}
|
||||
const downloadWordRecord = (recordId) => {
|
||||
let baseUrl = baseWebConfig.baseUrl
|
||||
commonAxios.get(`${baseUrl}/api/v1/workload/certificate/downloadWord/${recordId}`, {responseType: 'blob'}).then((response) => {
|
||||
if (response.data.type === 'application/json') {
|
||||
messageApi.error('证明已失效 (GENERATE_CERTIFICATE_ERROR_007)');
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 1000);
|
||||
} else {
|
||||
let fileName = `certificate-${recordId}.docx`;
|
||||
const blob = new Blob([response.data], {type: 'application/octet-stream'});
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = fileName;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
document.body.removeChild(a);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
const reGenerateRecord = (record) => {
|
||||
if (record.status === '01' || record.status === '02') {
|
||||
@ -83,7 +106,17 @@ const CardAction = (record, messageApi, navigator) => {
|
||||
>
|
||||
<RetweetOutlined/>
|
||||
</Popconfirm>] : []),
|
||||
...(record.status === '02' ? [<DownloadOutlined onClick={() => downloadRecord(record.id)}/>] : []),
|
||||
...(record.status === '02' ? [
|
||||
<span onClick={() => downloadRecord(record.id)} style={{ marginRight: 16, cursor: 'pointer' }}>
|
||||
<DownloadOutlined style={{ marginRight: 4 }} />
|
||||
下载PDF
|
||||
</span>,
|
||||
//downloadWordRecord
|
||||
<span onClick={() => downloadWordRecord(record.id)} style={{ cursor: 'pointer' }}>
|
||||
<DownloadOutlined style={{ marginRight: 4 }} />
|
||||
下载Word
|
||||
</span>
|
||||
] : []),
|
||||
...(record.status === '03' || record.status === '04'
|
||||
? [<Popconfirm
|
||||
title="删除证明记录"
|
||||
|
||||
@ -26,7 +26,7 @@ function PrintRecordCard(props) {
|
||||
<Card
|
||||
bordered={true}
|
||||
bodyStyle={{
|
||||
height: 200
|
||||
height: 250
|
||||
}}
|
||||
style={{minWidth: 400}}
|
||||
hoverable={true}
|
||||
|
||||
@ -8,7 +8,8 @@ import {PlusOutlined} from "@ant-design/icons";
|
||||
import {useNavigate} from "react-router-dom";
|
||||
|
||||
const DataPrint = props => {
|
||||
const [downloadDisabled, setDownloadDisabled] = useState(true);
|
||||
//const [downloadDisabled, setDownloadDisabled] = useState(true);
|
||||
const [setDownloadDisabled] = useState(true);
|
||||
const previewClicked = () => {
|
||||
setDownloadDisabled(false);
|
||||
}
|
||||
|
||||
@ -1,145 +1,171 @@
|
||||
import React, {useEffect} from 'react';
|
||||
import {Button, Flex, Form, Input, message, Spin, Table, Typography} from "antd";
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import { Button, Flex, Form, Input, message, Spin, Table, Typography } from "antd";
|
||||
import creatMessageCommonAxios from "../../../http/CreatMessageCommonAxios";
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
const ChooseUser = props => {
|
||||
const { allowNext, request, setRequest } = props;
|
||||
const [searchParams] = useSearchParams(); // 获取URL参数
|
||||
const [autoProcessed, setAutoProcessed] = useState(false); // 防止重复处理
|
||||
const { Title, Text } = Typography;
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const [form] = Form.useForm();
|
||||
const dataFetchRef = useRef(false); // 防止重复请求
|
||||
const commonAxios = creatMessageCommonAxios(messageApi);
|
||||
// 初始加载标记
|
||||
const [isInitialLoad, setIsInitialLoad] = useState(true);
|
||||
// 新增:用于存储当前选中的行ID(控制表格视觉选中状态)
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
||||
const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
hidden: true,
|
||||
},
|
||||
{
|
||||
title: '工号',
|
||||
dataIndex: 'staffNumber',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'name',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: '学院',
|
||||
dataIndex: 'college',
|
||||
},
|
||||
{
|
||||
title: '系别',
|
||||
dataIndex: 'department',
|
||||
width: 300
|
||||
},
|
||||
];
|
||||
|
||||
const {allowNext, request, setRequest} = props;
|
||||
const [staffInfo, setStaffInfo] = useState([]);
|
||||
const [staffNumberPrefix, setStaffNumberPrefix] = useState("");
|
||||
const [spinning, setSpinning] = useState(true);
|
||||
|
||||
const {Title, Text} = Typography;
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const [form] = Form.useForm();
|
||||
// 处理选中行逻辑(同时更新表格选中状态)
|
||||
const handleRowSelect = (selectedRowKeys, selectedRows) => {
|
||||
console.log(`选中行: ${selectedRowKeys}`, selectedRows);
|
||||
// 1. 更新按钮状态和请求参数
|
||||
allowNext(selectedRows.length > 0);
|
||||
if (selectedRows.length > 0) {
|
||||
setRequest({ ...request, stuffNumber: selectedRows[0].staffNumber });
|
||||
}
|
||||
// 2. 更新表格选中状态(关键:让表格知道哪些行被选中)
|
||||
setSelectedRowKeys(selectedRowKeys);
|
||||
};
|
||||
|
||||
const commonAxios = creatMessageCommonAxios(messageApi);
|
||||
// 行选择配置(使用selectedRowKeys控制选中状态)
|
||||
const rowSelection = {
|
||||
onChange: handleRowSelect,
|
||||
selectedRowKeys: selectedRowKeys, // 绑定选中行ID数组
|
||||
defaultSelectedRowKeys: () => [],
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
hidden: true,
|
||||
width: 0,
|
||||
},
|
||||
{
|
||||
title: '工号',
|
||||
dataIndex: 'staffNumber',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'name',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: '学院',
|
||||
dataIndex: 'college',
|
||||
},
|
||||
{
|
||||
title: '系别',
|
||||
dataIndex: 'department',
|
||||
width: 300
|
||||
},
|
||||
];
|
||||
// 通用搜索函数(自动选中时同步更新表格状态)
|
||||
const fetchStaffData = (staffNumber) => {
|
||||
if (dataFetchRef.current) return;
|
||||
dataFetchRef.current = true;
|
||||
|
||||
const [staffInfo, setStaffInfo] = React.useState([]);
|
||||
|
||||
const [staffNumberPrefix, setStaffNumberPrefix] = React.useState("");
|
||||
const [spinning, setSpinning] = React.useState(true);
|
||||
|
||||
const rowSelection = {
|
||||
onChange: (selectedRowKeys, selectedRows) => {
|
||||
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
|
||||
allowNext(selectedRows.length > 0);
|
||||
setRequest({...request, stuffNumber: selectedRows[0].staffNumber});
|
||||
sessionStorage.setItem('chooseUser', selectedRowKeys)
|
||||
sessionStorage.removeItem('certificateParam');
|
||||
sessionStorage.removeItem('targetKeys');
|
||||
sessionStorage.removeItem('generate-request');
|
||||
},
|
||||
defaultSelectedRowKeys: () => {
|
||||
const selectedRowKeys = [];
|
||||
let selected = sessionStorage.getItem('chooseUser');
|
||||
if (selected) {
|
||||
// 转换为number
|
||||
selectedRowKeys.push(selected);
|
||||
allowNext(selectedRowKeys.length > 0);
|
||||
}
|
||||
return selectedRowKeys;
|
||||
}
|
||||
setSpinning(true);
|
||||
const params = staffNumber ? `&staffNumber=${staffNumber}` : '';
|
||||
commonAxios.get(`/api/auth/query/registered?page=1&size=10${params}`)
|
||||
.then((response) => {
|
||||
if (response.data.data?.list) {
|
||||
const list = response.data.data.list.map(item => ({ ...item, key: item.id }));
|
||||
setStaffInfo(list);
|
||||
return list;
|
||||
} else {
|
||||
setStaffInfo([]);
|
||||
return [];
|
||||
}
|
||||
})
|
||||
.then((list) => {
|
||||
const fromPrint = searchParams.get('from') === 'print';
|
||||
if (fromPrint && list.length === 1 && !autoProcessed) {
|
||||
// 自动选中时,同步更新表格选中状态
|
||||
const targetRowKey = [list[0].id];
|
||||
handleRowSelect(targetRowKey, [list[0]]); // 触发选中逻辑
|
||||
setSelectedRowKeys(targetRowKey); // 强制更新表格选中状态
|
||||
setAutoProcessed(true);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
messageApi.error('搜索失败,请重试');
|
||||
setStaffInfo([]);
|
||||
})
|
||||
.finally(() => {
|
||||
setSpinning(false);
|
||||
dataFetchRef.current = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 监听URL参数(从打印界面跳转时处理)
|
||||
useEffect(() => {
|
||||
commonAxios.get(`/api/auth/query/registered?page=1&size=10`).then((response) => {
|
||||
if (response.data.data != null) {
|
||||
let list = response.data.data.list;
|
||||
// 为list设置key=id
|
||||
list.forEach((item) => {
|
||||
item.key = item.id;
|
||||
});
|
||||
setStaffInfo(list);
|
||||
} else {
|
||||
setStaffInfo([]);
|
||||
}
|
||||
});
|
||||
setSpinning(false);
|
||||
}, []);
|
||||
const staffNumber = searchParams.get('staffNumber');
|
||||
const fromPrint = searchParams.get('from') === 'print'; // 标记来自打印界面
|
||||
|
||||
// 优先处理:如果有工号参数且来自打印界面,执行搜索
|
||||
if (staffNumber && fromPrint && !autoProcessed) {
|
||||
form.setFieldsValue({ 'staff-number': staffNumber });
|
||||
setStaffNumberPrefix(staffNumber);
|
||||
fetchStaffData(staffNumber);
|
||||
setIsInitialLoad(false); // 已处理参数,无需再加载全部
|
||||
}
|
||||
// 次要处理:无参数时,初始加载全部数据(仅执行一次)
|
||||
else if (isInitialLoad) {
|
||||
fetchStaffData(''); // 空参数表示查询全部
|
||||
setIsInitialLoad(false);
|
||||
}
|
||||
}, [searchParams, form, autoProcessed, isInitialLoad]); // 添加isInitialLoad依赖
|
||||
|
||||
// 手动搜索
|
||||
const onSearch = () => {
|
||||
setSpinning(true);
|
||||
commonAxios.get(`/api/auth/query/registered?staffNumber=${staffNumberPrefix}&page=1&size=10`).then((response) => {
|
||||
if (response.data.data != null) {
|
||||
let list = response.data.data.list;
|
||||
// 为list设置key=id
|
||||
list.forEach((item) => {
|
||||
item.key = item.id;
|
||||
});
|
||||
setStaffInfo(list);
|
||||
} else {
|
||||
setStaffInfo([]);
|
||||
}
|
||||
setSpinning(false);
|
||||
});
|
||||
}
|
||||
fetchStaffData(staffNumberPrefix);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{contextHolder}
|
||||
<Flex vertical justiffy={"start"} align={"start"} gap={"large"}>
|
||||
<div>
|
||||
<Title level={4}>选择用户</Title>
|
||||
<Text level={4}
|
||||
type={'secondary'}>指示EFC系统为何人生成报告,选择后这份报告将会出现在您和该同事的EFC系统证明管理画面中。</Text>
|
||||
</div>
|
||||
<Form
|
||||
form={form}
|
||||
layout={"inline"}
|
||||
>
|
||||
<Form.Item
|
||||
name='staff-number'
|
||||
>
|
||||
<Input placeholder={"工号"} onChange={(event) => setStaffNumberPrefix(event.target.value)}/>
|
||||
</Form.Item>
|
||||
<Button type={"primary"} onClick={() => onSearch()}>搜索</Button>
|
||||
</Form>
|
||||
<div style={{width: '100%'}}>
|
||||
<Spin spinning={spinning}>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={staffInfo}
|
||||
pagination={false}
|
||||
rowSelection={{
|
||||
type: 'radio',
|
||||
...rowSelection,
|
||||
}}
|
||||
/>
|
||||
</Spin>
|
||||
</div>
|
||||
</Flex>
|
||||
</div>
|
||||
)
|
||||
;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
{contextHolder}
|
||||
<Flex vertical justify={"start"} align={"start"} gap={"large"}>
|
||||
<div>
|
||||
<Title level={4}>选择用户</Title>
|
||||
<Text type={'secondary'}>
|
||||
指示EFC系统为何人生成报告,选择后这份报告将会出现在您和该同事的EFC系统证明管理画面中。
|
||||
</Text>
|
||||
</div>
|
||||
<Form form={form} layout={"inline"}>
|
||||
<Form.Item name='staff-number'>
|
||||
<Input
|
||||
placeholder={"工号"}
|
||||
onChange={(e) => setStaffNumberPrefix(e.target.value)}
|
||||
onPressEnter={onSearch} // 支持回车搜索
|
||||
/>
|
||||
</Form.Item>
|
||||
<Button type={"primary"} onClick={onSearch}>搜索</Button>
|
||||
</Form>
|
||||
<div style={{ width: '100%' }}>
|
||||
<Spin spinning={spinning}>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={staffInfo}
|
||||
pagination={false}
|
||||
rowSelection={{ type: 'radio', ...rowSelection }}
|
||||
locale={{ emptyText: '暂无数据,请输入工号搜索' }}
|
||||
/>
|
||||
</Spin>
|
||||
</div>
|
||||
</Flex>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
ChooseUser.propTypes = {};
|
||||
|
||||
|
||||
@ -15,14 +15,15 @@ const GenerateCertificate = props => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
|
||||
const [current, setCurrent] = React.useState(() => {
|
||||
let nowStep = sessionStorage.getItem('nowStep');
|
||||
if (nowStep === null) {
|
||||
return 0;
|
||||
} else {
|
||||
return parseInt(nowStep);
|
||||
}
|
||||
});
|
||||
//const [current, setCurrent] = React.useState(() => {
|
||||
// let nowStep = sessionStorage.getItem('nowStep');
|
||||
// if (nowStep === null) {
|
||||
// return 0;
|
||||
// } else {
|
||||
// return parseInt(nowStep);
|
||||
// }
|
||||
//});
|
||||
const [current, setCurrent] = React.useState(0);
|
||||
|
||||
const [request, setRequest] = React.useState({
|
||||
ids: [],
|
||||
@ -36,7 +37,7 @@ const GenerateCertificate = props => {
|
||||
const [result, setResult] = React.useState({});
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
|
||||
const [pageConfig, setPageConfig] = React.useState({});
|
||||
//const [pageConfig, setPageConfig] = React.useState({});
|
||||
|
||||
const steps = [
|
||||
{
|
||||
@ -159,7 +160,7 @@ const GenerateCertificate = props => {
|
||||
const onPrev = () => {
|
||||
let nextCurrent = current - 1;
|
||||
setCurrent(nextCurrent);
|
||||
let editFlag = sessionStorage.getItem('edit-flag');
|
||||
//let editFlag = sessionStorage.getItem('edit-flag');
|
||||
if (nextCurrent <= 0) {
|
||||
setCurrent(0)
|
||||
setPreButton({...preButton, disabled: true,})
|
||||
|
||||
Reference in New Issue
Block a user