diff --git a/public/img/avatar.jpg b/public/img/avatar.jpg
new file mode 100644
index 0000000..a3d075e
Binary files /dev/null and b/public/img/avatar.jpg differ
diff --git a/public/img/avatar1.jpg b/public/img/avatar1.jpg
new file mode 100644
index 0000000..378fe5d
Binary files /dev/null and b/public/img/avatar1.jpg differ
diff --git a/public/img/card.jpg b/public/img/card.jpg
new file mode 100644
index 0000000..800e314
Binary files /dev/null and b/public/img/card.jpg differ
diff --git a/src/assets/img/avatar.jpg b/src/assets/img/avatar.jpg
new file mode 100644
index 0000000..a3d075e
Binary files /dev/null and b/src/assets/img/avatar.jpg differ
diff --git a/src/pages/attendancemanage_attendancedata/attendancemanageAttendancedata.js b/src/pages/attendancemanage_attendancedata/attendancemanageAttendancedata.js
index 0d5951d..af98105 100644
--- a/src/pages/attendancemanage_attendancedata/attendancemanageAttendancedata.js
+++ b/src/pages/attendancemanage_attendancedata/attendancemanageAttendancedata.js
@@ -1,14 +1,576 @@
-import React, {Fragment, PureComponent} from 'react';
-import styles from './attendancemanageAttendancedata.less';
-class attendancemanageAttendancedata extends PureComponent {
+import React, { PureComponent } from 'react';
+import {
+ Card,
+ Tree,
+ Button,
+ Select,
+ Space,
+ Row,
+ Col,
+ Pagination
+} from 'antd';
+import { history } from 'umi';
+import {
+ ExpandOutlined,
+ UserOutlined,
+ TeamOutlined,
+ ApartmentOutlined,
+ SyncOutlined,
+ DollarOutlined,
+ SettingOutlined,
+ DownloadOutlined,
+ UserAddOutlined,
+ EditOutlined,
+ DeleteOutlined
+} from '@ant-design/icons';
+import styles from './AttendancemanageAttendancedata.less';
+import StandardTable from '@/components/StandardTable';
+import AttendancedataAdd from './form/AttendancedataAdd';
+import AttendancedataAddRenderSimpleForm from "./form/AttendancedataAddRenderSimpleForm" //表单
+
+const { Option } = Select;
+
+class AttendancemanageAttendancedata extends PureComponent {
+ constructor(props) {
+ super(props);
+ this.state = {
+ searchForm: {},
+ selectedKeys: [],
+ expandedKeys: ['0-0', '0-0-0', '0-0-1', '0-0-2'],
+ addModalVisible: false, // 新增弹窗显示状态
+ addLoading: false, // 新增loading状态
+ organizationData: [
+ {
+ title: '飞利信科技有限公司',
+ key: '0-0',
+ count: 356,
+ children: [
+ {
+ title: '技术部',
+ key: '0-0-0',
+ count: 120,
+ children: [
+ { title: '前端组', key: '0-0-0-0', count: 45 },
+ { title: '后端组', key: '0-0-0-1', count: 52 },
+ { title: '测试组', key: '0-0-0-2', count: 23 }
+ ],
+ },
+ {
+ title: '产品部',
+ key: '0-0-1',
+ count: 68,
+ children: [
+ { title: '产品设计组', key: '0-0-1-0', count: 28 },
+ { title: '用户体验组', key: '0-0-1-1', count: 25 },
+ { title: '产品运营组', key: '0-0-1-2', count: 15 }
+ ],
+ },
+ {
+ title: '运营部',
+ key: '0-0-2',
+ count: 52,
+ children: [
+ { title: '市场营销组', key: '0-0-2-0', count: 22 },
+ { title: '客户服务组', key: '0-0-2-1', count: 18 },
+ { title: '商务合作组', key: '0-0-2-2', count: 12 }
+ ],
+ },
+ {
+ title: '财务部',
+ key: '0-0-3',
+ count: 32,
+ children: [
+ { title: '会计组', key: '0-0-3-0', count: 18 },
+ { title: '审计组', key: '0-0-3-1', count: 14 }
+ ],
+ },
+ {
+ title: '人事部',
+ key: '0-0-4',
+ count: 84,
+ children: [
+ { title: 'HR专员组', key: '0-0-4-0', count: 25 },
+ { title: '招聘组', key: '0-0-4-1', count: 22 },
+ { title: '培训组', key: '0-0-4-2', count: 18 },
+ { title: '薪酬组', key: '0-0-4-3', count: 19 }
+ ],
+ },
+ ],
+ },
+ ],
+ tableData: [
+ {
+ key: '1',
+ employeeId: 'EMP001',
+ employeeName: '张三',
+ date: '2024-01-15',
+ unit: '飞利信科技有限公司',
+ department: '技术部',
+ attendanceStatus: '正常',
+ clockInTime: '09:00:00',
+ clockOutTime: '18:00:00'
+ },
+ {
+ key: '2',
+ employeeId: 'EMP002',
+ employeeName: '李四',
+ date: '2024-01-15',
+ unit: '飞利信科技有限公司',
+ department: '产品部',
+ attendanceStatus: '迟到',
+ clockInTime: '09:15:00',
+ clockOutTime: '18:00:00'
+ },
+ {
+ key: '3',
+ employeeId: 'EMP003',
+ employeeName: '王五',
+ date: '2024-01-15',
+ unit: '飞利信科技有限公司',
+ department: '运营部',
+ attendanceStatus: '早退',
+ clockInTime: '09:00:00',
+ clockOutTime: '17:30:00'
+ },
+ {
+ key: '4',
+ employeeId: 'EMP004',
+ employeeName: '赵六',
+ date: '2024-01-15',
+ unit: '飞利信科技有限公司',
+ department: '财务部',
+ attendanceStatus: '正常',
+ clockInTime: '08:55:00',
+ clockOutTime: '18:05:00'
+ },
+ {
+ key: '5',
+ employeeId: 'EMP005',
+ employeeName: '陈七',
+ date: '2024-01-15',
+ unit: '飞利信科技有限公司',
+ department: '人事部',
+ attendanceStatus: '缺勤',
+ clockInTime: '--',
+ clockOutTime: '--'
+ },
+ ],
+ pagination: {
+ current: 1,
+ pageSize: 5,
+ total: 356,
+ }
+ };
+
+ // 默认列配置
+ this.defaultColumns = [
+ {
+ title: '员工ID',
+ dataIndex: 'employeeId',
+ key: 'employeeId',
+ width: 100,
+ align: 'center',
+ },
+ {
+ title: '员工姓名',
+ dataIndex: 'employeeName',
+ key: 'employeeName',
+ width: 100,
+ align: 'center',
+ },
+ {
+ title: '日期',
+ dataIndex: 'date',
+ key: 'date',
+ width: 120,
+ align: 'center',
+ },
+ {
+ title: '单位',
+ dataIndex: 'unit',
+ key: 'unit',
+ width: 180,
+ ellipsis: true,
+ },
+ {
+ title: '部门',
+ dataIndex: 'department',
+ key: 'department',
+ width: 100,
+ align: 'center',
+ },
+ {
+ title: '考勤状态',
+ dataIndex: 'attendanceStatus',
+ key: 'attendanceStatus',
+ width: 100,
+ align: 'center',
+ render: (text) => {
+ const statusColors = {
+ '正常': '#52c41a',
+ '迟到': '#faad14',
+ '早退': '#ff7875',
+ '缺勤': '#f50',
+ '请假': '#1890ff'
+ };
+ return (
+
+ {text}
+
+ );
+ }
+ },
+ {
+ title: '上班时间',
+ dataIndex: 'clockInTime',
+ key: 'clockInTime',
+ width: 100,
+ align: 'center',
+ },
+ {
+ title: '下班时间',
+ dataIndex: 'clockOutTime',
+ key: 'clockOutTime',
+ width: 100,
+ align: 'center',
+ },
+ {
+ title: '操作',
+ key: 'action',
+ align: 'center',
+ width: 80,
+ render: (_, record) => (
+
+ }
+ title="编辑"
+ onClick={() => this.handleEdit(record)}
+ />
+ }
+ title="删除"
+ onClick={() => this.handleDelete(record)}
+ />
+
+ ),
+ },
+ ];
+ }
+
+ // 获取处理后的树形数据
+ getTreeData = () => {
+ const { organizationData } = this.state;
+
+ const processNode = (node) => ({
+ key: node.key,
+ title: (
+
+ {this.getNodeIcon(node.title)}
+ {node.title}
+ ({node.count})
+
+ ),
+ children: node.children ? node.children.map(processNode) : undefined
+ });
+
+ return organizationData.map(processNode);
+ };
+
+ // 获取节点图标
+ getNodeIcon = (title) => {
+ if (title.includes('公司') || title.includes('集团')) return ;
+ if (title.includes('技术') || title.includes('开发') || title.includes('测试')) return ;
+ if (title.includes('产品') || title.includes('设计') || title.includes('体验')) return ;
+ if (title.includes('运营') || title.includes('市场') || title.includes('客户') || title.includes('商务')) return ;
+ if (title.includes('财务') || title.includes('会计') || title.includes('审计')) return ;
+ if (title.includes('人事') || title.includes('HR') || title.includes('招聘') || title.includes('培训') || title.includes('薪酬')) return ;
+ return ;
+ };
+
+ // 搜索处理
+ handleSearch = (values) => {
+ console.log('搜索参数:', values);
+ this.setState({ searchForm: values });
+ };
+
+ // 重置搜索
+ handleReset = () => {
+ this.formRef?.resetFields();
+ this.setState({ searchForm: {} });
+ };
+
+ // 树节点选择
+ onTreeSelect = (selectedKeys, info) => {
+ console.log('选中节点:', selectedKeys, info);
+ this.setState({ selectedKeys });
+ };
+
+ // 树节点展开
+ onTreeExpand = (expandedKeys) => {
+ this.setState({ expandedKeys });
+ };
+
+ // 刷新树数据
+ handleTreeRefresh = () => {
+ // console.log('刷新组织架构');
+ // 这里可以添加刷新树数据的逻辑
+ };
+
+ // 展开/收缩所有节点
+ handleTreeToggle = () => {
+ const { expandedKeys, organizationData } = this.state;
+ if (expandedKeys.length > 0) {
+ // 收缩所有节点
+ this.setState({ expandedKeys: [] });
+ } else {
+ // 展开所有节点
+ const getAllKeys = (nodes) => {
+ let keys = [];
+ nodes.forEach(node => {
+ keys.push(node.key);
+ if (node.children) {
+ keys = keys.concat(getAllKeys(node.children));
+ }
+ });
+ return keys;
+ };
+ this.setState({ expandedKeys: getAllKeys(organizationData) });
+ }
+ };
+
+ renderSimpleForm() {
+ const { prooperlog = {} } = this.props;
+ const { params = {} } = prooperlog;
+ const parentMethods = {
+ handleSearch: this.handleSearch,
+ handleFormReset: this.handleFormReset,
+ toggleForm: this.toggleForm,
+ submitButtons: styles.submitButtons,
+ params
+ };
+ return (
+
+ );
+ }
+
+ renderAdvancedForm() {
+ const { prooperlog: { params } } = this.props;
+ const parentMethods = {
+ handleSearch: this.handleSearch,
+ handleFormReset: this.handleFormReset,
+ toggleForm: this.toggleForm,
+ params
+ };
+
+ return (
+
+ );
+ }
+
+ renderForm() {
+ const { expandForm } = this.state;
+ return expandForm ? this.renderAdvancedForm() : this.renderSimpleForm();
+ }
+
+ // 分页处理
+ onPaginationChange = (page, pageSize) => {
+ this.setState({
+ pagination: {
+ ...this.state.pagination,
+ current: page,
+ pageSize,
+ }
+ });
+ };
+
+ // 显示新增弹窗
+ showAddModal = () => {
+ this.setState({ addModalVisible: true });
+ };
+
+ // 关闭新增弹窗
+ hideAddModal = () => {
+ this.setState({ addModalVisible: false });
+ };
+
+ // 新增成功回调
+ handleAddSuccess = (values) => {
+ console.log('新增考勤记录成功:', values);
+
+ // 这里可以刷新列表数据
+ // 模拟添加到表格数据中
+ const newAttendance = {
+ key: String(Date.now()),
+ employeeId: values.employeeId || `EMP${String(this.state.tableData.length + 1).padStart(3, '0')}`,
+ employeeName: values.employeeName,
+ date: values.date || new Date().toISOString().split('T')[0],
+ unit: values.unit || '飞利信科技有限公司',
+ department: values.department,
+ attendanceStatus: values.attendanceStatus || '正常',
+ clockInTime: values.clockInTime || '09:00:00',
+ clockOutTime: values.clockOutTime || '18:00:00'
+ };
+
+ this.setState({
+ tableData: [...this.state.tableData, newAttendance],
+ pagination: {
+ ...this.state.pagination,
+ total: this.state.pagination.total + 1
+ }
+ });
+ };
+
+ // 处理姓名点击事件
+ handleNameClick = (record) => {
+ console.log('点击员工:', record);
+ // 跳转到人员详情页面,传递员工ID参数
+ history.push(`/topnavbar00/staffmanage/particulars`);
+ };
+
+ // 处理编辑
+ handleEdit = (record) => {
+ console.log('编辑员工:', record);
+ // 这里可以打开编辑弹窗或跳转到编辑页面
+ };
+
+ // 处理删除
+ handleDelete = (record) => {
+ console.log('删除员工:', record);
+ // 这里可以弹出确认框并执行删除操作
+ };
+
render() {
+ const { tableData, pagination, expandedKeys, addModalVisible, addLoading } = this.state;
return (
- <>
-
- >
- )
+
+ {/* 主体内容 */}
+
+
+
+ {/* 左侧组织架构树 */}
+
+
+
+
+ 组织架构
+
+
+ }
+ size="small"
+ style={{ color: '#1890ff' }}
+ onClick={this.handleTreeRefresh}
+ title="刷新"
+ />
+ }
+ size="small"
+ style={{ color: '#1890ff' }}
+ onClick={this.handleTreeToggle}
+ title={expandedKeys.length > 0 ? "收缩全部" : "展开全部"}
+ />
+
+
+ }
+ className={styles.treeCard}
+ >
+
+
+
+
+
+
+ {/* 右侧人员信息区 */}
+
+ {/* 筛选条件 */}
+
+ {this.renderForm()}
+
+
+ {/* 操作按钮和统计 */}
+
+
+ {/* 共 {pagination.total} 条记录 */}
+
+
+ }
+ size="middle"
+ // className={styles.exportButton}
+ >
+ 导出
+
+ {/* }
+ size="large"
+ className={styles.addButton}
+ onClick={this.showAddModal}
+ >
+ 新增
+ */}
+
+
+
+ {/* 人员表格 */}
+
+
+
+ {/* 分页 */}
+
+
+ `显示 ${range[0]} 到 ${range[1]} 条,共 ${total} 条记录`
+ }
+ onChange={this.onPaginationChange}
+ onShowSizeChange={this.onPaginationChange}
+ />
+
+
+
+
+
+
+
+ {/* 新增人员弹窗 */}
+
+
+ );
}
}
-export default attendancemanageAttendancedata
+export default AttendancemanageAttendancedata;
\ No newline at end of file
diff --git a/src/pages/attendancemanage_attendancedata/attendancemanageAttendancedata.less b/src/pages/attendancemanage_attendancedata/attendancemanageAttendancedata.less
index d5bff80..c265b34 100644
--- a/src/pages/attendancemanage_attendancedata/attendancemanageAttendancedata.less
+++ b/src/pages/attendancemanage_attendancedata/attendancemanageAttendancedata.less
@@ -1,10 +1,521 @@
@import '~@/utils/utils.less';
-.frameContent {
- width: 100%;
- height: 100vh;
- border: none;
- display: block;
- margin: 0;
- padding: 0;
+.staffInfoContainer {
+ min-height: 100vh;
+ // background-color: #f5f6fa;
+
+ .announcementBar {
+ background: #e6f7ff;
+ border: 1px solid #91d5ff;
+ margin-bottom: 16px;
+ border-radius: 6px;
+ overflow: hidden;
+
+ .announcement {
+ display: flex;
+ align-items: center;
+
+ .announcementLabel {
+ background-color: #fef3c7;
+ color: #92400e;
+ border-radius: 4px;
+ padding: 4px 8px;
+ font-size: 12px;
+ font-weight: 500;
+ margin-right: 12px;
+ white-space: nowrap;
+ display: flex;
+ align-items: center;
+
+ .anticon {
+ margin-right: 4px;
+ }
+ }
+
+ .scrollContainer {
+ flex: 1;
+ overflow: hidden;
+ white-space: nowrap;
+ }
+
+ .scrollContent {
+ display: inline-block;
+ animation: scroll 30s linear infinite;
+ color: #666;
+ font-size: 14px;
+ }
+ }
+ }
+
+ .mainContent {
+ padding: 12px;
+
+ .contentCard {
+ .ant-card-head {
+ .ant-card-head-title {
+ font-size: 18px;
+ font-weight: 600;
+ color: #333;
+ }
+ }
+ }
+
+ .treeCard {
+ height: 600px;
+ border: 1px solid #e8e8e8;
+ border-radius: 8px;
+
+ .treeHeader {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-size: 14px;
+ font-weight: 500;
+ }
+
+ .treeContainer {
+ height: 520px;
+ overflow-y: auto;
+
+ /* 自定义滚动条样式 */
+ &::-webkit-scrollbar {
+ width: 6px;
+ }
+
+ &::-webkit-scrollbar-track {
+ background: transparent;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: #d9d9d9;
+ border-radius: 3px;
+
+ &:hover {
+ background: #bfbfbf;
+ }
+ }
+
+ .orgTree {
+ .ant-tree-treenode {
+ padding: 2px 0;
+
+ .ant-tree-node-content-wrapper {
+ border-radius: 4px;
+ transition: all 0.3s ease;
+ padding: 4px 8px;
+
+ &:hover {
+ background-color: #f0f9ff;
+ transform: translateX(2px);
+ }
+
+ &.ant-tree-node-selected {
+ background-color: #e6f7ff !important;
+ box-shadow: 0 2px 8px rgba(24, 144, 255, 0.2);
+ }
+ }
+
+ .ant-tree-iconEle {
+ margin-right: 8px;
+ }
+
+ .ant-tree-title {
+ font-size: 14px;
+ }
+ }
+ }
+ }
+ }
+
+ /* Tree节点标题样式 */
+ .tree-node-title {
+ display: flex;
+ align-items: center;
+ width: 100%;
+
+ .node-title {
+ flex: 1;
+ font-size: 14px;
+ margin-left: 8px;
+ color: #333;
+ }
+
+ .node-count {
+ color: #999;
+ font-size: 12px;
+ margin-left: auto;
+ background: #f0f0f0;
+ padding: 1px 6px;
+ border-radius: 10px;
+ min-width: 20px;
+ text-align: center;
+ }
+ }
+
+ .searchCard {
+ margin-bottom: 16px;
+ border-radius: 8px;
+ border: 1px solid #e8e8e8;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
+
+ .ant-card-body {
+ padding: 16px;
+ }
+
+ /* 搜索表单容器样式 */
+ .searchFormContainer {
+ .searchForm {
+ .ant-form-item {
+ margin-bottom: 16px;
+
+ .ant-form-item-label {
+ font-weight: 500;
+ color: #333;
+
+ label {
+ color: #333 !important;
+ font-size: 14px;
+ }
+ }
+
+ .ant-input,
+ .ant-select-selector,
+ .ant-picker {
+ border-radius: 6px;
+ border: 1px solid #d9d9d9;
+ transition: all 0.3s ease;
+
+ &:hover {
+ border-color: #4c7bff;
+ }
+
+ &:focus,
+ &.ant-select-focused .ant-select-selector,
+ &.ant-picker-focused {
+ border-color: #2d5cf6;
+ box-shadow: 0 0 0 2px rgba(45, 92, 246, 0.2);
+ }
+ }
+
+ .ant-select-selection-placeholder,
+ .ant-input::placeholder,
+ .ant-picker-input input::placeholder {
+ color: #bfbfbf;
+ }
+ }
+ }
+ }
+
+ /* 搜索按钮样式 */
+ .searchButton {
+ background: linear-gradient(135deg, #2d5cf6 0%, #4c7bff 100%);
+ border: none;
+ border-radius: 6px;
+ color: white;
+ font-weight: 500;
+ font-size: 14px;
+ box-shadow: 0 2px 8px rgba(45, 92, 246, 0.3);
+ transition: all 0.3s ease;
+ height: 32px;
+ padding: 0 16px;
+
+ &:hover,
+ &:focus {
+ background: linear-gradient(135deg, #4c7bff 0%, #6b8fff 100%);
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(45, 92, 246, 0.4);
+ color: white;
+ }
+
+ &:active {
+ transform: translateY(0);
+ }
+ }
+
+ /* 重置按钮样式 */
+ .resetButton {
+ background: #fff;
+ border: 1px solid #d9d9d9;
+ color: #666;
+ border-radius: 6px;
+ font-weight: 500;
+ font-size: 14px;
+ transition: all 0.3s ease;
+ height: 32px;
+ padding: 0 16px;
+
+ &:hover,
+ &:focus {
+ border-color: #4c7bff;
+ color: #2d5cf6;
+ }
+
+ .anticon {
+ color: #ff7875;
+ }
+ }
+
+ /* 展开按钮样式 */
+ .expandButton {
+ color: #2d5cf6;
+ font-size: 14px;
+ padding: 0 8px;
+ height: 32px;
+
+ &:hover,
+ &:focus {
+ color: #4c7bff;
+ }
+ }
+ }
+
+ .actionBar {
+
+
+
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 16px;
+
+ .totalInfo {
+ color: #666;
+ font-size: 14px;
+ font-weight: 500;
+ }
+
+ .exportButton {
+ background: linear-gradient(135deg, #52c41a 0%, #73d13d 100%);
+ border: none;
+ color: white;
+ border-radius: 8px;
+ font-weight: 500;
+ font-size: 14px;
+ box-shadow: 0 4px 12px rgba(82, 196, 26, 0.3);
+ transition: all 0.3s ease;
+ // margin-top: -8px;
+ height: 35px;
+ padding: 0 16px;
+
+
+ &:hover,
+ &:focus {
+ background: linear-gradient(135deg, #73d13d 0%, #95de64 100%);
+ transform: translateY(-2px);
+ box-shadow: 0 6px 20px rgba(82, 196, 26, 0.4);
+ color: white;
+ }
+
+ &:active {
+ transform: translateY(0);
+ }
+
+ .anticon {
+ color: white;
+ }
+ }
+
+
+ .addButton {
+ background: linear-gradient(135deg, #fa8c16 0%, #ffa940 100%);
+ border: none;
+ border-radius: 8px;
+ font-weight: 600;
+ font-size: 14px;
+ box-shadow: 0 4px 12px rgba(250, 140, 22, 0.3);
+ transition: all 0.3s ease;
+ // margin-top: -8px;
+ height: 35px;
+ padding: 0 16px;
+
+
+ &:hover,
+ &:focus {
+ background: linear-gradient(135deg, #ffa940 0%, #ffc069 100%);
+ transform: translateY(-2px);
+ box-shadow: 0 6px 20px rgba(250, 140, 22, 0.4);
+ }
+
+ &:active {
+ transform: translateY(0);
+ }
+ }
+ }
+
+ .tableCard {
+ border-radius: 8px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
+ padding-bottom: 10px;
+
+ .ant-table-wrapper {
+ max-height: 600px;
+ overflow-y: auto;
+
+ /* 自定义滚动条样式 */
+ &::-webkit-scrollbar {
+ width: 8px;
+ }
+
+ &::-webkit-scrollbar-track {
+ background: #f5f5f5;
+ border-radius: 4px;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: #d9d9d9;
+ border-radius: 4px;
+
+ &:hover {
+ background: #bfbfbf;
+ }
+ }
+
+ .ant-table-thead>tr>th {
+ background-color: #fafafa;
+ font-weight: 600;
+ color: #333;
+ border-bottom: 1px solid #e8e8e8;
+ position: sticky;
+ top: 0;
+ z-index: 1;
+ }
+
+ .ant-table-tbody>tr {
+ &:hover>td {
+ background-color: #f5f5f5 !important;
+ }
+
+ >td {
+ border-bottom: 1px solid #f0f0f0;
+ }
+ }
+ }
+
+ .paginationWrapper {
+ margin-top: 20px;
+ text-align: right;
+
+ .ant-pagination {
+ .ant-pagination-total-text {
+ color: #666;
+ }
+
+ .ant-pagination-item {
+ border-radius: 4px;
+
+ &.ant-pagination-item-active {
+ background-color: #2d5cf6;
+ border-color: #2d5cf6;
+ }
+ }
+
+ .ant-pagination-prev,
+ .ant-pagination-next {
+ border-radius: 4px;
+ }
+ }
+ }
+ }
+ }
+}
+
+.mainContent {
+ padding: 12px;
+
+ .contentCard {
+ .ant-card-head {
+ .ant-card-head-title {
+ font-size: 18px;
+ font-weight: 600;
+ color: #333;
+ }
+ }
+ }
+
+ .actionBar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 16px;
+
+ .totalInfo {
+ color: #666;
+ font-size: 14px;
+ }
+ }
+
+ :global {
+ .ant-card-body {
+ padding: 12px 24px 0px 24px;
+ }
+ }
+}
+
+
+@keyframes scroll {
+ 0% {
+ transform: translateX(0);
+ }
+
+ 100% {
+ transform: translateX(-50%);
+ }
+}
+
+// 响应式设计
+@media (max-width: 1200px) {
+ .staffInfoContainer {
+ .mainContent {
+ .searchCard {
+ .ant-row {
+ .ant-col {
+ margin-bottom: 16px;
+ }
+ }
+ }
+ }
+ }
+}
+
+// 自定义主题色
+.ant-btn-primary {
+ background-color: #2d5cf6;
+ border-color: #2d5cf6;
+
+ &:hover,
+ &:focus {
+ background-color: #4c7bff;
+ border-color: #4c7bff;
+ }
+}
+
+.ant-tree .ant-tree-node-selected {
+ background-color: #e6f7ff !important;
+}
+
+.ant-select-focused .ant-select-selector,
+.ant-input-affix-wrapper-focused,
+.ant-input:focus,
+.ant-input-focused {
+ border-color: #2d5cf6 !important;
+ box-shadow: 0 0 0 2px rgba(45, 92, 246, 0.2) !important;
+}
+
+// 标签样式优化
+.ant-tag {
+ border-radius: 4px;
+ font-size: 12px;
+}
+
+// 按钮组间距调整
+.ant-space-item {
+ .ant-btn+.ant-btn {
+ margin-left: 8px;
+ }
+}
+
+// 表格链接按钮样式
+.ant-btn-link {
+ padding: 0 4px;
+ font-size: 12px;
}
\ No newline at end of file
diff --git a/src/pages/attendancemanage_attendancedata/form/AttendancedataAdd.js b/src/pages/attendancemanage_attendancedata/form/AttendancedataAdd.js
new file mode 100644
index 0000000..c26b71f
--- /dev/null
+++ b/src/pages/attendancemanage_attendancedata/form/AttendancedataAdd.js
@@ -0,0 +1,218 @@
+import React, { PureComponent } from 'react';
+import {
+ Modal,
+ Form,
+ Input,
+ Select,
+ InputNumber,
+ Row,
+ Col,
+ message,
+ TreeSelect
+} from 'antd';
+import {
+ ApartmentOutlined,
+ UserOutlined,
+ TeamOutlined,
+ FileTextOutlined,
+ NumberOutlined
+} from '@ant-design/icons';
+
+const { Option } = Select;
+
+class DeptMaintainAdd extends PureComponent {
+ constructor(props) {
+ super(props);
+ this.formRef = React.createRef();
+ }
+
+ // 提交表单
+ handleSubmit = (values) => {
+ console.log('新增部门信息:', values);
+
+ // 这里可以调用API接口保存数据
+ // 模拟保存成功
+ message.success('新增部门成功!');
+
+ // 重置表单
+ this.formRef.current?.resetFields();
+
+ // 调用父组件的回调函数
+ if (this.props.onSuccess) {
+ this.props.onSuccess(values);
+ }
+
+ // 关闭弹窗
+ this.handleCancel();
+ };
+
+ // 取消操作
+ handleCancel = () => {
+ // 重置表单
+ this.formRef.current?.resetFields();
+
+ // 调用父组件的关闭回调
+ if (this.props.onCancel) {
+ this.props.onCancel();
+ }
+ };
+
+ render() {
+ const { visible, loading = false } = this.props;
+
+ return (
+ this.formRef.current?.submit()}
+ onCancel={this.handleCancel}
+ width={700}
+ confirmLoading={loading}
+ destroyOnClose={true}
+ maskClosable={false}
+ >
+
+
+ );
+ }
+}
+
+export default DeptMaintainAdd;
diff --git a/src/pages/attendancemanage_attendancedata/form/AttendancedataAddRenderSimpleForm.js b/src/pages/attendancemanage_attendancedata/form/AttendancedataAddRenderSimpleForm.js
new file mode 100644
index 0000000..55180ec
--- /dev/null
+++ b/src/pages/attendancemanage_attendancedata/form/AttendancedataAddRenderSimpleForm.js
@@ -0,0 +1,204 @@
+import React, { useState } from 'react';
+import { Button, Col, Form, Input, Row, message, Select, Space, DatePicker, TreeSelect } from 'antd';
+import { ClearOutlined, SearchOutlined, ExpandOutlined, CompressOutlined, UserOutlined, ApartmentOutlined, TeamOutlined } from '@ant-design/icons';
+import styles from "../AttendancemanageAttendancedata.less";
+
+const FormItem = Form.Item;
+const { Option } = Select;
+const { RangePicker } = DatePicker;
+const AttendancedataAddRenderSimpleForm = (props) => {
+ const [form] = Form.useForm();
+ const [expandForm, setExpandForm] = useState(false);
+ const { submitButtons, handleSearch, handleFormReset, toggleForm, params } = props;
+
+ React.useEffect(() => {
+ form.setFieldsValue({
+ employeeId: params?.employeeId,
+ employeeName: params?.employeeName,
+ unit: params?.unit,
+ department: params?.department,
+ dateRange: params?.dateRange,
+ attendanceStatus: params?.attendanceStatus,
+ });
+ }, [params]);
+
+ const onFinish = values => {
+ const searchParams = {
+ ...values,
+ dateRange: values.dateRange ? [
+ values.dateRange[0].format('YYYY-MM-DD'),
+ values.dateRange[1].format('YYYY-MM-DD')
+ ] : undefined,
+ };
+ handleSearch && handleSearch(searchParams);
+ };
+
+ const myhandleFormReset = () => {
+ form.resetFields();
+ handleFormReset && handleFormReset();
+ };
+
+ const toggleExpandForm = () => {
+ setExpandForm(!expandForm);
+ };
+
+ return (
+
+
+
+ );
+
+};
+
+export default AttendancedataAddRenderSimpleForm;
diff --git a/src/pages/attendancemanage_attendancedata/form/AttendancedataAddRenderSimpleForm.less b/src/pages/attendancemanage_attendancedata/form/AttendancedataAddRenderSimpleForm.less
new file mode 100644
index 0000000..e69de29
diff --git a/src/pages/attendancemanage_attendancedetails/Attendancedetails.js b/src/pages/attendancemanage_attendancedetails/Attendancedetails.js
new file mode 100644
index 0000000..a932377
--- /dev/null
+++ b/src/pages/attendancemanage_attendancedetails/Attendancedetails.js
@@ -0,0 +1,466 @@
+import React, { PureComponent } from 'react';
+import { Card, Input, Button, Table, DatePicker, Tag, Avatar, Row, Col, Statistic, Progress } from 'antd';
+import { SearchOutlined, SyncOutlined, ExclamationCircleOutlined, EditOutlined, ExportOutlined, LineChartOutlined, CalendarOutlined, CalculatorOutlined, DownloadOutlined, PieChartOutlined } from '@ant-design/icons';
+import * as echarts from 'echarts';
+import styles from './Attendancedetails.less';
+
+const { RangePicker } = DatePicker;
+
+class Attendancedetails extends PureComponent {
+ constructor(props) {
+ super(props);
+ this.state = {
+ employeeId: '',
+ employeeName: '',
+ dateRange: null,
+ attendanceData: [],
+ loading: false,
+ };
+ }
+
+ componentDidMount() {
+ this.initAttendanceChart();
+ }
+
+ // 初始化考勤分析图表
+ initAttendanceChart = () => {
+ const chartDom = document.getElementById('attendanceChart');
+ if (chartDom) {
+ const myChart = echarts.init(chartDom);
+ const option = {
+ tooltip: {
+ trigger: 'axis'
+ },
+ legend: {
+ data: ['正常出勤', '迟到', '早退', '缺勤']
+ },
+ grid: {
+ left: '3%',
+ right: '4%',
+ bottom: '3%',
+ containLabel: true
+ },
+ xAxis: {
+ type: 'category',
+ boundaryGap: false,
+ data: ['1日', '2日', '3日', '4日', '5日', '6日', '7日', '8日', '9日', '10日']
+ },
+ yAxis: {
+ type: 'value'
+ },
+ series: [
+ {
+ name: '正常出勤',
+ type: 'line',
+ stack: 'Total',
+ data: [9, 9, 8.5, 9, 9.5, 9, 8.8, 9.2, 9, 9.3]
+ },
+ {
+ name: '迟到',
+ type: 'line',
+ stack: 'Total',
+ data: [0, 0, 0.5, 0, 0, 0, 0.2, 0, 0, 0]
+ },
+ {
+ name: '早退',
+ type: 'line',
+ stack: 'Total',
+ data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+ },
+ {
+ name: '缺勤',
+ type: 'line',
+ stack: 'Total',
+ data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+ }
+ ]
+ };
+ myChart.setOption(option);
+ }
+ };
+
+ // 查询考勤数据
+ handleSearch = () => {
+ this.setState({ loading: true });
+ // 模拟API调用
+ setTimeout(() => {
+ this.setState({ loading: false });
+ }, 1000);
+ };
+
+ // 表格列定义
+ getTableColumns = () => [
+ {
+ title: '日期',
+ dataIndex: 'date',
+ key: 'date',
+ width: 120,
+ },
+ {
+ title: '考勤地点',
+ dataIndex: 'location',
+ key: 'location',
+ width: 150,
+ },
+ {
+ title: '考勤状态',
+ dataIndex: 'status',
+ key: 'status',
+ width: 100,
+ render: (status) => {
+ const statusConfig = {
+ normal: { color: 'success', text: '正常' },
+ late: { color: 'error', text: '迟到' },
+ early: { color: 'warning', text: '早退' },
+ remote: { color: 'processing', text: '远程' },
+ };
+ const config = statusConfig[status] || statusConfig.normal;
+ return {config.text};
+ },
+ },
+ {
+ title: '上班时间',
+ dataIndex: 'checkInTime',
+ key: 'checkInTime',
+ width: 120,
+ },
+ {
+ title: '下班时间',
+ dataIndex: 'checkOutTime',
+ key: 'checkOutTime',
+ width: 120,
+ },
+ {
+ title: '工作时长',
+ dataIndex: 'workHours',
+ key: 'workHours',
+ width: 120,
+ },
+ {
+ title: '操作',
+ key: 'action',
+ width: 80,
+ render: (_, record) => (
+
+ ),
+ },
+ ];
+
+ // 模拟表格数据
+ getTableData = () => [
+ {
+ key: '1',
+ date: '2023-11-01',
+ location: '总部大楼-3F',
+ status: 'normal',
+ checkInTime: '08:56',
+ checkOutTime: '18:30',
+ workHours: '9小时34分钟',
+ },
+ {
+ key: '2',
+ date: '2023-10-31',
+ location: '总部大楼-3F',
+ status: 'normal',
+ checkInTime: '09:02',
+ checkOutTime: '18:45',
+ workHours: '9小时43分钟',
+ },
+ {
+ key: '3',
+ date: '2023-10-30',
+ location: '远程办公',
+ status: 'remote',
+ checkInTime: '09:15',
+ checkOutTime: '18:50',
+ workHours: '9小时35分钟',
+ },
+ {
+ key: '4',
+ date: '2023-10-27',
+ location: '总部大楼-3F',
+ status: 'late',
+ checkInTime: '09:35',
+ checkOutTime: '18:20',
+ workHours: '8小时45分钟',
+ },
+ {
+ key: '5',
+ date: '2023-10-26',
+ location: '总部大楼-3F',
+ status: 'normal',
+ checkInTime: '08:50',
+ checkOutTime: '18:10',
+ workHours: '9小时20分钟',
+ },
+ ];
+
+ render() {
+ const { employeeId, employeeName, dateRange, loading } = this.state;
+
+ return (
+
+ {/* 查询条件 */}
+
+
+
+
+
+ this.setState({ employeeId: e.target.value })}
+ />
+
+
+
+
+
+ this.setState({ employeeName: e.target.value })}
+ />
+
+
+
+
+
+ this.setState({ dateRange: dates })}
+ />
+
+
+
+
+
+ }
+ onClick={this.handleSearch}
+ loading={loading}
+ block
+ >
+ 查询
+
+
+
+
+
+
+ {/* 第一行卡片组 */}
+
+ {/* 员工基本信息卡片 */}
+
+
+
+
+
+ 部门:
+ 产品研发中心
+
+
+ 岗位:
+ 高级产品经理
+
+
+ 职级:
+ P7
+
+
+ 入职日期:
+ 2019-05-15
+
+
+
+
+
+ {/* 考勤状态卡片 */}
+
+
+
+
+
+
上班打卡: 08:58 (准时)
+
下班打卡: 18:32 (准时)
+
工作时长: 9小时34分钟
+
本月累计出勤: 18天
+
+
+
+
+
+ {/* 操作按钮卡片 */}
+
+
+
+
+
+ }>重新同步
+
+
+ }>异常提报
+
+
+ }>修改记录
+
+
+ }>导出数据
+
+
+ }>
+ 查看考勤分析
+
+
+
+
+
+
+
+
+ {/* 考勤数据表格 */}
+
+ `显示 ${range[0]}-${range[1]} 条,共 ${total} 条记录`,
+ }}
+ scroll={{ x: 800 }}
+ />
+
+
+ {/* 第二行卡片组 */}
+
+ {/* 排班数据卡片 */}
+
+
+
+
+ 排班名称:
+ 标准工作日
+
+
+ 上班时间:
+ 09:00
+
+
+ 下班时间:
+ 18:00
+
+
+ 午休时间:
+ 12:00-13:30
+
+
+ 适用日期:
+ 周一至周五
+
+
} className={styles['schedule-button']}>
+ 查看排班历史
+
+
+
+
+
+ {/* 考勤明细卡片 */}
+
+
+
+
+ 应出勤天数:
+ 22天
+
+
+ 实际出勤天数:
+ 18天
+
+
+ 迟到次数:
+ 1次
+
+
+ 早退次数:
+ 0次
+
+
+ 缺卡次数:
+ 0次
+
+
} className={styles['stat-button']}>
+ 查看详细统计
+
+
+
+
+
+ {/* 同步信息卡片 */}
+
+
+
+
+ 最后同步时间:
+ 2023-11-01 23:45:12
+
+
+ 同步状态:
+ 成功
+
+
+ 最后计算时间:
+ 2023-11-02 00:15:30
+
+
+ 计算状态:
+ 成功
+
+
+
+
+ }>立即同步
+
+
+ }>
+ 重新计算
+
+
+
+
+
+
+
+
+
+ {/* 考勤分析图表 */}
+
+
+
月度考勤分析
+
+ }>选择月份
+ }>导出图表
+
+
+
+
+
+ );
+ }
+}
+
+export default Attendancedetails;
\ No newline at end of file
diff --git a/src/pages/attendancemanage_attendancedetails/Attendancedetails.less b/src/pages/attendancemanage_attendancedetails/Attendancedetails.less
new file mode 100644
index 0000000..a1a9a09
--- /dev/null
+++ b/src/pages/attendancemanage_attendancedetails/Attendancedetails.less
@@ -0,0 +1,438 @@
+@import '~@/utils/utils.less';
+
+/* 考勤详情页面样式 */
+.attendance-details-page {
+ padding: 24px;
+ background-color: #f5f5f5;
+ min-height: 90vh;
+ max-height: 90vh; /* 限制最大高度 */
+ overflow-y: auto; /* 添加垂直滚动条 */
+ overflow-x: hidden; /* 隐藏水平滚动条 */
+
+ /* 自定义滚动条样式 */
+ &::-webkit-scrollbar {
+ width: 8px;
+ }
+
+ &::-webkit-scrollbar-track {
+ background: #f1f1f1;
+ border-radius: 4px;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: #c1c1c1;
+ border-radius: 4px;
+
+ &:hover {
+ background: #a8a8a8;
+ }
+ }
+
+ .ant-card {
+ border-radius: 8px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ transition: all 0.3s ease;
+
+ &:hover {
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+ transform: translateY(-2px);
+ }
+ }
+}
+
+/* 查询条件样式 */
+.search-section {
+ margin-bottom: 16px;
+ flex-shrink: 0; /* 防止被压缩 */
+
+ .form-item {
+ margin-bottom: 16px;
+
+ .form-label {
+ display: block;
+ font-size: 14px;
+ font-weight: 500;
+ color: #262626;
+ margin-bottom: 8px;
+ }
+ }
+}
+
+/* 卡片行样式 */
+.cards-row {
+ margin-bottom: 16px;
+ flex-shrink: 0; /* 防止被压缩 */
+}
+
+/* 员工信息卡片 */
+.info-card {
+ height: 255px; /* 设置固定高度 */
+
+ .ant-card-body {
+ height: calc(100% - 57px);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden; /* 防止内容溢出 */
+ }
+
+ .employee-info {
+ display: flex;
+ align-items: center;
+ margin-bottom: 16px;
+ flex-shrink: 0;
+
+ .employee-details {
+ margin-left: 16px;
+
+ h3 {
+ font-size: 18px;
+ font-weight: 600;
+ color: #262626;
+ margin: 0 0 4px 0;
+ }
+
+ p {
+ font-size: 14px;
+ color: #8c8c8c;
+ margin: 0;
+ }
+ }
+ }
+
+ .employee-meta {
+ flex: 1;
+ overflow-y: auto; /* 如果内容过多,添加滚动 */
+
+ .meta-item {
+ display: flex;
+ margin-bottom: 12px;
+
+ .meta-label {
+ font-size: 14px;
+ color: #8c8c8c;
+ width: 80px;
+ flex-shrink: 0;
+ }
+
+ span:last-child {
+ font-size: 14px;
+ color: #262626;
+ }
+ }
+ }
+}
+
+/* 考勤状态卡片 */
+.status-card {
+ height: 255px; /* 设置固定高度 */
+
+ .ant-card-body {
+ height: calc(100% - 57px);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ }
+
+ .status-info {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+
+ .status-badge {
+ display: flex;
+ align-items: center;
+ margin-bottom: 16px;
+ flex-shrink: 0;
+
+ .status-dot {
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+ background-color: #52c41a;
+ margin-right: 8px;
+ }
+
+ span {
+ font-size: 14px;
+ font-weight: 500;
+ color: #262626;
+ }
+ }
+
+ .status-details {
+ flex: 1;
+ overflow-y: auto;
+
+ p {
+ font-size: 14px;
+ color: #595959;
+ margin: 0 0 12px 0;
+ line-height: 1.4;
+ }
+ }
+ }
+}
+
+/* 操作按钮卡片 */
+.action-card {
+ height: 255px; /* 设置固定高度 */
+
+ .ant-card-body {
+ height: calc(100% - 57px);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ }
+
+ .action-buttons {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+
+ .ant-row {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ }
+
+ .ant-col:last-child {
+ margin-top: auto;
+ }
+
+ .ant-btn {
+ font-size: 12px;
+ height: 36px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ }
+}
+
+/* 表格样式 */
+.table-section {
+ margin-bottom: 16px;
+ flex-shrink: 0;
+
+ .ant-table-thead > tr > th {
+ background-color: #fafafa;
+ font-weight: 500;
+ }
+
+ .ant-table-tbody > tr:hover > td {
+ background-color: #f5f5f5;
+ }
+
+ /* 表格内部滚动 */
+ .ant-table-body {
+ max-height: 400px;
+ overflow-y: auto;
+ }
+}
+
+/* 排班数据卡片 */
+.schedule-card {
+ height: 280px; /* 设置固定高度 */
+
+ .ant-card-body {
+ height: calc(100% - 57px);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ }
+
+ .schedule-info {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+
+ .schedule-item {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 9px;
+ font-size: 14px;
+
+ span:first-child {
+ color: #8c8c8c;
+ }
+
+ span:last-child {
+ font-weight: 500;
+ color: #262626;
+ }
+ }
+
+ .schedule-button {
+ margin-top: auto;
+ // padding-top: 16px;
+ // border-top: 1px solid #f0f0f0;
+ flex-shrink: 0;
+ }
+ }
+}
+
+/* 考勤统计卡片 */
+.statistics-card {
+ height: 280px; /* 设置固定高度 */
+
+ .ant-card-body {
+ height: calc(100% - 57px);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ }
+
+ .statistics-info {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+
+ .stat-item {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 9px;
+ font-size: 14px;
+
+ span:first-child {
+ color: #8c8c8c;
+ }
+
+ span:last-child {
+ font-weight: 500;
+ color: #262626;
+ }
+ }
+
+ .stat-button {
+ margin-top: auto;
+ // padding-top: 16px;
+ // border-top: 1px solid #f0f0f0;
+ flex-shrink: 0;
+ }
+ }
+}
+
+/* 同步信息卡片 */
+.sync-card {
+ height: 280px; /* 设置固定高度 */
+
+ .ant-card-body {
+ height: calc(100% - 57px);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ }
+
+ .sync-info {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+
+ .sync-item {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 12px;
+ font-size: 14px;
+
+ span:first-child {
+ color: #8c8c8c;
+ }
+
+ span:last-child {
+ font-weight: 500;
+ color: #262626;
+ }
+ }
+
+ .success-text {
+ color: #52c41a !important;
+ }
+
+ .sync-buttons {
+ margin-top: auto;
+ padding-top: 16px;
+ border-top: 1px solid #f0f0f0;
+ flex-shrink: 0;
+ }
+ }
+}
+
+/* 图表区域样式 */
+.chart-section {
+ flex-shrink: 0;
+
+ .chart-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 16px;
+
+ h3 {
+ font-size: 18px;
+ font-weight: 600;
+ color: #262626;
+ margin: 0;
+ }
+
+ .chart-actions {
+ display: flex;
+ gap: 8px;
+ }
+ }
+
+ .chart-container {
+ height: 320px;
+ width: 100%;
+ }
+}
+
+/* 响应式样式 */
+@media (max-width: 768px) {
+ .attendance-details-page {
+ padding: 16px;
+ max-height: 90vh;
+ overflow-y: auto;
+ }
+
+ .info-card,
+ .status-card,
+ .action-card,
+ .schedule-card,
+ .statistics-card,
+ .sync-card {
+ height: auto; /* 移动端自适应高度 */
+ min-height: 200px;
+ }
+
+ .chart-header {
+ flex-direction: column;
+ align-items: stretch !important;
+
+ .chart-actions {
+ margin-top: 12px;
+ justify-content: center;
+ }
+ }
+
+ .employee-info {
+ flex-direction: column;
+ text-align: center;
+
+ .employee-details {
+ margin-left: 0 !important;
+ margin-top: 12px;
+ }
+ }
+
+ .chart-container {
+ height: 250px; /* 移动端降低图表高度 */
+ }
+}
+
+/* Firefox 滚动条样式 */
+.attendance-details-page {
+ scrollbar-width: thin;
+ scrollbar-color: #c1c1c1 #f1f1f1;
+}
\ No newline at end of file