feat(): 强化法治模块开发

qzc-dev
李神峰 2026-02-03 17:54:52 +08:00
parent d246a90eab
commit 98f1781507
13 changed files with 986 additions and 31 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -337,6 +337,13 @@ input:-webkit-autofill:active {
color: #fff;
}
}
.ant-picker-cell-disabled {
pointer-events: none;
.ant-picker-cell-inner {
color: rgba(255, 255, 255, 0.25) !important;
background-color: rgba(255, 255, 255, 0.1) !important;
}
}
// Footer/Ranges
.ant-picker-footer {

View File

@ -71,6 +71,16 @@ const apiurl = {
manageInfo: service + '/screen/mechanisms/equipment',
managePic: service + '/screen/manageHouseImg/get',
wzPage:service + '/rescue/goods/page/query'
},
qhfz: {
lawPage: service + '/SzRuleByLaw/page',
systemPage: service + '/SzRegulatoryFramework/page',
caseSta:service + '/szCase/statistics/1'
},
zrz: {
respPerson: service + '/screen/responsibility/getPerson',
floodPerson: service + '/screen/responsibility/getFxPerson',
train:service + '/screen/responsibility/getTraining'
}
}
}

View File

@ -3,7 +3,7 @@ import centerOfMass from '@turf/center-of-mass';
import bbox from '@turf/bbox';
import turfLength from '@turf/length';
import along from '@turf/along';
import { config } from '@/config';
const class2type = {};
const { toString } = class2type;
'Boolean Number String Function Array Date RegExp Object Error'.split(' ').forEach((name) => {
@ -596,4 +596,17 @@ export const myFiltrate = (data,params)=>{
return query.substring(iStart);
return query.substring(iStart, iEnd);
}
export const download = (url) => {
let downloadLink = document.createElement("a");
// downloadLink.href = `${process.env.REACT_APP_API_URL}/gunshiApp/ss/personnelPlan/file/download/${params}`;
downloadLink.href = config.ip +url;
// downloadLink.download = `${params.fileName}`;
downloadLink.style.display = "none";
// 将链接添加到页面中
document.body.appendChild(downloadLink);
// 模拟点击事件,开始下载
downloadLink.click();
}

View File

@ -6,6 +6,7 @@ import { treeList, srcData, videoList, ysyToken } from './http'
import VideoControler from "@/components/VideoCom/VideoControler"
import { httppost } from "@/utils/request"
import apiurl from "@/service/apiurl"
import { Spin } from "antd"
const VideoList = () => {
@ -15,6 +16,7 @@ const VideoList = () => {
const [size, setSize] = useState(1)
const [treeListData, setTreeData] = useState([])
const [selectList, setSelectList] = useState()
const [loading, setLoading] = useState(true)
const selectedKeys = async (list, node) => {
console.log(node, 'node');
@ -74,18 +76,24 @@ const VideoList = () => {
}
const getTreeData = async () => {
const res = await treeList()
const res1 = await videoList()
const arr = res1.data.filter(item => item.menuId).map((item, index) => {
item.parentId = item.menuId
item.id = 999 + index
item.isLeaf = true
// item.icon=<VideoCameraFilled />
return item
})
const arr1 = [...arr, ...res.data]
console.log("before", arr1);
setTreeData(buildTree(arr1))
try {
const res = await treeList()
const res1 = await videoList()
const arr = res1.data.filter(item => item.menuId).map((item, index) => {
item.parentId = item.menuId
item.id = 999 + index
item.isLeaf = true
// item.icon=<VideoCameraFilled />
return item
})
const arr1 = [...arr, ...res.data]
console.log("before", arr1);
setTreeData(buildTree(arr1))
} catch (error) {
console.error(error)
} finally {
setLoading(false)
}
}
function buildTree(data, parentId = "0") {
const tree = [];
@ -137,20 +145,28 @@ const VideoList = () => {
}, [])
return (
<div className='flex videoList'>
<div className={['treeRight', (selectList && selectList.type == 1) ? 'ptz-visible' : ''].join(' ')}>
<TreeData size={size} selectedKeys={selectedKeys} treeListData={treeListData} videoArr={videoArr} />
{
selectList && selectList.type == 1 ?
<div style={{ position: "absolute", bottom: 0, left: 0 }}>
<VideoControler
selectItem={selectList}
onOperation={onOperation}
/>
</div>
: null
}
</div>
<div className='treeLeft'><SplitScreen count={count} videoArr={videoArr} clickIndex={clickIndex} getType={getType} /></div>
{loading ? (
<div style={{ width: '100%', height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<Spin tip="加载中..." />
</div>
) : (
<>
<div className={['treeRight', (selectList && selectList.type == 1) ? 'ptz-visible' : ''].join(' ')}>
<TreeData size={size} selectedKeys={selectedKeys} treeListData={treeListData} videoArr={videoArr} />
{
selectList && selectList.type == 1 ?
<div style={{ position: "absolute", bottom: 0, left: 0 }}>
<VideoControler
selectItem={selectList}
onOperation={onOperation}
/>
</div>
: null
}
</div>
<div className='treeLeft'><SplitScreen count={count} videoArr={videoArr} clickIndex={clickIndex} getType={getType} /></div>
</>
)}
</div>
)
}

View File

@ -0,0 +1,212 @@
import React, { useState,useEffect } from 'react';
import { Image } from 'antd';
import arrowIcon from '@/assets/images/card/arrow.png';
import selectedBg from '@/assets/images/modal/selected.png';
import resperson from '@/assets/images/card/resperson.png';
import smallCard from '@/assets/images/card/smallCard.png';
import qys from '@/assets/images/business/qys.png';
import PdfView from '@/views/Home/components/UI/PdfView';
import apiurl from '@/service/apiurl';
import { httpget } from '@/utils/request';
import { download } from '@/utils/tools';
import './index.less';
const ImplementResponsibility = () => {
const types = {
1:"行政责任人",
2:"主管部门责任人",
3:"管理单位责任人",
4:"巡查责任人",
5:"技术责任人",
}
const [activeTab, setActiveTab] = useState('dam'); // 'dam' or 'flood'
const [pdfInfo, setPdfInfo] = useState({ visible: false, title: '', fileId: '' });
const [imagePreview, setImagePreview] = useState({ visible: false, src: '' });
const [respData, setRespData] = useState([])
const [floodData, setFloodData] = useState([])
const [trainData, setTrainData] = useState({})
const [trainFileData, setTrainFileData] = useState({})
// 获取大坝安全责任人
const getRespData = async () => {
try {
const { code, data } = await httpget(apiurl.sz.zrz.respPerson)
if (code == 200 && data.length > 0) {
const list = data.map(item => ({name:item.name,phone:item.contactInfo,role:types[item.type]}))
setRespData(list)
}
} catch (error) {
console.log(error);
}
}
// 获取防汛安全责任人
const getFloodData = async () => {
try {
const { code, data } = await httpget(apiurl.sz.zrz.floodPerson)
if (code == 200 && data.length > 0) {
const list = data.map(item => ({name:item.name,phone:item.contactInfo,role:types[item.type]}))
setFloodData(list)
}
} catch (error) {
console.log(error);
}
}
// 获取岗位培训
const getTrainData = async () => {
try {
const { code, data } = await httpget(apiurl.sz.zrz.train)
if (code == 200) {
setTrainData(data)
setTrainFileData(data?.latestPersonnelPlan?.files[0])
}
} catch (error) {
console.log(error);
}
}
const {trainingCount,hasTraining,hasNoTraining,totalTraining,latestPersonnelPlan} = trainData||{}
const trainingStats = [
{ label: '培训计划', value: trainingCount??'-' },
{ label: '已开展', value: hasTraining??'-' },
{ label: '未开展', value: hasNoTraining??'-' },
{ label: '参训总人次', value: totalTraining??'-' }
];
const handleTrainingClick = () => {
if (!trainFileData || !trainFileData.fileName) return;
const fileName = trainFileData.fileName;
const fileId = trainFileData.fileId;
const extension = fileName.split('.').pop().toLowerCase();
const downloadUrl = `/gunshiApp/ss/personnelPlan/file/download/${fileId}`;
if (['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(extension)) {
setImagePreview({
visible: true,
src: downloadUrl
});
} else if (extension === 'pdf') {
setPdfInfo({
visible: true,
title: fileName,
fileId: fileId
});
} else {
download(downloadUrl)
// window.location.href = downloadUrl;
}
};
const currentPersonList = activeTab === 'dam' ? respData : floodData;
useEffect(() => {
if (activeTab === 'dam') {
getRespData()
} else {
getFloodData()
}
}, [activeTab])
useEffect(() => {
getTrainData()
}, [])
return (
<div className="implement-responsibility">
{/* Top Tabs */}
<div className="tabs-container">
<div
className={`tab-item ${activeTab === 'dam' ? 'active' : ''}`}
onClick={() => setActiveTab('dam')}
style={activeTab === 'dam' ? { backgroundImage: `url(${selectedBg})` } : {}}
>
大坝安全责任人
</div>
<div
className={`tab-item ${activeTab === 'flood' ? 'active' : ''}`}
onClick={() => setActiveTab('flood')}
style={activeTab === 'flood' ? { backgroundImage: `url(${selectedBg})` } : {}}
>
防汛 三个责任人
</div>
</div>
{/* Person List */}
<div className="person-list">
{currentPersonList.map((person, index) => (
<div key={index} className="person-item">
<img src={resperson} alt="avatar" className="avatar" />
<span className="name">{person.name}</span>
<span className="phone">{person.phone}</span>
<div
className="role-label"
style={{ backgroundImage: `url(${smallCard})` }}
title={person.role}
>
{person.role}
</div>
</div>
))}
</div>
{/* Job Training Section */}
<div className="section-header">
<div className="title-wrapper">
<img src={arrowIcon} alt="arrow" className="arrow-icon" />
<span>岗位培训</span>
</div>
</div>
{/* Training Stats */}
<div className="training-stats">
{trainingStats.map((stat, index) => (
<div key={index} className="stat-item">
<span className="stat-value">{stat.value}</span>
<img src={qys} alt="icon" className="stat-icon" />
<span className="stat-label">{stat.label}</span>
</div>
))}
</div>
{/* Latest Training Content */}
<div className="latest-training" style={{ backgroundImage: `url(${smallCard})` }}>
<span className="label">最新培训内容:</span>
<div
className="value-box"
onClick={handleTrainingClick}
title={trainFileData.fileName?.replace(/\.[^/.]+$/, '')}
>
{trainFileData.fileName?.replace(/\.[^/.]+$/, '')}
</div>
</div>
{/* PDF Viewer */}
{pdfInfo.visible && (
<PdfView
visible={pdfInfo.visible}
onClose={() => setPdfInfo({ ...pdfInfo, visible: false })}
title={pdfInfo.title}
fileId={pdfInfo.fileId}
url="/gunshiApp/ss/personnelPlan/file/download/"
/>
)}
{/* Image Preview */}
<div style={{ display: 'none' }}>
<Image
src={imagePreview.src}
preview={{
visible: imagePreview.visible,
src: imagePreview.src,
onVisibleChange: (value) => {
setImagePreview({ ...imagePreview, visible: value });
},
}}
/>
</div>
</div>
);
};
export default ImplementResponsibility;

View File

@ -0,0 +1,173 @@
.implement-responsibility {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
box-sizing: border-box;
.tabs-container {
display: flex;
justify-content: space-around;
margin-bottom: 10px;
.tab-item {
flex: 1;
text-align: center;
padding: 3px 0;
font-size: 14px;
color: rgba(255, 255, 255, 0.6);
cursor: pointer;
background-size: 100% 100%;
background-repeat: no-repeat;
transition: all 0.3s;
&.active {
color: #fff;
text-shadow: 0 0 10px #00a0e9;
}
&:hover {
color: #fff;
}
}
}
.person-list {
display: flex;
justify-content: space-between;
padding: 0 10px;
margin-bottom: 10px;
.person-item {
display: flex;
flex-direction: column;
align-items: center;
width: 30%;
.avatar {
width: 40px;
height: 45px;
margin-bottom: 5px;
}
.name {
font-size: 14px;
color: #fff;
margin-bottom: 2px;
}
.phone {
font-size: 14px;
color: #fff;
margin-bottom: 5px;
}
.role-label {
width: 100%;
height: 24px;
line-height: 24px;
text-align: center;
color: #fff;
font-size: 14px;
background-size: 100% 100%;
background-repeat: no-repeat;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
.title-wrapper {
display: flex;
align-items: center;
.arrow-icon {
width: 20px;
height: 18px;
margin-right: 8px;
object-fit: contain;
}
span {
font-size: 14px;
color: #fff;
text-shadow: 0 0 5px rgba(0, 160, 233, 0.5);
}
}
}
.training-stats {
display: flex;
justify-content: space-between;
padding: 0 10px;
margin-bottom: 15px;
.stat-item {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
.stat-value {
font-size: 18px;
color: #00eaff;
font-weight: bold;
margin-bottom: -5px;
z-index: 1;
}
.stat-icon {
width: 100px;
height: 60px;
margin-bottom: 5px;
}
.stat-label {
font-size: 14px;
color: rgba(255, 255, 255);
}
}
}
.latest-training {
display: flex;
align-items: center;
padding: 0 10px;
margin-top: auto;
margin-bottom: 10px;
background-size: 100% 100%;
background-repeat: no-repeat;
.label {
font-size: 14px;
color: #fff;
margin-right: 10px;
white-space: nowrap;
}
.value-box {
flex: 1;
height: 30px;
line-height: 30px;
padding: 0 10px;
color: #00eaff;
font-size: 14px;
cursor: pointer;
text-decoration: underline;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
&:hover {
color: #fff;
}
}
}
}

View File

@ -0,0 +1,362 @@
import React, { useState,useEffect } from 'react';
import ReactEcharts from 'echarts-for-react';
import arrowIcon from '@/assets/images/card/arrow.png';
import selectedBg from '@/assets/images/modal/selected.png';
import YearSelect from '@/views/Home/components/UI/YearSelect';
import PdfView from '@/views/Home/components/UI/PdfView';
import { FileTextOutlined } from '@ant-design/icons';
import apiurl from '@/service/apiurl';
import { httppost, httpget } from '@/utils/request';
import { Empty } from 'antd';
import './index.less';
import moment from 'moment';
const StrengthenRuleOfLaw = () => {
const params = {
pageSo:{ pageSize: 9999, pageNumber: 1 }
}
const [activeTab, setActiveTab] = useState('laws');
const [lawData, setLawData] = useState([]);
const [systemData, setSystemData] = useState([]);
const [year, setYear] = useState(moment().format('YYYY'));
const [pdfInfo, setPdfInfo] = useState({ visible: false, title: '', fileId: '' });
// 获取法律法规文件
const lawsFiles = async () => {
try {
const { code, data } = await httppost(apiurl.sz.qhfz.lawPage, params)
if (code == 200) {
const list = data?.records.map(item => {
if (item?.files?.length === 0) {
return []
}
return { name: item?.files[0]?.fileName?.replace(/\.pdf$/i, ''), fileId: item?.files[0]?.fileId }
}).flat()
setLawData(list)
}
} catch (error) {
console.log(error);
}
}
// 获取系统文件
const systemFiles = async () => {
try {
const { code, data } = await httppost(apiurl.sz.qhfz.systemPage, params)
if (code == 200) {
const list = data?.records.map(item => {
if (item?.files?.length === 0) {
return []
}
return { name: item?.files[0]?.fileName?.replace(/\.pdf$/i, ''), fileId: item?.files[0]?.fileId }
}).flat()
setSystemData(list)
}
} catch (error) {
console.log(error);
}
}
const [chartData, setChartData] = useState([]);
const [selectedPieItem, setSelectedPieItem] = useState(null);
const [startAngle, setStartAngle] = useState(90);
const typeMapping = {
0: { name: '违建', color: '#1890ff' },
1: { name: '毁林垦荒', color: '#00eaff' },
2: { name: '筑坝拦汊', color: '#3155fb' },
3: { name: '填占库容', color: '#bcebf7' },
4: { name: '违法取水', color: '#00d085' },
5: { name: '其他', color: '#1890ff' },
};
// 获取水政执法数据 0:违建,1:毀林垦荒,2:筑坝拦汊,3:填占库容,4:违法取水,5:其他
const caseList = async (params) => {
try {
const { code, data } = await httppost(apiurl.sz.qhfz.caseSta, params)
if (code == 200) {
if (!data || data.length === 0) {
setChartData([]);
return;
}
const newChartData = data.map(item => {
const typeInfo = typeMapping[item.type] || { name: '未知', color: '#ccc' };
return {
name: typeInfo.name,
value: item.count,
color: typeInfo.color
};
});
setChartData(newChartData);
}
} catch (error) {
console.log(error);
}
}
const total = chartData.reduce((acc, cur) => acc + cur.value, 0);
const getOption = () => {
let centerName = '案件总数';
let centerValue = total;
let centerPercent = '100%';
if (selectedPieItem) {
centerName = selectedPieItem.name;
centerValue = selectedPieItem.value;
centerPercent = selectedPieItem.percent;
} else if (chartData.length === 1) {
centerName = chartData[0].name;
}
return {
tooltip: {
trigger: 'item',
formatter: '{b}: {c} ({d}%)'
},
series: [
{
name: '水政执法-外圈',
type: 'pie',
radius: ['48%', '82%'],
center: ['34%', '50%'],
startAngle: startAngle,
avoidLabelOverlap: false,
label: {
show: true,
position: 'inside',
formatter: '{b}',
color: '#fff',
fontSize: 10
},
itemStyle: {
opacity: 0.4
},
data: chartData.map(item => ({
value: item.value,
name: item.name,
itemStyle: { color: item.color }
}))
},
{
name: '水政执法-内圈',
type: 'pie',
radius: ['50%', '56%'],
center: ['34%', '50%'],
startAngle: startAngle,
avoidLabelOverlap: false,
label: {
show: true,
position: 'center',
formatter: () => `{name|${centerName}}\n{value|${centerValue}}\n{percent|${centerPercent}}`,
rich: {
name: {
fontSize: 12,
color: 'rgba(255,255,255,0.6)',
lineHeight: 16
},
value: {
fontSize: 14,
color: '#fff',
fontWeight: 'bold',
lineHeight: 20
},
percent: {
fontSize: 12,
color: '#fff',
lineHeight: 16
}
}
},
emphasis: {
label: {
show: true,
fontSize: '14',
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: chartData.map(item => ({
value: item.value,
name: item.name,
itemStyle: { color: item.color }
}))
}
]
}};
const onChartClick = (params) => {
if (params.componentType !== 'series') return;
const { name, value, dataIndex } = params;
// Toggle selection
if (selectedPieItem && selectedPieItem.name === name) {
setSelectedPieItem(null);
setStartAngle(90);
return;
}
let sumBefore = 0;
for (let i = 0; i < dataIndex; i++) {
sumBefore += chartData[i].value;
}
const offset = (sumBefore + value / 2) / total * 360;
const newStartAngle = 90 + offset;
setStartAngle(newStartAngle);
setSelectedPieItem({
name,
value,
percent: ((value / total) * 100).toFixed(0) + '%'
});
};
const handleItemClick = (item) => {
setPdfInfo({
visible: true,
title: item.name,
fileId: item.fileId
});
};
useEffect(() => {
if (chartData && chartData.length > 0) {
const totalVal = chartData.reduce((acc, cur) => acc + cur.value, 0);
const firstItem = chartData[0];
const value = firstItem.value;
const offset = (value / 2) / totalVal * 360;
const newStartAngle = 90 + offset;
setStartAngle(newStartAngle);
setSelectedPieItem({
name: firstItem.name,
value: value,
percent: ((value / totalVal) * 100).toFixed(0) + '%'
});
} else {
setSelectedPieItem(null);
setStartAngle(90);
}
}, [chartData]);
useEffect(() => {
if (activeTab == 'laws') {
lawsFiles()
} else {
systemFiles()
}
}, [activeTab])
useEffect(() => {
if (year) {
const params = {
stm: moment(year).format('YYYY-01-01 00:00:00'),
etm: moment(year).format('YYYY-12-31 23:59:59'),
}
caseList(params)
}
}, [year])
return (
<div className="strengthen-rule-of-law">
{/* Top Tabs */}
<div className="tabs-container">
<div
className={`tab-item ${activeTab === 'laws' ? 'active' : ''}`}
onClick={() => setActiveTab('laws')}
style={activeTab === 'laws' ? { backgroundImage: `url(${selectedBg})` } : {}}
>
法律法规
</div>
<div
className={`tab-item ${activeTab === 'system' ? 'active' : ''}`}
onClick={() => setActiveTab('system')}
style={activeTab === 'system' ? { backgroundImage: `url(${selectedBg})` } : {}}
>
制度管理
</div>
</div>
{/* List Content */}
<div className="list-content">
{(activeTab === 'laws' ? lawData : systemData).length > 0 ? (
(activeTab === 'laws' ? lawData : systemData).map((item, index) => (
<div key={index} className="list-item" onClick={() => handleItemClick(item)}>
<div className="icon-wrapper">
<FileTextOutlined style={{ color: '#1890ff', fontSize: '16px' }} />
</div>
<span className="text">{item.name}</span>
</div>
))
) : (
<div style={{ height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={<span style={{color:'#fff'}}>暂无数据</span>} />
</div>
)}
</div>
{/* Water Administration Law Enforcement */}
<div className="enforcement-section">
<div className="section-header">
<div className="title-wrapper">
<img src={arrowIcon} alt="arrow" className="arrow-icon" />
<span>水政执法</span>
</div>
<YearSelect
value={year}
onChange={setYear}
style={{ width: 100 }}
/>
</div>
<div className="chart-legend-container">
{chartData.length > 0 ? (
<>
<div className="chart-wrapper">
<ReactEcharts
option={getOption()}
style={{ height: '100%', width: '100%' }}
notMerge={true}
onEvents={{
'click': onChartClick
}}
/>
</div>
<div className="legend-wrapper">
{chartData.map((item, index) => (
<div key={index} className="legend-item">
<span className="color-dot" style={{ backgroundColor: item.color }}></span>
<span className="name">{item.name}</span>
<span className="value">{item.value}</span>
</div>
))}
</div>
</>
) : (
<div style={{ width: '100%', height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={<span style={{color:'#fff'}}>暂无数据</span>} />
</div>
)}
</div>
</div>
{/* PDF Viewer */}
{pdfInfo.visible && (
<PdfView
visible={pdfInfo.visible}
onClose={() => setPdfInfo({ ...pdfInfo, visible: false })}
title={pdfInfo.title}
fileId={pdfInfo.fileId}
url="/gunshiApp/ss/projectEvents/file/download/"
/>
)}
</div>
);
};
export default StrengthenRuleOfLaw;

View File

@ -0,0 +1,148 @@
.strengthen-rule-of-law {
width: 100%;
height: 100%;
color: #fff;
display: flex;
flex-direction: column;
.tabs-container {
display: flex;
justify-content: space-between;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
.tab-item {
flex: 1;
text-align: center;
padding: 3px 0;
font-size: 14px;
color: rgba(255, 255, 255, 0.6);
cursor: pointer;
background-size: 100% 100%;
background-repeat: no-repeat;
transition: all 0.3s;
&.active {
color: #fff;
text-shadow: 0 0 10px #00a0e9;
}
&:hover {
color: #fff;
}
}
}
.list-content {
flex: 1;
overflow-y: auto;
margin-bottom: 15px;
max-height: 120px; /* Limit height to show scroll if needed, though items are few */
.list-item {
display: flex;
align-items: center;
padding: 8px 0;
cursor: pointer;
transition: background-color 0.3s;
&:hover {
background-color: rgba(255, 255, 255, 0.05);
.text {
color: #00a0e9;
text-decoration: underline;
}
}
.icon-wrapper {
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 10px;
background: rgba(24, 144, 255, 0.1);
border-radius: 4px;
}
.text {
font-size: 14px;
color: rgba(255, 255, 255, 0.9);
}
}
}
.enforcement-section {
flex: 1;
display: flex;
flex-direction: column;
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
.title-wrapper {
display: flex;
align-items: center;
.arrow-icon {
width: 20px;
height: 18px;
margin-right: 8px;
object-fit: contain;
}
span {
font-size: 14px;
color: #fff;
text-shadow: 0 0 5px rgba(0, 160, 233, 0.5);
}
}
}
.chart-legend-container {
flex: 1;
display: flex;
align-items: center;
.chart-wrapper {
flex: 1;
height: 100%;
min-height: 140px;
}
.legend-wrapper {
width: 140px;
display: flex;
flex-direction: column;
justify-content: center;
padding-left: 10px;
.legend-item {
display: flex;
align-items: center;
margin-bottom: 6px;
font-size: 12px;
.color-dot {
width: 8px;
height: 8px;
margin-right: 8px;
border-radius: 2px;
}
.name {
flex: 1;
color: rgba(255, 255, 255, 0.8);
}
.value {
color: #fff;
font-weight: bold;
}
}
}
}
}
}

View File

@ -2,6 +2,8 @@ import React, { useState, useEffect } from 'react';
import CommonCard from '../../UI/CommonCard';
import PerfectSystem from './components/PerfectSystem';
import SoundMechanism from './components/SoundMechanism';
import StrengthenRuleOfLaw from './components/StrengthenRuleOfLaw';
import ImplementResponsibility from './components/ImplementResponsibility';
import { httppost } from '@/utils/request';
import apiurl from '@/service/apiurl';
import './index.less';
@ -36,10 +38,10 @@ const SiZhi = () => {
<div className="side-panel right">
<CommonCard title="强化法治" className="panel-card card-1">
<div className="placeholder-content">内容填充区域</div>
<StrengthenRuleOfLaw />
</CommonCard>
<CommonCard title="落实责任制" className="panel-card card-2">
<div className="placeholder-content">内容填充区域</div>
<ImplementResponsibility />
</CommonCard>
</div>
</div>

View File

@ -7,7 +7,7 @@ const PdfView = ({ visible, title, onClose, url, fileId }) => {
return (
<CommonModal
visible={visible}
title={title}
title={title?.replace(/\.pdf$/i, '')}
onClose={onClose}
width="60%"
bodyStyle={{ padding: 0, overflow: 'hidden' }}

View File

@ -9,14 +9,18 @@ const YearSelect = ({ value, onChange, className, style, ...props }) => {
onChange(dateString);
}
};
const disabledDate = (current) => {
return current && current > moment().endOf('day');
};
return (
<DatePicker
picker="year"
disabledDate={disabledDate}
value={value ? moment(value, 'YYYY') : null}
onChange={handleChange}
className={`custom-year-select ${className || ''}`}
dropdownClassName="custom-year-select-dropdown"
// dropdownClassName="custom-year-select-dropdown"
style={style}
allowClear={false}
{...props}

View File

@ -65,6 +65,14 @@
color: #fff;
}
.ant-picker-cell-disabled {
pointer-events: none;
.ant-picker-cell-inner {
color: rgba(255, 255, 255, 0.25) !important;
background-color: rgba(255, 255, 255, 0.1) !important;
}
}
.ant-picker-cell-selected .ant-picker-cell-inner {
background-color: #00a0e9 !important;
color: #fff;