/*
|
* @Company: hugeInfo
|
* @Author: AI
|
* @Date: 2025-04-17 16:30:00
|
* @LastEditTime: 2025-05-23 15:29:34
|
* @LastEditors: lwh
|
* @Version: 1.0.0
|
* @Description: 工作统计
|
*/
|
import React, { useEffect, useState } from 'react';
|
import { useHistory, useLocation } from 'react-router-dom';
|
import { Drawer, Tabs, Button, Select, Modal, Picker, List } from 'dingtalk-design-mobile';
|
import { ArrowOutlined, SettingOutlined, CloseOutlined } from 'dd-icons';
|
import * as $$ from '../../utils/utility';
|
import caseTypeSelect from '../../utils/caseTypeSelect';
|
import NavBarPage from '../../components/NavBarPage';
|
import MyChartBar from './MyChartBar';
|
import MyLTopChartPie from './MyLTopChartPie';
|
import CalendarRangeTwoDay from '../../components/CalendarRangeTwoDay';
|
import ModalDown from '../../components/ModalDown';
|
import { workStatistics_3, workStatistics_4, workStatistics_5, applyClose_1 } from '../../assets/img';
|
import './index.less';
|
import WorkStatisticsTabs, { getCurrentTabKeyByLocation } from '../../components/WorkStatisticsTabs';
|
|
// 获取工作统计数据
|
function getWorkStatisticsApi(data) {
|
return $$.ax.request({ url: 'caseInfo/workStatistics', type: 'get', data, service: 'mediate' });
|
}
|
|
const WorkStatistics = () => {
|
const history = useHistory();
|
const location = useLocation();
|
const currentTab = getCurrentTabKeyByLocation(location);
|
|
// 事项来源选项
|
const canalOptions = [
|
{ value: '22_00001-1', label: '大厅来访' },
|
{ value: '22_00001-2', label: '线上来访' },
|
{ value: '22_00001-3', label: '自行排查' },
|
{ value: '22_00001-4', label: '协同推送' },
|
];
|
|
// 事项等级选项
|
const caseLevelOptions = [
|
{ value: '1', label: '一级' },
|
{ value: '2', label: '二级' },
|
{ value: '3', label: '三级' },
|
];
|
|
// 新增:时间类型选项
|
const dateTypeOptions = [
|
{ value: 'custom', label: '自定义' },
|
{ value: 'lastMonth', label: '上月' },
|
{ value: 'lastWeek', label: '上周' },
|
{ value: 'thisMonth', label: '本月' },
|
{ value: 'thisWeek', label: '本周' },
|
{ value: 'thisYear', label: '本年度' },
|
{ value: 'lastYear', label: '上年度' },
|
];
|
|
const [loading, setLoading] = useState(false);
|
const [settingVisible, setSettingVisible] = useState(false);
|
const [datePickerVisible, setDatePickerVisible] = useState(false);
|
const [currentDateType, setCurrentDateType] = useState('');
|
const [activeStatTab, setActiveStatTab] = useState('total');
|
const [dateTypeModalVisible, setDateTypeModalVisible] = useState(false);
|
const [dateTypeTarget, setDateTypeTarget] = useState(''); // 'create' or 'close'
|
const userInfo = $$.getSessionStorage('customerSystemUser');
|
|
const [screenModal, setScreenModal] = useState({
|
dataList: [
|
{
|
title: '登记时间',
|
column: '1',
|
type: 'rangePicker',
|
key: ['createTimeStart', 'createTimeEnd'],
|
},
|
],
|
visible: false,
|
});
|
|
// 查询参数
|
const [queryParams, setQueryParams] = useState({
|
createStart: $$.myTimeFormat(new Date(new Date().getFullYear(), new Date().getMonth(), 1), 'YYYY-MM-DD'),
|
createEnd: $$.myTimeFormat(new Date(), 'YYYY-MM-DD'),
|
closeStart: '',
|
closeEnd: '',
|
canal: '',
|
caseLevel: '',
|
caseType: '',
|
});
|
|
// 临时筛选条件(用于抽屉中的操作,不立即生效)
|
const [tempFilterParams, setTempFilterParams] = useState({
|
createStart: $$.myTimeFormat(new Date(new Date().getFullYear(), new Date().getMonth(), 1), 'YYYY-MM-DD'),
|
createEnd: $$.myTimeFormat(new Date(), 'YYYY-MM-DD'),
|
closeStart: '',
|
closeEnd: '',
|
canal: '',
|
caseLevel: '',
|
caseType: '',
|
});
|
|
// 统计数据
|
const [statistics, setStatistics] = useState({
|
totalNum: 0,
|
processNum: 0,
|
finishNum: 0,
|
rejectNum: 0,
|
resolveNum: 0,
|
resolveRate: '0',
|
unResolveNum: 0,
|
toDayTotalNum: 0,
|
toDayProcessNum: 0,
|
toDayRejectNum: 0,
|
toDayFinishNum: 0,
|
momTotalRate: '0',
|
yoyTotalRate: '0',
|
momProcessRate: '0',
|
yoyProcessRate: '0',
|
momRejectRate: '0',
|
yoyRejectRate: '0',
|
momFinishNumRate: '0',
|
yoyFinishNumRate: '0',
|
momResolveRate: '0',
|
yoyResolveRate: '0',
|
typeList: [],
|
timeList: [],
|
});
|
|
// 视图切换相关
|
const [viewDrawerVisible, setViewDrawerVisible] = useState(false);
|
const [selectedView, setSelectedView] = useState('个人工作统计'); // 默认选中
|
const viewOptions = [
|
{ label: '个人工作统计', value: '个人工作统计' },
|
{ label: '部门工作统计', value: '部门工作统计' },
|
{ label: '区域工作统计', value: '区域工作统计' },
|
];
|
|
// 检查值是否以特定字符开头,防止null错误
|
const startsWithSafe = (value, char) => {
|
return value && typeof value === 'string' && value.startsWith(char);
|
};
|
|
// 初始化加载数据
|
useEffect(() => {
|
fetchStatisticsData();
|
}, [location, queryParams]);
|
|
// 监听路由变化
|
useEffect(() => {
|
const path = window.location.pathname;
|
if (path === '/gzdyh/workStatistics') {
|
// setCurrentTab('个人工作统计');
|
} else if (path === '/gzdyh/areaStatistics') {
|
// setCurrentTab('区域工作统计');
|
}
|
}, [window.location.pathname]);
|
|
// 获取统计数据
|
const fetchStatisticsData = async () => {
|
global.setSpinning(true);
|
setLoading(true);
|
try {
|
const res = await getWorkStatisticsApi({
|
...queryParams,
|
workType: currentTab === '个人工作统计' ? 1 : 2,
|
});
|
if (res.type && res.data) {
|
// 确保所有需要的字段都存在,避免null错误
|
const data = {
|
...statistics,
|
...res.data,
|
// 确保这些字段不为null
|
momTotalRate: res.data.momTotalRate || '0',
|
yoyTotalRate: res.data.yoyTotalRate || '0',
|
momProcessRate: res.data.momProcessRate || '0',
|
yoyProcessRate: res.data.yoyProcessRate || '0',
|
momRejectRate: res.data.momRejectRate || '0',
|
yoyRejectRate: res.data.yoyRejectRate || '0',
|
momFinishNumRate: res.data.momFinishNumRate || '0',
|
yoyFinishNumRate: res.data.yoyFinishNumRate || '0',
|
momResolveRate: res.data.momResolveRate || '0',
|
yoyResolveRate: res.data.yoyResolveRate || '0',
|
resolveRate: res.data.resolveRate || '0',
|
timeList: Array.isArray(res.data.timeList) ? res.data.timeList : [],
|
typeList: Array.isArray(res.data.typeList) ? res.data.typeList : [],
|
};
|
setStatistics(data);
|
}
|
} catch (error) {
|
console.error('获取工作统计数据失败', error);
|
} finally {
|
setLoading(false);
|
global.setSpinning(false);
|
}
|
};
|
|
// 打开设置抽屉时,将当前查询参数同步到临时参数
|
const handleOpenSetting = () => {
|
setTempFilterParams({ ...queryParams });
|
setSettingVisible(true);
|
};
|
|
// 关闭设置抽屉
|
const handleCloseSetting = () => {
|
setSettingVisible(false);
|
};
|
|
// 重置筛选条件(只重置临时参数)
|
const handleResetFilter = () => {
|
setTempFilterParams({
|
createStart: $$.myTimeFormat(new Date(new Date().getFullYear(), new Date().getMonth(), 1), 'YYYY-MM-DD'),
|
createEnd: $$.myTimeFormat(new Date(), 'YYYY-MM-DD'),
|
closeStart: '',
|
closeEnd: '',
|
canal: '',
|
caseLevel: '',
|
caseType: '',
|
});
|
};
|
|
// 应用筛选条件(将临时参数更新到正式查询参数)
|
const handleApplyFilter = () => {
|
setQueryParams({ ...tempFilterParams });
|
setSettingVisible(false);
|
};
|
|
// 处理日期选择
|
const handleOpenDatePicker = (type) => {
|
setCurrentDateType(type);
|
setDatePickerVisible(true);
|
};
|
|
// 处理日期变更
|
const handleDateChange = (dates) => {
|
if (!dates || dates.length !== 2) return;
|
|
const formatDate = (date) => {
|
if (!date || !date.key) return '';
|
return date.key;
|
};
|
|
const formattedStart = formatDate(dates[0]);
|
const formattedEnd = formatDate(dates[1]);
|
|
switch (currentDateType) {
|
case 'create':
|
setTempFilterParams((prev) => ({
|
...prev,
|
createStart: formattedStart,
|
createEnd: formattedEnd,
|
}));
|
break;
|
case 'close':
|
setTempFilterParams((prev) => ({
|
...prev,
|
closeStart: formattedStart,
|
closeEnd: formattedEnd,
|
}));
|
break;
|
default:
|
break;
|
}
|
setDatePickerVisible(false);
|
};
|
|
// 日历组件操作处理
|
const handleCalendarClick = (type, action) => {
|
if (action === 'onClose') {
|
setDatePickerVisible(false);
|
} else if (action === 'submit') {
|
setDatePickerVisible(false);
|
}
|
};
|
|
// 获取统计时间类型显示文本(当月、当年、当日)
|
const getTimeTypeText = () => {
|
if (!queryParams.createStart || !queryParams.createEnd) return '当日';
|
|
const startDate = new Date(queryParams.createStart);
|
const endDate = new Date(queryParams.createEnd);
|
|
// 检查是否为整月
|
if (
|
startDate.getDate() === 1 &&
|
endDate.getDate() === new Date(endDate.getFullYear(), endDate.getMonth() + 1, 0).getDate() &&
|
startDate.getMonth() === endDate.getMonth() &&
|
startDate.getFullYear() === endDate.getFullYear()
|
) {
|
return '当月';
|
}
|
|
// 检查是否为整年
|
if (
|
startDate.getMonth() === 0 &&
|
startDate.getDate() === 1 &&
|
endDate.getMonth() === 11 &&
|
endDate.getDate() === 31 &&
|
startDate.getFullYear() === endDate.getFullYear()
|
) {
|
return '当年';
|
}
|
|
return '当日';
|
};
|
|
// 判断是否为整月或整年
|
const isFullMonthOrYear = () => {
|
if (!queryParams.createStart || !queryParams.createEnd) return false;
|
|
const startDate = new Date(queryParams.createStart);
|
const endDate = new Date(queryParams.createEnd);
|
|
// 检查是否为整月
|
const isFullMonth =
|
startDate.getDate() === 1 &&
|
endDate.getDate() === new Date(endDate.getFullYear(), endDate.getMonth() + 1, 0).getDate() &&
|
startDate.getMonth() === endDate.getMonth() &&
|
startDate.getFullYear() === endDate.getFullYear();
|
|
// 检查是否为整年
|
const isFullYear =
|
startDate.getMonth() === 0 &&
|
startDate.getDate() === 1 &&
|
endDate.getMonth() === 11 &&
|
endDate.getDate() === 31 &&
|
startDate.getFullYear() === endDate.getFullYear();
|
|
return isFullMonth || isFullYear;
|
};
|
|
// 判断是否为整年
|
const isFullYear = () => {
|
if (!queryParams.createStart || !queryParams.createEnd) return false;
|
|
const startDate = new Date(queryParams.createStart);
|
const endDate = new Date(queryParams.createEnd);
|
|
return (
|
startDate.getMonth() === 0 &&
|
startDate.getDate() === 1 &&
|
endDate.getMonth() === 11 &&
|
endDate.getDate() === 31 &&
|
startDate.getFullYear() === endDate.getFullYear()
|
);
|
};
|
|
// 获取对比文本(月同比/年同比)
|
const getCompareText = () => {
|
return isFullYear() ? '年同比' : '月同比';
|
};
|
|
// 获取环比文本(月环比/年环比)
|
const getRatioText = () => {
|
return isFullYear() ? '年环比' : '月环比';
|
};
|
|
// 获取事项来源文本
|
const getCanalText = () => {
|
if (!queryParams.canal) return '全部';
|
const option = canalOptions.find((item) => item.value === queryParams.canal);
|
return option ? option.label : '全部';
|
};
|
|
// 获取筛选条件显示信息
|
const getFilterInfoText = () => {
|
const info = [];
|
|
// 添加登记时间
|
if (queryParams.createStart && queryParams.createEnd) {
|
info.push(`登记时间:${queryParams.createStart.replace(/-/g, '.')}–${queryParams.createEnd.replace(/-/g, '.')}`);
|
}
|
|
// 添加事项来源
|
info.push(`事项来源:${getCanalText()}`);
|
|
return info;
|
};
|
|
// 清除单个筛选条件
|
const clearFilterItem = (type) => {
|
switch (type) {
|
case 'create':
|
setQueryParams((prev) => ({
|
...prev,
|
createStart: $$.myTimeFormat(new Date(new Date().getFullYear(), new Date().getMonth(), 1), 'YYYY-MM-DD'),
|
createEnd: $$.myTimeFormat(new Date(), 'YYYY-MM-DD'),
|
}));
|
break;
|
case 'close':
|
setQueryParams((prev) => ({
|
...prev,
|
closeStart: '',
|
closeEnd: '',
|
}));
|
break;
|
case 'canal':
|
setQueryParams((prev) => ({
|
...prev,
|
canal: '',
|
}));
|
break;
|
case 'caseLevel':
|
setQueryParams((prev) => ({
|
...prev,
|
caseLevel: '',
|
}));
|
break;
|
case 'caseType':
|
setQueryParams((prev) => ({
|
...prev,
|
caseType: '',
|
}));
|
break;
|
case 'area':
|
setQueryParams((prev) => ({
|
...prev,
|
queCity: '',
|
queArea: '',
|
queRoad: '',
|
queVillage: '',
|
}));
|
break;
|
default:
|
break;
|
}
|
|
// 清除后立即更新数据
|
setTimeout(() => {
|
fetchStatisticsData();
|
}, 0);
|
};
|
|
// 渲染同比环比的图标和数据
|
const renderRateWithIcon = (rate) => {
|
if (!rate) return '0%';
|
|
// 去掉+/-符号
|
const rateValue = rate.replace(/[+\-]/g, '');
|
const isPositive = !startsWithSafe(rate, '-');
|
|
return (
|
<span className={isPositive ? 'up' : 'down'}>
|
<img src={isPositive ? workStatistics_3 : workStatistics_4} alt="" className="rate-icon" />
|
{rateValue}%
|
</span>
|
);
|
};
|
|
// 渲染化解统计图表
|
const renderChartByTab = () => {
|
// 确保timeList是数组
|
const timeList = Array.isArray(statistics.timeList) ? statistics.timeList : [];
|
|
switch (activeStatTab) {
|
case 'total':
|
return (
|
<MyChartBar
|
data={timeList.map((item) => ({
|
caseNum: item.totalNum || 0,
|
name: item.timeStr || '',
|
}))}
|
dataAxis={timeList.map((item) => item.timeStr || '')}
|
barColor={['#5fa6d4', '#1a6fb8']}
|
/>
|
);
|
case 'processing':
|
return (
|
<MyChartBar
|
data={timeList.map((item) => ({
|
caseNum: item.processNum || 0,
|
name: item.timeStr || '',
|
}))}
|
dataAxis={timeList.map((item) => item.timeStr || '')}
|
barColor={['#5fa6d4', '#1a6fb8']}
|
/>
|
);
|
case 'finished':
|
return (
|
<MyChartBar
|
data={timeList.map((item) => ({
|
resolveNum: item.resolveNum || 0,
|
unResolveNum: item.unResolveNum || 0,
|
name: item.timeStr || '',
|
}))}
|
dataAxis={timeList.map((item) => item.timeStr || '')}
|
barColor={['#08979C', '#F2657D']}
|
isStacked={true}
|
/>
|
);
|
case 'rejected':
|
return (
|
<MyChartBar
|
data={timeList.map((item) => ({
|
caseNum: item.rejectNum || 0,
|
name: item.timeStr || '',
|
}))}
|
dataAxis={timeList.map((item) => item.timeStr || '')}
|
barColor={['#5fa6d4', '#1a6fb8']}
|
/>
|
);
|
default:
|
return null;
|
}
|
};
|
|
// 计算时间范围
|
const getDateRangeByType = (type) => {
|
const now = new Date();
|
let start, end;
|
switch (type) {
|
case 'lastMonth': {
|
const year = now.getMonth() === 0 ? now.getFullYear() - 1 : now.getFullYear();
|
const month = now.getMonth() === 0 ? 11 : now.getMonth() - 1;
|
start = new Date(year, month, 1);
|
end = new Date(year, month + 1, 0);
|
break;
|
}
|
case 'thisMonth': {
|
start = new Date(now.getFullYear(), now.getMonth(), 1);
|
end = new Date(now.getFullYear(), now.getMonth() + 1, 0);
|
break;
|
}
|
case 'lastWeek': {
|
const day = now.getDay() || 7;
|
end = new Date(now.getFullYear(), now.getMonth(), now.getDate() - day);
|
start = new Date(now.getFullYear(), now.getMonth(), now.getDate() - day - 6);
|
break;
|
}
|
case 'thisWeek': {
|
const day = now.getDay() || 7;
|
start = new Date(now.getFullYear(), now.getMonth(), now.getDate() - day + 1);
|
end = new Date(now.getFullYear(), now.getMonth(), now.getDate() - day + 7);
|
break;
|
}
|
case 'thisYear': {
|
start = new Date(now.getFullYear(), 0, 1);
|
end = new Date(now.getFullYear(), 11, 31);
|
break;
|
}
|
case 'lastYear': {
|
start = new Date(now.getFullYear() - 1, 0, 1);
|
end = new Date(now.getFullYear() - 1, 11, 31);
|
break;
|
}
|
default:
|
start = end = now;
|
}
|
return [$$.myTimeFormat(start, 'YYYY-MM-DD'), $$.myTimeFormat(end, 'YYYY-MM-DD')];
|
};
|
|
// 打开时间类型弹窗
|
const handleOpenDateTypeModal = (target) => {
|
setDateTypeTarget(target);
|
setDateTypeModalVisible(true);
|
};
|
|
// 选择时间类型
|
const handleDateTypeSelect = (type) => {
|
setDateTypeModalVisible(false);
|
if (type === 'custom') {
|
handleOpenDatePicker(dateTypeTarget);
|
} else {
|
const [start, end] = getDateRangeByType(type);
|
if (dateTypeTarget === 'create') {
|
setTempFilterParams((prev) => ({ ...prev, createStart: start, createEnd: end }));
|
} else if (dateTypeTarget === 'close') {
|
setTempFilterParams((prev) => ({ ...prev, closeStart: start, closeEnd: end }));
|
}
|
}
|
};
|
|
// 在组件内增加一个方法用于获取label
|
const getCaseTypeLabel = (value) => {
|
if (!value) return '';
|
let label = '';
|
caseTypeSelect.caseTypeSelect.forEach((item) => {
|
if (item.value === value) {
|
label = item.label;
|
} else if (item.children) {
|
const child = item.children.find((child) => child.value === value);
|
if (child) label = child.label;
|
}
|
});
|
return label;
|
};
|
|
// 筛选重置 确定
|
function handleScreen(data, list) {
|
console.log(data, list);
|
// let submitData = { ...data };
|
setScreenModal({ dataList: list, visible: false });
|
// setModalTop({ dataList: list, visible: false });
|
// getListData({ ...data, page: 1, size: 10 }, 'spin');
|
// // getListData({ ...search, ...submitData, page: 1, }, "spin");
|
}
|
|
function modalClick() {}
|
|
return (
|
<NavBarPage
|
title={currentTab}
|
rightContentFunc={() => setViewDrawerVisible(true)}
|
rightChildren={userInfo.ctUseroleList?.some((item) => item.roleCode === '22_00024-2' || item.roleCode === '22_00024-3') ? '切换视图' : ''}
|
>
|
{/* <WorkStatisticsTabs /> */}
|
<div className="work-statistics">
|
{/* 筛选条件展示区域 */}
|
<div className="filter-info-section">
|
<div className="filter-info-title">筛选条件</div>
|
<div className="filter-settings" onClick={handleOpenSetting}>
|
<img src={workStatistics_5} alt="" className="settings-icon" />
|
<span>设置</span>
|
</div>
|
</div>
|
|
{/* 筛选条件内容 */}
|
<div className="filter-conditions">
|
{queryParams.createStart && queryParams.createEnd && (
|
<div className="filter-info-item">
|
<span className="filter-info-text">
|
登记时间:{queryParams.createStart.replace(/-/g, '.')}~{queryParams.createEnd.replace(/-/g, '.')}
|
</span>
|
<CloseOutlined className="filter-info-clear" onClick={() => clearFilterItem('create')} />
|
</div>
|
)}
|
{queryParams.closeStart && queryParams.closeEnd && (
|
<div className="filter-info-item">
|
<span className="filter-info-text">
|
办结时间:{queryParams.closeStart.replace(/-/g, '.')}~{queryParams.closeEnd.replace(/-/g, '.')}
|
</span>
|
<CloseOutlined className="filter-info-clear" onClick={() => clearFilterItem('close')} />
|
</div>
|
)}
|
{queryParams.canal && (
|
<div className="filter-info-item">
|
<span className="filter-info-text">事项来源:{getCanalText()}</span>
|
<CloseOutlined className="filter-info-clear" onClick={() => clearFilterItem('canal')} />
|
</div>
|
)}
|
{queryParams.caseLevel && (
|
<div className="filter-info-item">
|
<span className="filter-info-text">事项等级:{caseLevelOptions.find((i) => i.value === queryParams.caseLevel)?.label || ''}</span>
|
<CloseOutlined className="filter-info-clear" onClick={() => clearFilterItem('caseLevel')} />
|
</div>
|
)}
|
{queryParams.caseType && (
|
<div className="filter-info-item">
|
<span className="filter-info-text">纠纷类型:{getCaseTypeLabel(queryParams.caseType) || ''}</span>
|
<CloseOutlined className="filter-info-clear" onClick={() => clearFilterItem('caseType')} />
|
</div>
|
)}
|
{(queryParams.queCity || queryParams.queArea || queryParams.queRoad || queryParams.queVillage) && (
|
<div className="filter-info-item">
|
<span className="filter-info-text">问题属地:已选择</span>
|
<CloseOutlined className="filter-info-clear" onClick={() => clearFilterItem('area')} />
|
</div>
|
)}
|
</div>
|
|
{/* 工作总览 */}
|
<div className="work-overview-section">
|
<div className="work-overview-title">工作总览</div>
|
<div className="work-overview-cards">
|
{/* 第一行卡片:总登记、化解中、不予受理 */}
|
<div className="card-row">
|
{/* 总登记卡片 - 蓝色 */}
|
<div className="overview-card total-card">
|
<div className="card-day-data">
|
{getTimeTypeText()}+{statistics.toDayTotalNum || 0}
|
</div>
|
{isFullMonthOrYear() && (
|
<div className="card-month-rates">
|
<div className="month-compare">
|
{getCompareText()} {renderRateWithIcon(statistics.yoyTotalRate)}
|
</div>
|
<div className="month-ratio">
|
{getRatioText()} {renderRateWithIcon(statistics.momTotalRate)}
|
</div>
|
</div>
|
)}
|
<div className="card-value">{statistics.totalNum || 0}</div>
|
<div className="card-name">总登记</div>
|
</div>
|
|
{/* 化解中卡片 - 蓝色 */}
|
<div className="overview-card process-card">
|
<div className="card-day-data">
|
{getTimeTypeText()}+{statistics.toDayProcessNum || 0}
|
</div>
|
{isFullMonthOrYear() && (
|
<div className="card-month-rates">
|
<div className="month-compare">
|
{getCompareText()} {renderRateWithIcon(statistics.yoyProcessRate)}
|
</div>
|
<div className="month-ratio">
|
{getRatioText()} {renderRateWithIcon(statistics.momProcessRate)}
|
</div>
|
</div>
|
)}
|
<div className="card-value">{statistics.processNum || 0}</div>
|
<div className="card-name">化解中</div>
|
</div>
|
|
{/* 不予受理卡片 - 粉色 */}
|
<div className="overview-card reject-card">
|
<div className="card-day-data">
|
{getTimeTypeText()}+{statistics.toDayRejectNum || 0}
|
</div>
|
{isFullMonthOrYear() && (
|
<div className="card-month-rates">
|
<div className="month-compare">
|
{getCompareText()} {renderRateWithIcon(statistics.yoyRejectRate)}
|
</div>
|
<div className="month-ratio">
|
{getRatioText()} {renderRateWithIcon(statistics.momRejectRate)}
|
</div>
|
</div>
|
)}
|
<div className="card-value">{statistics.rejectNum || 0}</div>
|
<div className="card-name">不予受理</div>
|
</div>
|
</div>
|
|
{/* 第二行卡片:已结案、化解成功率 */}
|
<div className="card-row">
|
{/* 已结案卡片 - 黄色 */}
|
<div className="overview-card finish-card">
|
<div className="card-left-content">
|
<div className="card-day-data">
|
{getTimeTypeText()}+{statistics.toDayFinishNum || 0}
|
</div>
|
{isFullMonthOrYear() && (
|
<div className="card-month-rates">
|
<div className="month-compare">
|
{getCompareText()} {renderRateWithIcon(statistics.yoyFinishNumRate)}
|
</div>
|
<div className="month-ratio">
|
{getRatioText()} {renderRateWithIcon(statistics.momFinishNumRate)}
|
</div>
|
</div>
|
)}
|
<div className="card-value">{statistics.finishNum || 0}</div>
|
<div className="card-name">已结案</div>
|
</div>
|
<div className="card-right-content">
|
<div className="resolve-success">
|
<div className="resolve-value">{statistics.resolveNum || 0}</div>
|
<div className="resolve-label">化解成功</div>
|
</div>
|
<div className="vertical-divider"></div>
|
<div className="resolve-fail">
|
<div className="resolve-value">{statistics.unResolveNum || 0}</div>
|
<div className="resolve-label">化解不成功</div>
|
</div>
|
</div>
|
</div>
|
|
{/* 化解成功率卡片 - 绿色 */}
|
<div className="overview-card resolve-rate-card">
|
<div className="rate-value">{statistics.resolveRate || '0'}%</div>
|
{isFullMonthOrYear() && (
|
<div className="card-month-rates">
|
<div className="month-compare">
|
{getCompareText()} {renderRateWithIcon(statistics.yoyResolveRate)}
|
</div>
|
<div className="month-ratio">
|
{getRatioText()} {renderRateWithIcon(statistics.momResolveRate)}
|
</div>
|
</div>
|
)}
|
<div className="rate-label">化解成功率</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
|
{/* 化解统计区域 */}
|
<div className="work-statistics-section">
|
<div className="work-statistics-section-title">化解统计</div>
|
<div className="work-statistics-tabs">
|
<div className={`tab-item ${activeStatTab === 'total' ? 'active' : ''}`} onClick={() => setActiveStatTab('total')}>
|
总登记
|
</div>
|
<div className={`tab-item ${activeStatTab === 'processing' ? 'active' : ''}`} onClick={() => setActiveStatTab('processing')}>
|
化解中
|
</div>
|
<div className={`tab-item ${activeStatTab === 'finished' ? 'active' : ''}`} onClick={() => setActiveStatTab('finished')}>
|
已结案
|
</div>
|
<div className={`tab-item ${activeStatTab === 'rejected' ? 'active' : ''}`} onClick={() => setActiveStatTab('rejected')}>
|
不予受理
|
</div>
|
</div>
|
<div className="work-statistics-chart">{renderChartByTab()}</div>
|
</div>
|
|
{/* 纠纷类型区域 */}
|
<div className="work-statistics-section">
|
<div className="work-statistics-section-title">纠纷类型</div>
|
<div className="work-statistics-pie">
|
<MyLTopChartPie
|
data={(statistics.typeList || []).map((item) => ({
|
name: item.caseTypeName || '',
|
value: item.caseNum || 0,
|
rate: item.caseRate || '0',
|
}))}
|
showInside={true}
|
adjustLegend={true}
|
/>
|
</div>
|
</div>
|
|
{/* 设置筛选条件抽屉 */}
|
<Drawer
|
visible={settingVisible}
|
onClose={handleCloseSetting}
|
className="custom-filter-drawer"
|
position="top"
|
maskClosable={true}
|
popup
|
transparent={false}
|
>
|
<div className="custom-filter-content">
|
<div className="filter-item">
|
<div className="filter-label">登记时间</div>
|
<div className="filter-selector" onClick={() => handleOpenDateTypeModal('create')}>
|
{tempFilterParams.createStart && tempFilterParams.createEnd ? `${tempFilterParams.createStart}~${tempFilterParams.createEnd}` : '请选择日期范围'}
|
</div>
|
</div>
|
|
<div className="filter-item">
|
<div className="filter-label">办结时间</div>
|
<div className="filter-selector" onClick={() => handleOpenDateTypeModal('close')}>
|
{tempFilterParams.closeStart && tempFilterParams.closeEnd ? `${tempFilterParams.closeStart}~${tempFilterParams.closeEnd}` : '请选择日期范围'}
|
</div>
|
</div>
|
|
<div className="filter-item full-row">
|
<div className="filter-label">事项来源</div>
|
<div className="canal-radio-group">
|
<div
|
className={`canal-radio${!tempFilterParams.canal ? ' checked' : ''}`}
|
onClick={() => setTempFilterParams((prev) => ({ ...prev, canal: '' }))}
|
>
|
全部{!tempFilterParams.canal && <img src={applyClose_1} alt="选中" className="audit-radio-checked" />}
|
</div>
|
{canalOptions.map((opt) => (
|
<div
|
key={opt.value}
|
className={`canal-radio${tempFilterParams.canal === opt.value ? ' checked' : ''}`}
|
onClick={() => setTempFilterParams((prev) => ({ ...prev, canal: opt.value }))}
|
>
|
{opt.label}
|
{tempFilterParams.canal === opt.value && <img src={applyClose_1} alt="选中" className="audit-radio-checked" />}
|
</div>
|
))}
|
</div>
|
</div>
|
|
<div className="filter-item full-row">
|
<div className="filter-label">事项等级</div>
|
<div className="canal-radio-group">
|
<div
|
className={`canal-radio${!tempFilterParams.caseLevel ? ' checked' : ''}`}
|
onClick={() => setTempFilterParams((prev) => ({ ...prev, caseLevel: '' }))}
|
>
|
全部{!tempFilterParams.caseLevel && <img src={applyClose_1} alt="选中" className="audit-radio-checked" />}
|
</div>
|
{caseLevelOptions.map((opt) => (
|
<div
|
key={opt.value}
|
className={`canal-radio${tempFilterParams.caseLevel === opt.value ? ' checked' : ''}`}
|
onClick={() => setTempFilterParams((prev) => ({ ...prev, caseLevel: opt.value }))}
|
>
|
{opt.label}
|
{tempFilterParams.caseLevel === opt.value && <img src={applyClose_1} alt="选中" className="audit-radio-checked" />}
|
</div>
|
))}
|
</div>
|
</div>
|
|
<div className="filter-item full-row">
|
<div className="filter-label">纠纷类型</div>
|
<Picker
|
data={caseTypeSelect.caseTypeSelect}
|
cols={2}
|
cascade={true}
|
title="纠纷类型"
|
value={tempFilterParams.caseType ? [tempFilterParams.caseType] : []}
|
okText="确定"
|
onOk={(valArr) => {
|
// 支持选中第一级或第二级
|
const value = valArr.filter(Boolean).slice(-1)[0];
|
setTempFilterParams((prev) => ({ ...prev, caseType: value }));
|
}}
|
>
|
<List.Item className="filter-selector">
|
{getCaseTypeLabel(tempFilterParams.caseType) || <div className="filter-item-select">请选择</div>}
|
</List.Item>
|
</Picker>
|
</div>
|
</div>
|
|
<div className="custom-filter-buttons">
|
<Button className="filter-reset" onClick={handleResetFilter}>
|
重置
|
</Button>
|
<Button className="filter-apply" type="primary" onClick={handleApplyFilter}>
|
统计
|
</Button>
|
</div>
|
</Drawer>
|
|
{/* 日期选择弹窗 */}
|
<Modal
|
visible={datePickerVisible}
|
onClose={() => setDatePickerVisible(false)}
|
className="date-type-modal"
|
position="bottom"
|
maskClosable={true}
|
popup
|
transparent={false}
|
>
|
<div className="modal-header">
|
<div className="modal-title">选择日期范围</div>
|
<CloseOutlined className="modal-close" onClick={() => setDatePickerVisible(false)} />
|
</div>
|
<CalendarRangeTwoDay CalendaronClick={handleCalendarClick} onClickDate={handleDateChange} />
|
</Modal>
|
|
{/* 时间类型选择底部弹窗 */}
|
<Modal
|
visible={dateTypeModalVisible}
|
onClose={() => setDateTypeModalVisible(false)}
|
className="date-type-modal"
|
position="bottom"
|
maskClosable={true}
|
popup
|
transparent={false}
|
>
|
<div className="modal-header">
|
<div className="modal-title">选择时间类型</div>
|
<CloseOutlined className="modal-close" onClick={() => setDateTypeModalVisible(false)} />
|
</div>
|
<div className="date-type-modal-content">
|
{dateTypeOptions.map((opt) => (
|
<div key={opt.value} className="date-type-modal-item" onClick={() => handleDateTypeSelect(opt.value)}>
|
{opt.label}
|
</div>
|
))}
|
</div>
|
</Modal>
|
|
{/* 切换视图底部抽屉 */}
|
<Drawer
|
visible={viewDrawerVisible}
|
onClose={() => setViewDrawerVisible(false)}
|
position="bottom"
|
className="switch-view-drawer"
|
maskClosable={true}
|
popup
|
transparent={false}
|
>
|
<div className="switch-view-header">
|
<span className="switch-view-close" onClick={() => setViewDrawerVisible(false)}>
|
×
|
</span>
|
<span className="switch-view-title">切换视图</span>
|
<span
|
className="switch-view-confirm"
|
onClick={() => {
|
setViewDrawerVisible(false);
|
}}
|
>
|
确定
|
</span>
|
</div>
|
<div className="switch-view-list">
|
{viewOptions.map((opt) => (
|
<div
|
key={opt.value}
|
className={`switch-view-item${selectedView === opt.value ? ' active' : ''}`}
|
onClick={() => setSelectedView(opt.value)}
|
>
|
{opt.label}
|
</div>
|
))}
|
</div>
|
</Drawer>
|
</div>
|
</NavBarPage>
|
);
|
};
|
|
export default WorkStatistics;
|