From d3d4a393c62cd4d90cafd6d6a7db783f5fe51fcc Mon Sep 17 00:00:00 2001 From: wangyunfei <1224056307@qq,com> Date: Fri, 31 Oct 2025 12:12:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=80=BC=E7=8F=AD=E6=97=A5=E5=BF=97=E8=AE=B0?= =?UTF-8?q?=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/DutyLog.js | 473 ++++++++++------ .../components/DutyLog.less | 509 ++++++++++++++---- 2 files changed, 703 insertions(+), 279 deletions(-) diff --git a/src/pages/business_emergencyDuty/components/DutyLog.js b/src/pages/business_emergencyDuty/components/DutyLog.js index 981d610..65eadb5 100644 --- a/src/pages/business_emergencyDuty/components/DutyLog.js +++ b/src/pages/business_emergencyDuty/components/DutyLog.js @@ -1,122 +1,144 @@ import React, { useState } from 'react'; -import { Input, Button, Select, message, Modal, DatePicker } from 'antd'; -import { SearchOutlined, PlusOutlined, DeleteOutlined } from '@ant-design/icons'; +import { Input, Button, Select, message, Modal, Tag } from 'antd'; +import { SearchOutlined, PlusOutlined } from '@ant-design/icons'; import StandardTable from '@/components/StandardTable'; import styles from './DutyLog.less'; -import iconsc from '@/assets/yjzygl/iconsc.svg'; const { Option } = Select; -const { RangePicker } = DatePicker; const DutyLog = () => { const [loading, setLoading] = useState(false); const [selectedRowKeys, setSelectedRowKeys] = useState([]); const [searchValue, setSearchValue] = useState(''); + const [eventType, setEventType] = useState(''); + const [eventStatus, setEventStatus] = useState(''); const [pagination, setPagination] = useState({ - current: 1, - pageSize: 10, - total: 15, - showSizeChanger: true, + current: 3, + pageSize: 5, + total: 48, + showSizeChanger: false, showQuickJumper: true, - showTotal: (total, range) => `共${total}条`, + showTotal: (total) => `共${total}条`, }); // 模拟数据 const [dataSource, setDataSource] = useState([ { key: '1', - number: '01', - logDate: '2025-10-28 08:00', - dutyPerson: '张三', - dutyType: '白班', - logContent: '正常巡检,未发现异常情况', - weather: '晴', - temperature: '18°C', - recorder: '张三', - status: '已提交', + time: '2025-10-19 15:35:27', + location: '义宾南区16号楼', + eventType: '交通事故', + description: '主干道发生交通事故,造成交通拥堵', + status: '已解决', }, { key: '2', - number: '02', - logDate: '2025-10-28 20:00', - dutyPerson: '李四', - dutyType: '夜班', - logContent: '夜间巡检,设备运行正常', - weather: '晴', - temperature: '12°C', - recorder: '李四', - status: '已提交', + time: '2025-10-15 13:44:41', + location: '中山南大街甲1号楼-1-5号附近', + eventType: '自然灾害', + description: '强风导致广告牌松动,存在安全隐患', + status: '待处理', }, { key: '3', - number: '03', - logDate: '2025-10-27 08:00', - dutyPerson: '王五', - dutyType: '白班', - logContent: '发现A区域照明设备故障,已报修', - weather: '多云', - temperature: '16°C', - recorder: '王五', - status: '已处理', + time: '2025-10-15 00:29:03', + location: '西辛南区66号(卧龙环岛东南角)', + eventType: '社会安全', + description: '商场内发生顾客纠纷,可能引发冲突', + status: '已解决', }, - ]); - - // 表格列配置 - const columns = [ { - title: '编号', - dataIndex: 'number', - key: 'number', - width: 80, + key: '4', + time: '2025-10-14 17:21:38', + location: '怡馨家园5号楼', + eventType: '自然灾害', + description: '强风导致广告牌松动,存在安全隐患', + status: '已解决', }, { - title: '记录时间', - dataIndex: 'logDate', - key: 'logDate', - width: 150, + key: '5', + time: '2025-10-15 02:30:41', + location: '站前南街', + eventType: '社会安全', + description: '商场内发生顾客纠纷,可能引发冲突', + status: '已解决', }, + ]); + + // 最近值班日志数据 + const recentLogs = [ { - title: '值班人员', - dataIndex: 'dutyPerson', - key: 'dutyPerson', - width: 120, + title: '设备故障报告', + time: '2023-04-17 14:45', + location: '3号机房', + description: '服务器温度异常升高,已启动备用设备..', + status: '预警', }, { - title: '值班类型', - dataIndex: 'dutyType', - key: 'dutyType', - width: 100, + title: '网络中断处理', + time: '2023-04-17 14:45', + location: '3号机房', + description: '主办公楼网络中断,已联系维修人员处理..', + status: '紧急', }, { - title: '日志内容', - dataIndex: 'logContent', - key: 'logContent', - width: 250, - ellipsis: true, + title: '日常巡检记录', + time: '2023-04-17 14:45', + location: '83号机房', + description: '完成日常安全巡检,所有设备运行正常...', + status: '常规', + }, + ]; + + // 事件类型分布数据 + const eventTypeData = [ + { name: '交通事故', value: 10, color: '#52C41A' }, + { name: '自然灾害', value: 15, color: '#FAAD14' }, + { name: '社会安全', value: 8, color: '#FF7A45' }, + { name: '电力故障', value: 5, color: '#F5222D' }, + { name: '火灾隐患', value: 3, color: '#CF1322' }, + { name: '设施故障', value: 7, color: '#1890FF' }, + ]; + + // 表格列配置 + const columns = [ + { + title: '时间', + dataIndex: 'time', + key: 'time', + width: 180, }, { - title: '天气', - dataIndex: 'weather', - key: 'weather', - width: 80, + title: '地点', + dataIndex: 'location', + key: 'location', + width: 200, }, { - title: '温度', - dataIndex: 'temperature', - key: 'temperature', - width: 80, + title: '事件类型', + dataIndex: 'eventType', + key: 'eventType', + width: 120, }, { - title: '记录人', - dataIndex: 'recorder', - key: 'recorder', - width: 100, + title: '事件描述', + dataIndex: 'description', + key: 'description', + ellipsis: true, }, { title: '状态', dataIndex: 'status', key: 'status', width: 100, + render: (status) => { + const colorMap = { + '已解决': 'success', + '待处理': 'warning', + '已处理': 'processing', + }; + return {status}; + }, }, { title: '操作', @@ -128,21 +150,16 @@ const DutyLog = () => { type="link" size="small" onClick={() => handleView(record)} + style={{ color: '#1890FF', padding: 0 }} > 查看 - @@ -167,29 +184,7 @@ const DutyLog = () => { // 查看处理 const handleView = (record) => { - message.info(`查看日志详情:${record.logContent}`); - }; - - // 批量删除处理 - const handleBatchDelete = () => { - if (selectedRowKeys.length === 0) { - message.warning('请选择要删除的数据'); - return; - } - Modal.confirm({ - title: '确认删除', - content: `确定要删除选中的 ${selectedRowKeys.length} 条数据吗?`, - onOk() { - setDataSource(dataSource.filter(item => !selectedRowKeys.includes(item.key))); - setSelectedRowKeys([]); - message.success('删除成功'); - }, - }); - }; - - // 编辑处理 - const handleEdit = (record) => { - message.info(`编辑日志记录`); + message.info(`查看日志详情:${record.description}`); }; // 删除处理 @@ -209,79 +204,223 @@ const DutyLog = () => { setPagination(pagination); }; - return ( -
- {/* 页面标题 */} -
-
-

值班日志记录

+ // 渲染状态标签 + const renderStatusTag = (status) => { + const statusConfig = { + '预警': { color: '#FF7A45', bg: '#FFF7E6' }, + '紧急': { color: '#F5222D', bg: '#FFF1F0' }, + '常规': { color: '#1890FF', bg: '#E6F7FF' }, + }; + const config = statusConfig[status] || { color: '#666', bg: '#F5F5F5' }; + return ( + + {status} + + ); + }; + + // 渲染饼图(简化版) + const renderPieChart = () => { + const total = eventTypeData.reduce((sum, item) => sum + item.value, 0); + let currentAngle = 0; + + return ( +
+ + {eventTypeData.map((item, index) => { + const percentage = (item.value / total) * 100; + const angle = (percentage / 100) * 360; + const largeArc = percentage > 50 ? 1 : 0; + + const x1 = 100 + 60 * Math.cos((currentAngle * Math.PI) / 180); + const y1 = 100 + 60 * Math.sin((currentAngle * Math.PI) / 180); + const x2 = 100 + 60 * Math.cos(((currentAngle + angle) * Math.PI) / 180); + const y2 = 100 + 60 * Math.sin(((currentAngle + angle) * Math.PI) / 180); + + const path = [ + `M 100 100`, + `L ${x1} ${y1}`, + `A 60 60 0 ${largeArc} 1 ${x2} ${y2}`, + `Z`, + ].join(' '); + + currentAngle += angle; + + return ( + + ); + })} + + +
+ {eventTypeData.map((item, index) => ( +
+ + {item.name} +
+ ))} +
+ ); + }; - {/* 搜索和操作区域 */} -
-
- - - + return ( +
+ {/* A块:顶部统计卡片 */} +
+
+
+
+
+
+
24
+
今日日志总数
+
-
- - +
+
+
+
+
+
5
+
紧急事件
+
+
+
+
+
+
+
+
16
+
已处理事件
+
+
+
+
+
+
+
+
5
+
待处理事件
+
- {/* 数据表格 */} -
- + {/* B块:主要内容区域 */} +
+ {/* 左块 */} +
+ {/* 上部分:事件类型分布 */} +
+
事件类型分布
+
+ {renderPieChart()} +
+
+ {/* 下部分:最近值班日志 */} +
+
最近值班日志
+
+ {recentLogs.map((log, index) => ( +
+
{log.title}
+
+ {log.time} + {log.location} +
+
{log.description}
+
+ {renderStatusTag(log.status)} +
+
+ ))} +
+
+
+ + {/* 右块:值班日志列表 */} +
+
值班日志列表
+ {/* 搜索和操作区域 */} +
+ } + className={styles.searchInput} + style={{ borderRadius: '2px' }} + /> + + + +
+ {/* 数据表格 */} +
+ +
+
); }; export default DutyLog; - diff --git a/src/pages/business_emergencyDuty/components/DutyLog.less b/src/pages/business_emergencyDuty/components/DutyLog.less index 1c6a136..decbbc8 100644 --- a/src/pages/business_emergencyDuty/components/DutyLog.less +++ b/src/pages/business_emergencyDuty/components/DutyLog.less @@ -1,127 +1,412 @@ .container { padding: 20px; - background: #fff; + background: #F5F5F5; height: 100vh; -} - -.header { display: flex; - align-items: center; - margin-bottom: 15px; - - .titleBar { - width: 3px; - height: 16px; - background: #2E4CD4; - margin-right: 12px; - } - - .title { - margin: 0; - font-size: 14px; - font-weight: 500; - color: #333; - } -} + flex-direction: column; + overflow: hidden; -.searchBar { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 10px; - padding: 5px; - - .searchLeft { + // A块:顶部统计卡片区域 + .blockA { + width: 100%; + height: 20%; display: flex; - align-items: center; - gap: 12px; - } - - .searchRight { - display: flex; - align-items: center; - gap: 12px; - } -} + gap: 16px; + margin-bottom: 16px; + background: linear-gradient(135deg, #E6F4FF 0%, #BAE0FF 100%); + border-radius: 2px; + padding: 16px; -// 自定义按钮样式 -.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; - } - - &:focus { - background-color: #2E4CD4 !important; - border-color: #2E4CD4 !important; - } -} + .statCard { + flex: 1; + height: 100%; + background: #FFFFFF; + border-radius: 2px; + padding: 20px; + display: flex; + align-items: center; + gap: 16px; -.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; + .statIcon { + width: 48px; + height: 48px; + display: flex; + align-items: center; + justify-content: center; + + .cubeIcon { + width: 32px; + height: 32px; + background: #1890FF; + border-radius: 4px; + } + + .warningIcon { + width: 0; + height: 0; + border-left: 16px solid transparent; + border-right: 16px solid transparent; + border-bottom: 28px solid #1890FF; + position: relative; + + &::after { + content: '!'; + position: absolute; + top: 8px; + left: -6px; + color: #fff; + font-weight: bold; + font-size: 16px; + } + } + + .successIcon { + width: 32px; + height: 32px; + background: #1890FF; + border-radius: 2px; + position: relative; + + &::after { + content: '✓'; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + color: #fff; + font-weight: bold; + font-size: 18px; + } + } + + .clockIcon { + width: 32px; + height: 32px; + background: #1890FF; + border-radius: 2px; + position: relative; + + &::after { + content: 'L'; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + color: #fff; + font-weight: bold; + font-size: 18px; + } + } + } + + .statContent { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + + .statNumber { + font-size: 32px; + font-weight: 600; + color: #333333; + line-height: 1; + margin-bottom: 8px; + } + + .statLabel { + font-size: 14px; + color: #666666; + } + } } } -} -// 表格样式优化 -.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; + // B块:主要内容区域 + .blockB { + width: 100%; + flex: 1; + display: flex; + gap: 16px; + overflow: hidden; + + // 左块 + .blockBLeft { + width: 400px; + display: flex; + flex-direction: column; + gap: 16px; + + // 上部分:事件类型分布 + .leftTop { + flex: 1; + background: #FFFFFF; + border-radius: 2px; + padding: 16px; + display: flex; + flex-direction: column; + overflow: hidden; + + .sectionTitle { + font-size: 16px; + font-weight: 600; + color: #333333; + margin-bottom: 16px; + } + + .chartWrapper { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + } + + .pieChartContainer { + display: flex; + align-items: center; + gap: 24px; + width: 100%; + + .pieSvg { + width: 160px; + height: 160px; + flex-shrink: 0; + } + + .pieLegend { + flex: 1; + display: flex; + flex-direction: column; + gap: 12px; + + .legendItem { + display: flex; + align-items: center; + gap: 8px; + + .legendColor { + width: 12px; + height: 12px; + border-radius: 2px; + flex-shrink: 0; + } + + .legendText { + font-size: 14px; + color: #666666; + } + } + } + } + } + + // 下部分:最近值班日志 + .leftBottom { + flex: 1; + background: #FFFFFF; + border-radius: 2px; + padding: 16px; + display: flex; + flex-direction: column; + overflow: hidden; + + .sectionTitle { + font-size: 16px; + font-weight: 600; + color: #333333; + margin-bottom: 16px; + } + + .recentLogsList { + flex: 1; + display: flex; + flex-direction: column; + gap: 12px; + overflow-y: auto; + + .logCard { + background: #F5F5F5; + border-radius: 2px; + padding: 12px; + + .logTitle { + font-size: 14px; + font-weight: 500; + color: #333333; + margin-bottom: 8px; + } + + .logInfo { + font-size: 12px; + color: #999999; + margin-bottom: 8px; + display: flex; + gap: 8px; + + .logLocation { + margin-left: 8px; + } + } + + .logDescription { + font-size: 13px; + color: #666666; + line-height: 1.5; + margin-bottom: 8px; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + } + + .logFooter { + display: flex; + justify-content: flex-end; + + .statusTag { + padding: 2px 8px; + border-radius: 12px; + font-size: 12px; + border: 1px solid; + } + } + } + } + } } - - .ant-btn-link.ant-btn-sm { - font-size: 13px !important; - height: auto !important; - padding: 0 !important; + + // 右块:值班日志列表 + .blockBRight { + flex: 1; + background: #FFFFFF; + border-radius: 2px; + padding: 16px; + display: flex; + flex-direction: column; + overflow: hidden; + + .sectionTitle { + font-size: 16px; + font-weight: 600; + color: #333333; + margin-bottom: 16px; + } + + .searchBar { + display: flex; + gap: 12px; + margin-bottom: 16px; + align-items: center; + + .searchInput { + flex: 1; + max-width: 300px; + } + + .filterSelect { + width: 120px; + } + + .addButton { + background: #1890FF; + border-color: #1890FF; + color: #FFFFFF; + border-radius: 2px; + height: 32px; + padding: 0 16px; + display: flex; + align-items: center; + justify-content: center; + + &:hover { + background: #40A9FF; + border-color: #40A9FF; + } + } + } + + .tableContainer { + flex: 1; + overflow: hidden; + display: flex; + flex-direction: column; + + :global { + .ant-table-wrapper { + flex: 1; + display: flex; + flex-direction: column; + + .ant-spin-nested-loading { + flex: 1; + display: flex; + flex-direction: column; + + .ant-spin-container { + flex: 1; + display: flex; + flex-direction: column; + + .ant-table { + flex: 1; + display: flex; + flex-direction: column; + + .ant-table-container { + flex: 1; + display: flex; + flex-direction: column; + + .ant-table-body { + flex: 1; + overflow-y: auto; + } + } + } + } + } + } + + .ant-table-thead > tr > th { + background: #F5F5FA; + font-weight: 500; + color: #333333; + font-size: 14px; + text-align: center; + border-radius: 0; + } + + .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: 16px; + display: flex; + justify-content: flex-end; + align-items: center; + padding: 0; + } + } + + .actionButtons { + display: flex; + gap: 8px; + justify-content: center; + align-items: center; + + .ant-btn-link { + padding: 0; + height: auto; + font-size: 13px; + } + } + } } } } -