dev_1.2
tangjie 2026-07-23 11:11:41 +08:00
parent 201055a49b
commit 2d20215e96
5 changed files with 333 additions and 1 deletions

View File

@ -133,4 +133,16 @@ export const evalProjectMemberPage = declareRequest(
export const evalProjectMemberSave = declareRequest(
"memberSaveLoading",
"Post > @/safetyEval/institution/eval-project-member/save",
);
// ===== 项目预警(安评业务提醒) =====
export const projectWaringStat = declareRequest(
"projectWaringStatLoading",
"Get > /safetyEval/project-waring/stat",
);
export const projectWaringRemindPage = declareRequest(
"projectWaringRemindPageLoading",
"Get > /safetyEval/project-waring/remind-page",
);

View File

@ -351,4 +351,22 @@ export const PROGRESS_STATUS_MAP = {
NORMAL: { color: "success", text: "正常" },
NEAR: { color: "warning", text: "项目临期" },
DELAY: { color: "error", text: "项目延期" },
};
};
/** 安评业务提醒 — 提醒等级映射 */
export const WARING_STATUS_MAP = {
first: { color: "success", text: "首次预警" },
second: { color: "warning", text: "二次提醒" },
urgent: { color: "error", text: "紧急预警" },
overdue: { color: "default", text: "已逾期" },
normal: { color: "default", text: "正常" },
};
/** 安评业务提醒 — 提醒等级筛选选项 */
export const WARING_STATUS_OPTIONS = [
{ label: "首次预警6个月", value: "first" },
{ label: "二次提醒3个月", value: "second" },
{ label: "紧急预警1个月", value: "urgent" },
{ label: "已逾期", value: "overdue" },
{ label: "正常", value: "normal" },
];

View File

@ -21,6 +21,7 @@ import {
FormOutlined,
CheckCircleOutlined,
SyncOutlined,
BellOutlined,
} from "@ant-design/icons";
const menuItems = [
@ -236,6 +237,11 @@ const menuItems = [
label: "安评客户管理",
icon: <TeamOutlined />,
},
{
key: "/safetyEval/container/SafetyEvalBusiness/BusinessReminder",
label: "安评业务提醒",
icon: <BellOutlined />,
},
],
},
{

View File

@ -0,0 +1,258 @@
import React, { useState, useEffect } from "react";
import {
Form,
Table,
Button,
Tag,
Row,
Col,
Card,
Statistic,
Space,
} from "antd";
import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
import SearchForm from "@cqsjjb/jjb-react-admin-component/SearchForm";
import ControlWrapper from "@cqsjjb/jjb-react-admin-component/ControlWrapper";
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
import { WARING_STATUS_MAP, WARING_STATUS_OPTIONS } from "~/enumerate/constant";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { tools } from "@cqsjjb/jjb-common-lib";
import "./index.less";
const { router } = tools;
const INDUSTRY_OPTIONS = [
{ label: "危险化学品", value: "DANGEROUS_CHEMICAL" },
{ label: "非煤矿山", value: "NON_COAL_MINE" },
{ label: "城镇燃气", value: "URBAN_GAS" },
{ label: "一般工贸", value: "GENERAL_TRADE" },
];
const BusinessReminder = (props) => {
const [searchForm] = Form.useForm();
const [dataSource, setDataSource] = useState([]);
const [total, setTotal] = useState(0);
const [statData, setStatData] = useState({});
const { projectWaringRemindPageLoading } = props.safetyEvalBusiness;
const getStat = async () => {
const res = await props.projectWaringStat();
if (res?.success !== false) {
setStatData(res?.data || {});
}
};
const getData = async () => {
const params = {
...router.query,
current: router.query.current || 1,
size: router.query.size || 10,
};
const res = await props.projectWaringRemindPage(params);
if (res?.success !== false) {
setDataSource(res?.data || []);
setTotal(res?.totalCount || 0);
}
};
useEffect(() => {
searchForm.setFieldsValue(router.query);
getStat();
getData();
}, []);
const handleSearch = (values) => {
router.query = { ...router.query, ...values, current: 1, size: 10 };
getData();
};
const handleReset = (values) => {
searchForm.resetFields();
router.query = { ...values, current: 1, size: 10 };
getData();
};
const handlePageChange = (pagination) => {
router.query = {
...router.query,
current: pagination.current,
size: pagination.pageSize,
};
getData();
};
const handleViewCustomer = (record) => {
// TODO: 查看企业资料
};
const formatCycle = (days) => {
if (!days) return "-";
const years = days / 365;
if (years >= 1) {
return Number.isInteger(years) ? `${years}` : `${years.toFixed(1)}`;
}
return `${days}`;
};
const renderWaringStatus = (status) => {
const cfg = WARING_STATUS_MAP[status];
if (!cfg) return <Tag>{status}</Tag>;
const labelMap = {
first: "首次预警 · 6个月",
second: "二次提醒 · 3个月",
urgent: "紧急预警 · 1个月",
overdue: "已逾期",
normal: "正常",
};
return <Tag color={cfg.color}>{labelMap[status] || cfg.text}</Tag>;
};
const columns = [
{ title: "客户名称", dataIndex: "customerName", width: 180, ellipsis: true },
{ title: "行业 / 场景", dataIndex: "industryCode", width: 160, ellipsis: true },
{ title: "最近报告完成日", dataIndex: "archiveDate", width: 140 },
{
title: "周期",
dataIndex: "cycleDate",
width: 100,
render: (val) => formatCycle(val),
},
{ title: "下次应开展", dataIndex: "reassessmentDate", width: 120 },
{
title: "提醒等级",
dataIndex: "waringStatus",
width: 140,
render: (val) => renderWaringStatus(val),
},
{ title: "业务负责人", dataIndex: "projectLeaderName", width: 100, ellipsis: true },
{
title: "操作",
width: 120,
fixed: "right",
render: (_, record) => (
<Button type="link" size="small" onClick={() => handleViewCustomer(record)}>
查看企业资料
</Button>
),
},
];
return (
<PageLayout title="安评业务提醒">
<Row gutter={16} className="br-stat-row">
<Col span={6}>
<Card size="small">
<Statistic
title="纳入提醒客户"
value={statData.remindCount ?? "-"}
suffix={<span className="br-stat-suffix">按行业周期和属地要求维护</span>}
/>
</Card>
</Col>
<Col span={6}>
<Card size="small">
<Statistic
title="首次预警"
value={statData.firstWaringCount ?? "-"}
valueStyle={{ color: "#52c41a" }}
suffix={<span className="br-stat-suffix">到期前6个月启动商务对接</span>}
/>
</Card>
</Col>
<Col span={6}>
<Card size="small">
<Statistic
title="二次提醒"
value={statData.secondWaringCount ?? "-"}
valueStyle={{ color: "#faad14" }}
suffix={<span className="br-stat-suffix">到期前3个月正式委托启动</span>}
/>
</Card>
</Col>
<Col span={6}>
<Card size="small">
<Statistic
title="紧急预警"
value={statData.emergencyWaringCount ?? "-"}
valueStyle={{ color: "#ff4d4f" }}
suffix={<span className="br-stat-suffix">到期前1个月加快编制评审</span>}
/>
</Card>
</Col>
</Row>
<div className="br-note">
<strong>提醒时间规则</strong>
到期前6个月首次预警提示启动商务对接和项目排期到期前3个月二次提醒提示正式委托启动到期前1个月紧急预警提示加快报告编制与评审超过到期日自动转为已逾期
</div>
<SearchForm
form={searchForm}
loading={false}
style={{ marginBottom: 16 }}
formLine={[
<Form.Item key="customerName" name="customerName">
<ControlWrapper.Input
label="客户名称"
placeholder="输入客户名称"
allowClear
/>
</Form.Item>,
<Form.Item key="industryCode" name="industryCode">
<ControlWrapper.Select
label="行业 / 场景"
placeholder="全部"
allowClear
options={INDUSTRY_OPTIONS}
/>
</Form.Item>,
<Form.Item key="waringStatus" name="waringStatus">
<ControlWrapper.Select
label="提醒等级"
placeholder="全部"
allowClear
options={WARING_STATUS_OPTIONS}
/>
</Form.Item>,
]}
onFinish={handleSearch}
onReset={handleReset}
/>
<div className="br-toolbar">
<span className="br-toolbar-hint">
下一次应开展日期 = 最近一次正式报告完成日期 + 对应行业评价周期
</span>
<Space>
<Button>导出清单</Button>
<Button type="primary">批量提醒</Button>
</Space>
</div>
<Table
rowKey="id"
columns={columns}
dataSource={dataSource}
loading={projectWaringRemindPageLoading}
scroll={{ y: props.scrollY, x: 1200 }}
pagination={{
total,
current: router.query.current || 1,
pageSize: router.query.size || 10,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (total) => `${total}`,
}}
onChange={handlePageChange}
/>
</PageLayout>
);
};
export default Connect(
[NS_SAFETY_EVAL_BUSINESS],
true,
)(AntdTableFuncControl(BusinessReminder));

View File

@ -0,0 +1,38 @@
.br {
&-header-desc {
font-size: 13px;
color: #999;
margin-bottom: 16px;
}
&-stat-row {
margin-bottom: 16px;
}
&-stat-suffix {
font-size: 12px;
color: #999;
}
&-note {
padding: 8px 12px;
background: #f6f8fa;
border-radius: 6px;
font-size: 13px;
color: #555;
margin-bottom: 16px;
border: 1px solid #e8e8e8;
}
&-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
&-toolbar-hint {
font-size: 13px;
color: #999;
}
}