应急消防点页面

main
wangyunfei 1 day ago
parent 6101a571db
commit 50daab4c6d

@ -1,12 +1,26 @@
import React, { useState } from 'react';
import { Button } from 'antd';
import { LeftOutlined, RightOutlined } from '@ant-design/icons';
import { Button, DatePicker, Select, InputNumber, Table, Tag, Avatar } from 'antd';
import {
CalendarOutlined,
TeamOutlined,
UserOutlined,
PlusOutlined,
EditOutlined,
DeleteOutlined
} from '@ant-design/icons';
import moment from 'moment';
import styles from './DutySchedule.less';
const { RangePicker } = DatePicker;
const { Option } = Select;
const DutySchedule = () => {
// 当前周的起始日期
const [currentWeekStart, setCurrentWeekStart] = useState(moment().startOf('week'));
const [selectedRange, setSelectedRange] = useState([moment(), moment()]);
const [shiftType, setShiftType] = useState('早班');
const [personCount, setPersonCount] = useState(2);
const [specialty, setSpecialty] = useState('无特殊要求');
// 生成当前周的日期数组
const getWeekDates = (startDate) => {
@ -109,146 +123,399 @@ const DutySchedule = () => {
const cellData = getCellData(date, shift);
if (cellData.length === 0) return '';
// 如果有多个人,取第一个人的状态
const status = cellData[0].status;
// 检查是否所有人状态相同
const allSameStatus = cellData.every(item => item.status === status);
if (allSameStatus) {
return styles[`bg_${status}`];
}
// 如果状态不同,返回混合状态类名
return styles.bg_mixed;
};
// 底部表格数据
const tableColumns = [
{
title: '日期',
dataIndex: 'date',
key: 'date',
width: 120,
},
{
title: '班次',
dataIndex: 'shift',
key: 'shift',
width: 150,
},
{
title: '值班人员',
dataIndex: 'person',
key: 'person',
width: 100,
},
{
title: '职位',
dataIndex: 'position',
key: 'position',
width: 120,
},
{
title: '专业技能',
dataIndex: 'skills',
key: 'skills',
width: 150,
},
{
title: '岗位类型',
dataIndex: 'type',
key: 'type',
width: 100,
},
{
title: '联系方式',
dataIndex: 'contact',
key: 'contact',
width: 120,
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 80,
render: (status) => {
const colorMap = {
'请假': 'error',
'待岗': 'warning',
'在岗': 'success'
};
return <Tag color={colorMap[status]}>{status}</Tag>;
}
},
{
title: '操作',
key: 'action',
width: 150,
render: (_, record) => (
<div className={styles.tableActions}>
<Button type="link" size="small">编辑</Button>
<Button type="link" size="small" danger>删除</Button>
</div>
),
},
];
const tableData = [
{
key: '1',
date: '2025-10-13',
shift: '早班 (08:00-16:00)',
person: '钱居西',
position: '应急部门专家',
skills: '网格安全、系统运维',
type: '常规岗',
contact: '15086756708',
status: '请假'
},
{
key: '2',
date: '2025-10-12',
shift: '中班 (16:00-24:00)',
person: '冯俊',
position: '数据分析师',
skills: '数据分析、风险评估',
type: '专业岗',
contact: '15070198237',
status: '待岗'
},
{
key: '3',
date: '2025-10-10',
shift: '晚班 (00:00-08:00)',
person: '何乐',
position: '系统管理员',
skills: '服务器管理、网络管理',
type: '常规岗',
contact: '13726421306',
status: '在岗'
},
];
// 可用值班人员数据
const availablePersons = [
{ id: 1, name: '李华', dept: '信息安全', skills: '网络运维' },
{ id: 2, name: '王方', dept: '运营部', skills: '网络运维' },
{ id: 3, name: '孙敏', dept: '系统管理', skills: '由信息部' },
];
return (
<div className={styles.container}>
{/* 页面标题 */}
<div className={styles.header}>
<div className={styles.titleBar}></div>
<h2 className={styles.title}>值班排班表</h2>
</div>
<div className={styles.pageContainer}>
{/* 顶部区域 */}
<div className={styles.topSection}>
{/* 左侧:排班表 */}
<div className={styles.scheduleSection}>
<div className={styles.sectionHeader}>
<div className={styles.titleBar}></div>
<h2 className={styles.sectionTitle}>值班排班表</h2>
</div>
{/* 控制栏 */}
<div className={styles.toolbar}>
<div className={styles.toolbarLeft}>
<div className={styles.legend}>
<span className={styles.legendItem}>
<span className={`${styles.legendDot} ${styles.onduty}`}></span>
在岗
</span>
<span className={styles.legendItem}>
<span className={`${styles.legendDot} ${styles.leave}`}></span>
休假
</span>
<span className={styles.legendItem}>
<span className={`${styles.legendDot} ${styles.vacation}`}></span>
请假
</span>
<span className={styles.legendItem}>
<span className={`${styles.legendDot} ${styles.none}`}></span>
暂无安排
</span>
</div>
</div>
<div className={styles.toolbarRight}>
<span className={styles.dateRange}>
{currentWeekStart.format('YYYY-M-D')} {moment(currentWeekStart).add(6, 'days').format('YYYY-M-D')}
</span>
<div className={styles.weekNav}>
<Button onClick={handlePrevWeek} size="small" className={styles.navButton}>
上周
</Button>
<Button onClick={handleThisWeek} size="small" className={styles.navButtonActive}>
本周
</Button>
<Button onClick={handleNextWeek} size="small" className={styles.navButton}>
下周
</Button>
</div>
</div>
</div>
{/* 排班表格 */}
<div className={styles.scheduleTable}>
<table className={styles.table}>
<thead>
<tr>
<th className={styles.shiftHeader}>日期/班次</th>
{weekDates.map((date, index) => (
<th key={index} className={styles.dayHeader}>
<div className={styles.dayName}>
{['周一', '周二', '周三', '周四', '周五', '周六', '周日'][index]}
</div>
<div className={styles.dayDate}>{date.format('M/D')}</div>
</th>
))}
</tr>
</thead>
<tbody>
{/* 早班 */}
<tr>
<td className={styles.shiftCell}>
<div className={styles.shiftName}>早班</div>
<div className={styles.shiftTime}>08:00-16:00</div>
</td>
{weekDates.map((date, index) => (
<td key={index} className={`${styles.scheduleCell} ${getCellClassName(date, 'morning')}`}>
{renderCell(date, 'morning')}
</td>
))}
</tr>
{/* 中班 */}
<tr>
<td className={styles.shiftCell}>
<div className={styles.shiftName}>中班</div>
<div className={styles.shiftTime}>16:00-24:00</div>
</td>
{weekDates.map((date, index) => (
<td key={index} className={`${styles.scheduleCell} ${getCellClassName(date, 'middle')}`}>
{renderCell(date, 'middle')}
</td>
))}
</tr>
{/* 顶部控制栏 */}
<div className={styles.toolbar}>
<div className={styles.toolbarLeft}>
<div className={styles.legend}>
<span className={styles.legendItem}>
<span className={`${styles.legendDot} ${styles.onduty}`}></span>
在岗
</span>
<span className={styles.legendItem}>
<span className={`${styles.legendDot} ${styles.leave}`}></span>
休假
</span>
<span className={styles.legendItem}>
<span className={`${styles.legendDot} ${styles.vacation}`}></span>
请假
</span>
<span className={styles.legendItem}>
<span className={`${styles.legendDot} ${styles.none}`}></span>
暂无安排
</span>
{/* 晚班 */}
<tr>
<td className={styles.shiftCell}>
<div className={styles.shiftName}>晚班</div>
<div className={styles.shiftTime}>00:00-08:00</div>
</td>
{weekDates.map((date, index) => (
<td key={index} className={`${styles.scheduleCell} ${getCellClassName(date, 'evening')}`}>
{renderCell(date, 'evening')}
</td>
))}
</tr>
</tbody>
</table>
</div>
</div>
<div className={styles.toolbarRight}>
<span className={styles.dateRange}>
{currentWeekStart.format('YYYY-MM-DD')} {moment(currentWeekStart).add(6, 'days').format('YYYY-MM-DD')}
</span>
<div className={styles.weekNav}>
<Button onClick={handlePrevWeek} size="small" className={styles.navButton}>
上周
</Button>
<Button onClick={handleThisWeek} size="small" type="primary" className={styles.navButtonActive}>
本周
</Button>
<Button onClick={handleNextWeek} size="small" className={styles.navButton}>
下周
</Button>
{/* 右侧区域 */}
<div className={styles.rightSection}>
{/* 统计卡片 */}
<div className={styles.statsCards}>
<div className={styles.statCard}>
<div className={styles.statValue}>24</div>
<div className={styles.statLabel}>值班人员</div>
</div>
<div className={styles.statCard}>
<div className={styles.statValue}>156</div>
<div className={styles.statLabel}>本月班期</div>
</div>
<div className={styles.statCard}>
<div className={styles.statValue}>12</div>
<div className={styles.statLabel}>待派人</div>
</div>
<div className={styles.statCard}>
<div className={styles.statValue}>11</div>
<div className={styles.statLabel}>调班申请</div>
</div>
</div>
{/* 排班数设置 */}
<div className={styles.settingPanel}>
<div className={styles.panelHeader}>
<div className={styles.titleBar}></div>
<h3 className={styles.panelTitle}>排班数设置</h3>
</div>
<div className={styles.settingForm}>
<div className={styles.formItem}>
<label className={styles.formLabel}>选择排班</label>
<RangePicker
className={styles.formInput}
placeholder={['开始日期', '结束日期']}
format="YYYY/MM/DD"
suffixIcon={<CalendarOutlined />}
/>
</div>
<div className={styles.formItem}>
<label className={styles.formLabel}>日期</label>
<RangePicker
className={styles.formInput}
placeholder={['2025/10/16', '2025/10/16']}
format="YYYY/MM/DD"
suffixIcon={<CalendarOutlined />}
/>
</div>
<div className={styles.formItem}>
<label className={styles.formLabel}>每日班次</label>
<Select
className={styles.formInput}
value={shiftType}
onChange={setShiftType}
>
<Option value="早班">早班 (8:00-16:00)</Option>
<Option value="中班">中班 (16:00-24:00)</Option>
<Option value="晚班">晚班 (00:00-08:00)</Option>
</Select>
</div>
<div className={styles.formItem}>
<label className={styles.formLabel}>每日人数</label>
<InputNumber
className={styles.formInput}
value={personCount}
onChange={setPersonCount}
min={1}
max={10}
/>
</div>
<div className={styles.formItem}>
<label className={styles.formLabel}>专业要求</label>
<Select
className={styles.formInput}
value={specialty}
onChange={setSpecialty}
>
<Option value="无特殊要求">无特殊要求</Option>
<Option value="网络运维">网络运维</Option>
<Option value="系统管理">系统管理</Option>
</Select>
</div>
<div className={styles.formActions}>
<Button type="primary" icon={<CalendarOutlined />} block>
生成排班计划
</Button>
</div>
</div>
{/* 可用值班人员 */}
<div className={styles.availablePersons}>
<div className={styles.personsHeader}>
<h4 className={styles.personsTitle}>可用值班人员</h4>
<Button type="primary" size="small" icon={<PlusOutlined />}>
添加
</Button>
</div>
<div className={styles.personsList}>
{availablePersons.map(person => (
<div key={person.id} className={styles.personCard}>
<Avatar
size={40}
style={{ backgroundColor: '#87d068' }}
icon={<UserOutlined />}
/>
<div className={styles.personInfo}>
<div className={styles.personName}>{person.name}</div>
<div className={styles.personMeta}>
{person.dept} · {person.skills}
</div>
</div>
<Button
type="primary"
size="small"
icon={<PlusOutlined />}
className={styles.addButton}
/>
</div>
))}
</div>
</div>
</div>
</div>
</div>
{/* 排班表格 */}
<div className={styles.scheduleTable}>
<table className={styles.table}>
<thead>
<tr>
<th className={styles.shiftHeader}>日期/班次</th>
<th className={styles.dayHeader}>
<div className={styles.dayName}>周一</div>
<div className={styles.dayDate}>{weekDates[0].format('MM/DD')}</div>
</th>
<th className={styles.dayHeader}>
<div className={styles.dayName}>周二</div>
<div className={styles.dayDate}>{weekDates[1].format('MM/DD')}</div>
</th>
<th className={styles.dayHeader}>
<div className={styles.dayName}>周三</div>
<div className={styles.dayDate}>{weekDates[2].format('MM/DD')}</div>
</th>
<th className={styles.dayHeader}>
<div className={styles.dayName}>周四</div>
<div className={styles.dayDate}>{weekDates[3].format('MM/DD')}</div>
</th>
<th className={styles.dayHeader}>
<div className={styles.dayName}>周五</div>
<div className={styles.dayDate}>{weekDates[4].format('MM/DD')}</div>
</th>
<th className={styles.dayHeader}>
<div className={styles.dayName}>周六</div>
<div className={styles.dayDate}>{weekDates[5].format('MM/DD')}</div>
</th>
<th className={styles.dayHeader}>
<div className={styles.dayName}>周日</div>
<div className={styles.dayDate}>{weekDates[6].format('MM/DD')}</div>
</th>
</tr>
</thead>
<tbody>
{/* 早班 */}
<tr>
<td className={styles.shiftCell}>
<div className={styles.shiftName}>早班</div>
<div className={styles.shiftTime}>08:00-16:00</div>
</td>
{weekDates.map((date, index) => (
<td key={index} className={`${styles.scheduleCell} ${getCellClassName(date, 'morning')}`}>
{renderCell(date, 'morning')}
</td>
))}
</tr>
{/* 中班 */}
<tr>
<td className={styles.shiftCell}>
<div className={styles.shiftName}>中班</div>
<div className={styles.shiftTime}>16:00-24:00</div>
</td>
{weekDates.map((date, index) => (
<td key={index} className={`${styles.scheduleCell} ${getCellClassName(date, 'middle')}`}>
{renderCell(date, 'middle')}
</td>
))}
</tr>
{/* 晚班 */}
<tr>
<td className={styles.shiftCell}>
<div className={styles.shiftName}>晚班</div>
<div className={styles.shiftTime}>00:00-08:00</div>
</td>
{weekDates.map((date, index) => (
<td key={index} className={`${styles.scheduleCell} ${getCellClassName(date, 'evening')}`}>
{renderCell(date, 'evening')}
</td>
))}
</tr>
</tbody>
</table>
{/* 底部:近期值班信息人员列表 */}
<div className={styles.bottomSection}>
<div className={styles.sectionHeader}>
<div className={styles.titleBar}></div>
<h2 className={styles.sectionTitle}>近期值班信息人员列表</h2>
</div>
<div className={styles.tableHeader}>
<Button type="primary" icon={<PlusOutlined />}>
添加人员
</Button>
</div>
<Table
columns={tableColumns}
dataSource={tableData}
pagination={{
total: 48,
pageSize: 3,
current: 1,
showSizeChanger: false,
showQuickJumper: true,
showTotal: (total) => `${total}`
}}
className={styles.personTable}
/>
</div>
</div>
);

@ -1,296 +1,611 @@
.container {
padding: 20px;
background: #fff;
// 整体页面容器
.pageContainer {
width: 100%;
height: 100vh;
}
.header {
display: flex;
align-items: center;
margin-bottom: 20px;
.titleBar {
width: 3px;
height: 16px;
background: #2E4CD4;
margin-right: 12px;
}
.title {
margin: 0;
font-size: 14px;
font-weight: 500;
color: #333;
}
}
.toolbar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 0 10px;
.toolbarLeft {
flex: 1;
}
.toolbarRight {
display: flex;
align-items: center;
gap: 15px;
}
}
// 图例样式
.legend {
padding: 20px;
background: #F0F2F5;
display: flex;
flex-direction: column;
gap: 20px;
overflow: hidden;
.legendItem {
// 顶部区域 (60%高度)
.topSection {
height: 60%;
display: flex;
align-items: center;
font-size: 13px;
color: #666;
gap: 6px;
}
.legendDot {
width: 12px;
height: 12px;
border-radius: 2px;
display: inline-block;
&.onduty {
background: #D4F4DD;
}
&.leave {
background: #FFE7BA;
}
&.vacation {
background: #FFD6E0;
gap: 20px;
// 左侧排班表区域 (55%宽度)
.scheduleSection {
width: 55%;
background: #fff;
border-radius: 8px;
padding: 20px;
display: flex;
flex-direction: column;
overflow: hidden;
.sectionHeader {
display: flex;
align-items: center;
margin-bottom: 16px;
flex-shrink: 0;
.titleBar {
width: 3px;
height: 16px;
background: #2E4CD4;
margin-right: 12px;
}
.sectionTitle {
margin: 0;
font-size: 16px;
font-weight: 500;
color: #333;
}
}
// 控制栏
.toolbar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
padding: 0 8px;
flex-shrink: 0;
.toolbarLeft {
flex: 1;
.legend {
display: flex;
gap: 16px;
.legendItem {
display: flex;
align-items: center;
font-size: 12px;
color: #666;
gap: 6px;
.legendDot {
width: 10px;
height: 10px;
border-radius: 2px;
display: inline-block;
&.onduty {
background: #D4F4DD;
}
&.leave {
background: #FFE7BA;
}
&.vacation {
background: #FFD6E0;
}
&.none {
background: #E8E8E8;
}
}
}
}
}
.toolbarRight {
display: flex;
align-items: center;
gap: 12px;
.dateRange {
font-size: 12px;
color: #666;
}
.weekNav {
display: flex;
gap: 0;
border: 1px solid #d9d9d9;
border-radius: 2px;
overflow: hidden;
.navButton {
border: none;
border-radius: 0;
background: #fff;
color: #666;
height: 28px;
font-size: 12px;
padding: 0 12px;
border-right: 1px solid #d9d9d9;
&:last-child {
border-right: none;
}
&:hover {
background: #f5f5f5;
color: #333;
}
}
.navButtonActive {
background: #2E4CD4 !important;
color: #fff !important;
border: none;
&:hover {
background: #1e3bb8 !important;
}
}
}
}
}
// 排班表格
.scheduleTable {
flex: 1;
overflow: auto;
border: 1px solid #E5E5E5;
border-radius: 4px;
.table {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
th, td {
border: 1px solid #E5E5E5;
text-align: center;
vertical-align: middle;
}
thead {
background: #FAFAFA;
position: sticky;
top: 0;
z-index: 10;
th {
padding: 10px 6px;
font-weight: 500;
color: #333;
font-size: 12px;
}
}
tbody {
td {
padding: 0;
height: 100px;
}
}
// 第一列(班次列)
.shiftHeader {
width: 100px;
background: #FAFAFA;
color: #666;
}
.shiftCell {
background: #FAFAFA;
padding: 12px 8px !important;
.shiftName {
font-size: 13px;
font-weight: 500;
color: #333;
margin-bottom: 4px;
}
.shiftTime {
font-size: 11px;
color: #999;
}
}
// 日期表头
.dayHeader {
width: calc((100% - 100px) / 7);
.dayName {
font-size: 12px;
color: #333;
margin-bottom: 3px;
}
.dayDate {
font-size: 11px;
color: #999;
font-weight: normal;
}
}
// 排班单元格
.scheduleCell {
position: relative;
padding: 0 !important;
&.bg_onduty {
background: #D4F4DD;
}
&.bg_leave {
background: #FFE7BA;
}
&.bg_vacation {
background: #FFD6E0;
}
&.bg_none {
background: #F5F5F5;
}
&.bg_mixed {
background: linear-gradient(135deg, #D4F4DD 50%, #FFD6E0 50%);
}
.emptyCell {
width: 100%;
height: 100px;
}
.cellContent {
width: 100%;
height: 100px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 4px;
padding: 8px;
.personItem {
display: flex;
flex-direction: column;
align-items: center;
gap: 2px;
.personName {
font-size: 12px;
color: #333;
font-weight: 500;
}
.statusTag {
font-size: 10px;
padding: 2px 5px;
border-radius: 2px;
&.onduty {
color: #52C41A;
}
&.leave {
color: #FA8C16;
}
&.vacation {
color: #F5222D;
}
&.none {
color: transparent;
}
}
}
}
}
}
}
}
&.none {
background: #E8E8E8;
// 右侧区域 (45%宽度)
.rightSection {
width: 45%;
display: flex;
flex-direction: column;
gap: 20px;
overflow: hidden;
// 统计卡片区域
.statsCards {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
flex-shrink: 0;
.statCard {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 8px;
padding: 16px;
text-align: center;
color: #fff;
&:nth-child(1) {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
&:nth-child(2) {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
&:nth-child(3) {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}
&:nth-child(4) {
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
}
.statValue {
font-size: 28px;
font-weight: bold;
margin-bottom: 4px;
line-height: 1;
}
.statLabel {
font-size: 12px;
opacity: 0.9;
}
}
}
// 排班设置面板
.settingPanel {
flex: 1;
background: #fff;
border-radius: 8px;
padding: 20px;
overflow: auto;
display: flex;
flex-direction: column;
.panelHeader {
display: flex;
align-items: center;
margin-bottom: 16px;
flex-shrink: 0;
.titleBar {
width: 3px;
height: 16px;
background: #2E4CD4;
margin-right: 12px;
}
.panelTitle {
margin: 0;
font-size: 16px;
font-weight: 500;
color: #333;
}
}
// 设置表单
.settingForm {
margin-bottom: 20px;
flex-shrink: 0;
.formItem {
margin-bottom: 16px;
.formLabel {
display: block;
font-size: 13px;
color: #666;
margin-bottom: 8px;
}
.formInput {
width: 100%;
}
}
.formActions {
margin-top: 20px;
}
}
// 可用人员列表
.availablePersons {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
.personsHeader {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
flex-shrink: 0;
.personsTitle {
margin: 0;
font-size: 14px;
font-weight: 500;
color: #333;
}
}
.personsList {
flex: 1;
overflow: auto;
.personCard {
display: flex;
align-items: center;
gap: 12px;
padding: 12px;
border: 1px solid #E5E5E5;
border-radius: 6px;
margin-bottom: 8px;
transition: all 0.3s;
&:hover {
border-color: #2E4CD4;
box-shadow: 0 2px 8px rgba(46, 76, 212, 0.1);
}
.personInfo {
flex: 1;
.personName {
font-size: 13px;
color: #333;
font-weight: 500;
margin-bottom: 4px;
}
.personMeta {
font-size: 11px;
color: #999;
}
}
.addButton {
flex-shrink: 0;
}
}
}
}
}
}
}
}
// 日期范围和周导航
.dateRange {
font-size: 13px;
color: #666;
}
.weekNav {
display: flex;
gap: 0;
border: 1px solid #d9d9d9;
border-radius: 2px;
overflow: hidden;
.navButton {
border: none;
border-radius: 0;
// 底部区域 (40%高度)
.bottomSection {
height: 40%;
background: #fff;
color: #666;
height: 28px;
font-size: 13px;
border-right: 1px solid #d9d9d9;
&:last-child {
border-right: none;
}
&:hover {
background: #f5f5f5;
color: #333;
}
}
.navButtonActive {
background: #2E4CD4 !important;
color: #fff !important;
border: none;
&:hover {
background: #1e3bb8 !important;
}
}
}
// 表格样式
.scheduleTable {
width: 100%;
overflow-x: auto;
border: 1px solid #E5E5E5;
border-radius: 4px;
}
.table {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
th, td {
border: 1px solid #E5E5E5;
text-align: center;
vertical-align: middle;
}
// 表头样式
thead {
background: #FAFAFA;
th {
padding: 12px 8px;
font-weight: 500;
color: #333;
font-size: 13px;
}
}
tbody {
td {
padding: 0;
height: 120px;
}
}
}
// 第一列(班次列)样式
.shiftHeader {
width: 140px;
background: #FAFAFA;
color: #666;
}
.shiftCell {
background: #FAFAFA;
padding: 15px 10px !important;
.shiftName {
font-size: 14px;
font-weight: 500;
color: #333;
margin-bottom: 5px;
}
.shiftTime {
font-size: 12px;
color: #999;
}
}
// 日期表头
.dayHeader {
width: calc((100% - 140px) / 7);
.dayName {
font-size: 13px;
color: #333;
margin-bottom: 4px;
}
.dayDate {
font-size: 12px;
color: #999;
font-weight: normal;
}
}
// 排班单元格
.scheduleCell {
position: relative;
padding: 0 !important;
// 不同状态的背景色
&.bg_onduty {
background: #D4F4DD;
}
&.bg_leave {
background: #FFE7BA;
}
&.bg_vacation {
background: #FFD6E0;
}
&.bg_none {
background: #F5F5F5;
}
&.bg_mixed {
background: linear-gradient(135deg, #D4F4DD 50%, #FFD6E0 50%);
}
}
.emptyCell {
width: 100%;
height: 120px;
}
.cellContent {
width: 100%;
height: 120px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 5px;
padding: 10px;
}
.personItem {
display: flex;
flex-direction: column;
align-items: center;
gap: 3px;
.personName {
font-size: 13px;
color: #333;
font-weight: 500;
}
.statusTag {
font-size: 11px;
padding: 2px 6px;
border-radius: 2px;
&.onduty {
color: #52C41A;
}
&.leave {
color: #FA8C16;
border-radius: 8px;
padding: 20px;
display: flex;
flex-direction: column;
overflow: hidden;
.sectionHeader {
display: flex;
align-items: center;
margin-bottom: 16px;
flex-shrink: 0;
.titleBar {
width: 3px;
height: 16px;
background: #2E4CD4;
margin-right: 12px;
}
.sectionTitle {
margin: 0;
font-size: 16px;
font-weight: 500;
color: #333;
}
}
&.vacation {
color: #F5222D;
.tableHeader {
margin-bottom: 12px;
flex-shrink: 0;
}
&.none {
color: transparent;
.personTable {
flex: 1;
overflow: hidden;
:global {
.ant-table-wrapper {
height: 100%;
display: flex;
flex-direction: column;
}
.ant-spin-nested-loading {
height: 100%;
display: flex;
flex-direction: column;
}
.ant-spin-container {
height: 100%;
display: flex;
flex-direction: column;
}
.ant-table {
flex: 1;
overflow: hidden;
}
.ant-table-container {
height: 100%;
display: flex;
flex-direction: column;
}
.ant-table-body {
flex: 1;
overflow: auto !important;
}
}
.tableActions {
display: flex;
gap: 8px;
justify-content: center;
}
}
}
}
// 响应式
@media screen and (max-width: 1400px) {
.table {
font-size: 12px;
}
.personName {
font-size: 12px !important;
}
.statusTag {
font-size: 10px !important;
@media screen and (max-width: 1600px) {
.pageContainer {
.topSection {
.scheduleSection {
.scheduleTable {
.table {
font-size: 11px;
tbody td {
height: 80px;
}
.scheduleCell {
.emptyCell {
height: 80px;
}
.cellContent {
height: 80px;
}
}
}
}
}
.rightSection {
.statsCards {
.statCard {
padding: 12px;
.statValue {
font-size: 24px;
}
.statLabel {
font-size: 11px;
}
}
}
}
}
}
}

@ -7,7 +7,7 @@ const EmergencyMap = () => {
<div className={styles.container}>
<Card>
<div style={{ textAlign: 'center', padding: '50px', fontSize: '18px' }}>
待开发一张
应急地
</div>
</Card>
</div>

@ -5,7 +5,7 @@ import Yjwz from './secondary_menu/yjwz';
import Yjdw from './secondary_menu/yjdw';
import Yjzj from './secondary_menu/yjzj';
import Yjssd from './secondary_menu/yjssd';
import Yjxf from './secondary_menu/yjxf';
import Yjxfd from './secondary_menu/yjxfd';
import Zbhy from './secondary_menu/zbhy';
const EmergencyResource = () => {
@ -21,8 +21,8 @@ const EmergencyResource = () => {
'应急队伍',
'应急专家',
'应急疏散点',
// '应急消防点',
// '周边医院'
'应急消防点',
'周边医院'
];
const renderContent = () => {
@ -37,10 +37,10 @@ const EmergencyResource = () => {
return <Yjzj />;
case '应急疏散点':
return <Yjssd />;
// case '应急消防点':
// return <Yjxf />;
// case '周边医院':
// return <Zbhy />;
case '应急消防点':
return <Yjxfd />;
case '周边医院':
return <Zbhy />;
default:
return <Yjzbry />;
}

@ -11,7 +11,7 @@ const { Option } = Select;
const Yjdw = () => {
const [loading, setLoading] = useState(false);
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [searchValue, setSearchValue] = useState('');
const [searchValue, setSearchValue] = useState(undefined);
const [pagination, setPagination] = useState({
current: 1,
pageSize: 10,
@ -238,7 +238,8 @@ const Yjdw = () => {
placeholder="请选择单位"
value={searchValue}
onChange={setSearchValue}
style={{width: 180, height: 30, borderRadius: 2}}
style={{width: 180}}
className={styles.customSelect}
allowClear
>
<Option value="危险化学品事故救援队">危险化学品事故救援队</Option>
@ -247,9 +248,8 @@ const Yjdw = () => {
</Select>
<Input
placeholder="请输入队伍名称"
// value={searchValue}
// onChange={setSearchValue}
style={{width: 180, height: 30, borderRadius: 2}}
style={{width: 180}}
className={styles.customInput}
allowClear
/>
<Button

@ -46,6 +46,33 @@
}
}
// 自定义 Select 样式
.customSelect {
:global {
.ant-select-selector {
height: 30px !important;
border-radius: 2px !important;
display: flex !important;
align-items: center !important;
}
.ant-select-selection-search-input {
height: 30px !important;
}
.ant-select-selection-item,
.ant-select-selection-placeholder {
line-height: 30px !important;
}
}
}
// 自定义 Input 样式
.customInput {
height: 30px !important;
border-radius: 2px !important;
}
// 自定义按钮样式
.customButton {
background-color: #2E4CD4 !important;

@ -11,7 +11,7 @@ const { Option } = Select;
const Yjxfd = () => {
const [loading, setLoading] = useState(false);
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [searchValue, setSearchValue] = useState('');
const [searchValue, setSearchValue] = useState(undefined);
const [pagination, setPagination] = useState({
current: 1,
pageSize: 10,
@ -26,62 +26,80 @@ const Yjxfd = () => {
{
key: '1',
number: '01',
unitName: '文登市兴文新材料有限公司',
name: '国云海',
position: '生产班长',
mobile: '17898786567',
email: '1878967633@qq.com',
dutyTime: '夜班',
fireName: '消防点一',
waterPointName: '消防池 01',
hydrantCount: 97,
hydrantLocation: '一楼走廊',
range: 97,
waterType: '企业消防水池',
personInCharge: '冯钰涛',
fireImage: '点击查看图片',
remarks: '无',
},
{
key: '2',
number: '02',
unitName: '文登市兴文新材料有限公司',
name: '陈志强',
position: '生产班长',
mobile: '17898786567',
email: '1878967633@qq.com',
dutyTime: '白班',
fireName: '消防点二',
waterPointName: '消防池 02',
hydrantCount: 96,
hydrantLocation: '二楼走廊',
range: 96,
waterType: '企业消防水池',
personInCharge: '周静',
fireImage: '点击查看图片',
remarks: '备注二二',
},
{
key: '3',
number: '03',
unitName: '合湾新材科技有限公司',
name: '侯文涛',
position: '班长',
mobile: '17898786567',
email: '1878967633@qq.com',
dutyTime: '白班',
fireName: '消防点三',
waterPointName: '消防池 03',
hydrantCount: 91,
hydrantLocation: '三楼图书馆门口',
range: 91,
waterType: '企业消防水池',
personInCharge: '何能',
fireImage: '点击查看图片',
remarks: '备注三三',
},
{
key: '4',
number: '04',
unitName: '山东万图高分子材料股份有限公司',
name: '宋东',
position: '班长',
mobile: '17898786567',
email: '1878967633@qq.com',
dutyTime: '夜班',
fireName: '消防点四',
waterPointName: '消防池 04',
hydrantCount: 59,
hydrantLocation: '三楼应急通道口',
range: 59,
waterType: '企业消防水池',
personInCharge: '冯新',
fireImage: '点击查看图片',
remarks: '备注四四',
},
{
key: '5',
number: '05',
unitName: '合鸿新材科技有限公司',
name: '王一声',
position: '班长',
mobile: '17898786567',
email: '1878967633@qq.com',
dutyTime: '夜班',
fireName: '消防点五',
waterPointName: '消防池 05',
hydrantCount: 50,
hydrantLocation: '负一层东侧走廊',
range: 50,
waterType: '企业消防水池',
personInCharge: '赵俊英',
fireImage: '点击查看图片',
remarks: '备注五五',
},
{
key: '6',
number: '06',
unitName: '山东万图高分子材料股份有限公司',
name: '赵小敏',
position: '班长',
mobile: '17898786567',
email: '1878987633@qq.com',
dutyTime: '夜班',
fireName: '消防点六',
waterPointName: '消防池 06',
hydrantCount: 48,
hydrantLocation: '四楼c西侧走廊',
range: 48,
waterType: '企业消防水池',
personInCharge: '赵中琏',
fireImage: '点击查看图片',
remarks: '备注六六',
},
]);
@ -94,39 +112,66 @@ const Yjxfd = () => {
width: 80,
},
{
title: '单位名称',
dataIndex: 'unitName',
key: 'unitName',
width: 200,
title: '消防点名称',
dataIndex: 'fireName',
key: 'fireName',
width: 120,
},
{
title: '姓名',
dataIndex: 'name',
key: 'name',
width: 100,
title: '消防取水点名称',
dataIndex: 'waterPointName',
key: 'waterPointName',
width: 140,
},
{
title: '职务',
dataIndex: 'position',
key: 'position',
width: 120,
title: '消防栓数量',
dataIndex: 'hydrantCount',
key: 'hydrantCount',
width: 110,
},
{
title: '消防栓位置',
dataIndex: 'hydrantLocation',
key: 'hydrantLocation',
width: 150,
},
{
title: '射程',
dataIndex: 'range',
key: 'range',
width: 80,
},
{
title: '手机号',
dataIndex: 'mobile',
key: 'mobile',
width: 130,
title: '消防栓用水类型',
dataIndex: 'waterType',
key: 'waterType',
width: 140,
},
{
title: '邮箱',
dataIndex: 'email',
key: 'email',
width: 180,
title: '负责人',
dataIndex: 'personInCharge',
key: 'personInCharge',
width: 100,
},
{
title: '消防点图片',
dataIndex: 'fireImage',
key: 'fireImage',
width: 120,
render: (text) => (
<Button
type="link"
size="small"
onClick={() => message.info('查看图片功能待实现')}
>
{text}
</Button>
),
},
{
title: '值班时间',
dataIndex: 'dutyTime',
key: 'dutyTime',
title: '备注',
dataIndex: 'remarks',
key: 'remarks',
width: 100,
},
{
@ -191,14 +236,14 @@ const Yjxfd = () => {
// 编辑处理
const handleEdit = (record) => {
message.info(`编辑 ${record.name} 的信息`);
message.info(`编辑 ${record.fireName} 的信息`);
};
// 删除处理
const handleDelete = (record) => {
Modal.confirm({
title: '确认删除',
content: `确定要删除 ${record.name} 吗?`,
content: `确定要删除 ${record.fireName} 吗?`,
onOk() {
setDataSource(dataSource.filter(item => item.key !== record.key));
message.success('删除成功');
@ -212,28 +257,37 @@ const Yjxfd = () => {
};
return (
<div className={styles.container}>
<div className={styles.containerYJXFD}>
{/* 页面标题 */}
<div className={styles.header}>
<div className={styles.titleBar}></div>
<h2 className={styles.title}>应急消防</h2>
<h2 className={styles.title}>应急消防</h2>
</div>
{/* 搜索和操作区域 */}
<div className={styles.searchBar}>
<div className={styles.searchLeft}>
<Select
placeholder="请选择单位名称"
placeholder="请选择消防点"
value={searchValue}
onChange={setSearchValue}
style={{width: 180, height: 30, borderRadius: 2}}
style={{width: 180}}
className={styles.customSelect}
allowClear
>
<Option value="文登市兴文新材料有限公司">文登市兴文新材料有限公司</Option>
<Option value="合湾新材科技有限公司">合湾新材科技有限公司</Option>
<Option value="山东万图高分子材料股份有限公司">山东万图高分子材料股份有限公司</Option>
<Option value="合鸿新材科技有限公司">合鸿新材科技有限公司</Option>
<Option value="消防点一">消防点一</Option>
<Option value="消防点二">消防点二</Option>
<Option value="消防点三">消防点三</Option>
<Option value="消防点四">消防点四</Option>
<Option value="消防点五">消防点五</Option>
<Option value="消防点六">消防点六</Option>
</Select>
<Input
placeholder="请输入消防点名称"
style={{width: 180}}
className={styles.customInput}
allowClear
/>
<Button
type="primary"
icon={<SearchOutlined />}
@ -253,14 +307,14 @@ const Yjxfd = () => {
>
新增
</Button>
<Button
{/* <Button
danger
style={{width: 70, height: 30, borderRadius: 2, display: 'flex', alignItems: 'center', justifyContent: 'center'}}
icon={<img src={iconsc} alt="delete" style={{width: 14, height: 14, marginTop: -2}}/>}
onClick={handleBatchDelete}
>
删除
</Button>
</Button> */}
</div>
</div>

@ -1,122 +1,165 @@
.container {
.containerYJXFD {
padding: 20px;
background: #f5f5f5;
min-height: 100vh;
background: #fff;
height:100vh;
}
.header {
margin-bottom: 20px;
display: flex;
align-items: center;
}
.titleBar {
width: 4px;
height: 20px;
background: #1890ff;
margin-right: 10px;
}
// background-color: pink;
margin-bottom: 15px;
.titleBar {
width: 3px;
height: 16px;
background: #2E4CD4;
margin-right: 12px;
}
.title {
margin: 0;
font-size: 18px;
font-weight: 500;
color: #333;
.title {
margin: 0;
font-size: 14px;
font-weight: 500;
color: #333;
}
}
.searchBar {
background: #fff;
padding: 20px;
border-radius: 6px;
margin-bottom: 20px;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.searchLeft {
display: flex;
align-items: center;
gap: 12px;
}
margin-bottom: 10px;
padding: 5px;
.searchRight {
display: flex;
align-items: center;
gap: 12px;
}
.customButton {
height: 30px !important;
border-radius: 2px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
}
.tableContainer {
background: #fff;
border-radius: 6px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.actionButtons {
display: flex;
gap: 8px;
}
.actionButtons .ant-btn-link {
padding: 0;
height: auto;
line-height: 1;
}
.actionButtons .ant-btn-link:hover {
background: transparent;
}
.searchLeft {
display: flex;
align-items: center;
gap: 12px;
}
// 覆盖全局按钮样式
:global(.ant-btn) {
height: 28px !important;
border-radius: 2px !important;
.searchRight {
display: flex;
align-items: center;
gap: 12px;
}
}
:global(.ant-select) {
.ant-select-selector {
height: 30px !important;
border-radius: 2px !important;
// 自定义 Select 样式
.customSelect {
:global {
.ant-select-selector {
height: 30px !important;
border-radius: 2px !important;
display: flex !important;
align-items: center !important;
}
.ant-select-selection-search-input {
height: 30px !important;
}
.ant-select-selection-item,
.ant-select-selection-placeholder {
line-height: 30px !important;
}
}
}
:global(.ant-input) {
// 自定义 Input 样式
.customInput {
height: 30px !important;
border-radius: 2px !important;
}
:global(.ant-table) {
.ant-table-thead > tr > th {
background: #fafafa;
font-weight: 500;
color: #333;
// 自定义按钮样式
.customButton {
background-color: #2E4CD4 !important;
border-color: #2E4CD4 !important;
border-radius: 2px !important;
height: 30px !important;
width: 75px;
display: flex !important;
align-items: center !important;
justify-content: center !important;
&:hover {
background-color: #1e3bb8 !important;
border-color: #1e3bb8 !important;
}
.ant-table-tbody > tr:hover > td {
background: #f5f5f5;
&:focus {
background-color: #2E4CD4 !important;
border-color: #2E4CD4 !important;
}
}
:global(.ant-pagination) {
margin-top: 16px;
text-align: right;
}
// // 所有按钮统一样式
// .ant-btn {
// border-radius: 4px !important;
// height: 28px !important;
// display: flex !important;
// align-items: center !important;
// justify-content: center !important;
// }
:global(.ant-pagination-item) {
border-radius: 2px;
.tableContainer {
background: #fff;
border-radius: 0px;
overflow: hidden;
.actionButtons {
display: flex;
gap: 8px;
font-size: 10px;
justify-content: center;
.ant-btn-link {
padding: 0;
height: auto;
font-size: 10px;
}
}
}
:global(.ant-pagination-prev),
:global(.ant-pagination-next) {
border-radius: 2px;
// 表格样式优化
.tableContainer {
:global {
.ant-table-thead > tr > th {
background: #F5F5FA;
font-weight: 500;
color: #333333;
font-size: 14px;
text-align: center;
}
.ant-table-tbody > tr > td {
color: #666666;
font-size: 13px;
text-align: center;
}
.ant-table-tbody > tr:hover > td {
background: #f5f5f5;
}
.ant-pagination {
margin-top: 10px;
text-align: right;
}
// 覆盖操作列按钮样式
.ant-btn.ant-btn-sm {
font-size: 13px !important;
height: 20px !important;
padding: 0px 4px !important;
}
.ant-btn-link.ant-btn-sm {
font-size: 13px !important;
height: auto !important;
padding: 0 !important;
}
}
}

Loading…
Cancel
Save