feat
parent
6156138a55
commit
c755e472bc
|
|
@ -12,8 +12,8 @@ module.exports = {
|
||||||
// 可通过环境变量覆盖: SAFETY_EVAL_API_HOST=http://192.168.x.x:8095
|
// 可通过环境变量覆盖: SAFETY_EVAL_API_HOST=http://192.168.x.x:8095
|
||||||
//API_HOST: "https://gbs-gateway.qhdsafety.com",
|
//API_HOST: "https://gbs-gateway.qhdsafety.com",
|
||||||
|
|
||||||
//API_HOST: "http://192.168.0.152",
|
API_HOST: "http://192.168.0.152",
|
||||||
API_HOST: "http://192.168.0.150", //太浅
|
//API_HOST: "http://192.168.0.150", //太浅
|
||||||
// API_HOST: "http://192.168.0.152",
|
// API_HOST: "http://192.168.0.152",
|
||||||
//API_HOST: "http://192.168.0.103", //huwei
|
//API_HOST: "http://192.168.0.103", //huwei
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,154 @@
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import { Modal, Button, Descriptions, Table, Tag } from "antd";
|
||||||
|
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||||
|
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
|
||||||
|
import {
|
||||||
|
ENTERPRISE_STATUS_OPTIONS,
|
||||||
|
ENTERPRISE_SCALE_OPTIONS,
|
||||||
|
EVAL_TYPE_MAP,
|
||||||
|
} from "~/enumerate/constant";
|
||||||
|
import { QUALIFICATION_INDUSTRY_OPTIONS_MAP } from "~/enumerate/enterpriseOptions";
|
||||||
|
|
||||||
|
const CustomerDetailModal = ({ open, customerId, onCancel, ...props }) => {
|
||||||
|
const [detail, setDetail] = useState(null);
|
||||||
|
const { customerDetailLoading } = props.safetyEvalBusiness || {};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!open || !customerId) {
|
||||||
|
setDetail(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
props.customerDetail({ id: customerId }).then((res) => {
|
||||||
|
if (res?.success !== false) {
|
||||||
|
setDetail(res?.data || null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [open, customerId]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title={`客户详情 - ${detail?.customerName || ""}`}
|
||||||
|
open={open}
|
||||||
|
loading={customerDetailLoading}
|
||||||
|
onCancel={onCancel}
|
||||||
|
footer={<Button onClick={onCancel}>关闭</Button>}
|
||||||
|
width={700}
|
||||||
|
destroyOnHidden
|
||||||
|
>
|
||||||
|
{detail && (
|
||||||
|
<>
|
||||||
|
<Descriptions
|
||||||
|
column={2}
|
||||||
|
bordered
|
||||||
|
size="small"
|
||||||
|
style={{ marginBottom: 16 }}
|
||||||
|
>
|
||||||
|
<Descriptions.Item label="客户名称">
|
||||||
|
{detail.customerName}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="统一社会信用代码">
|
||||||
|
{detail.creditCode}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="企业状态">
|
||||||
|
{(() => {
|
||||||
|
const statusOption = ENTERPRISE_STATUS_OPTIONS.find(
|
||||||
|
(opt) => opt.value === detail.enterpriseStatusCode,
|
||||||
|
);
|
||||||
|
return statusOption?.label || detail.enterpriseStatusName;
|
||||||
|
})()}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="企业规模">
|
||||||
|
{(() => {
|
||||||
|
const scaleOption = ENTERPRISE_SCALE_OPTIONS.find(
|
||||||
|
(opt) => opt.value === detail.enterpriseScaleCode,
|
||||||
|
);
|
||||||
|
return scaleOption?.label || detail.enterpriseScaleName;
|
||||||
|
})()}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="所属行业">
|
||||||
|
{detail.industryCode
|
||||||
|
?.split(",")
|
||||||
|
.map(
|
||||||
|
(code) =>
|
||||||
|
QUALIFICATION_INDUSTRY_OPTIONS_MAP[code.trim()] ||
|
||||||
|
code.trim(),
|
||||||
|
)
|
||||||
|
.join("、")}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="属地">
|
||||||
|
{detail.districtName}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="联系人">
|
||||||
|
{detail.principalName}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="联系电话">
|
||||||
|
{detail.principalPhone}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="主要负责人">
|
||||||
|
{detail.principalName}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="负责人电话">
|
||||||
|
{detail.principalPhone}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="法定代表人">
|
||||||
|
{detail.legalRepresentative}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="法人电话">
|
||||||
|
{detail.legalRepresentativePhone}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="经营地址" span={2}>
|
||||||
|
{detail.businessAddress}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="经度">
|
||||||
|
{detail.longitude}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="纬度">
|
||||||
|
{detail.latitude}
|
||||||
|
</Descriptions.Item>
|
||||||
|
</Descriptions>
|
||||||
|
|
||||||
|
<h4 style={{ margin: "12px 0 8px" }}>安全评价项目列表</h4>
|
||||||
|
<Table
|
||||||
|
rowKey="id"
|
||||||
|
dataSource={detail.projects || []}
|
||||||
|
columns={[
|
||||||
|
{ title: "项目名称", dataIndex: "projectName" },
|
||||||
|
{
|
||||||
|
title: "评价类型",
|
||||||
|
dataIndex: "evalTypeCode",
|
||||||
|
width: 120,
|
||||||
|
render: (s) => EVAL_TYPE_MAP[s] || s || "",
|
||||||
|
},
|
||||||
|
{ title: "报告完成日期", dataIndex: "planEndDate", width: 130 },
|
||||||
|
{
|
||||||
|
title: "项目状态",
|
||||||
|
dataIndex: "status",
|
||||||
|
width: 100,
|
||||||
|
fixed: "right",
|
||||||
|
render: (phase, record) => {
|
||||||
|
if (record.archiveFlag === 1) {
|
||||||
|
return <Tag color="success">已归档</Tag>;
|
||||||
|
}
|
||||||
|
if (record.projectPhaseCode === "NORMAL") {
|
||||||
|
return <Tag color="success">正常</Tag>;
|
||||||
|
}
|
||||||
|
if (record.projectPhaseCode === "DELAY") {
|
||||||
|
return <Tag color="error">已延期</Tag>;
|
||||||
|
}
|
||||||
|
return record.projectPhaseName;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
pagination={false}
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Connect(
|
||||||
|
[NS_SAFETY_EVAL_BUSINESS],
|
||||||
|
true,
|
||||||
|
)(CustomerDetailModal);
|
||||||
|
|
@ -373,20 +373,22 @@ export const PROGRESS_STATUS_MAP = {
|
||||||
|
|
||||||
/** 安评业务提醒 — 提醒等级映射 */
|
/** 安评业务提醒 — 提醒等级映射 */
|
||||||
export const WARING_STATUS_MAP = {
|
export const WARING_STATUS_MAP = {
|
||||||
first: { color: "success", text: "首次预警" },
|
first_waring: { color: "success", text: "首次预警" },
|
||||||
second: { color: "warning", text: "二次提醒" },
|
second_waring: { color: "warning", text: "二次预警" },
|
||||||
urgent: { color: "error", text: "紧急预警" },
|
emergency_waring: { color: "error", text: "紧急预警" },
|
||||||
overdue: { color: "default", text: "已逾期" },
|
overdue_warning: { color: "default", text: "逾期预警" },
|
||||||
normal: { color: "default", text: "正常" },
|
end_warning: { color: "default", text: "结束预警" },
|
||||||
|
non_warn: { color: "default", text: "暂时不预警" },
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 安评业务提醒 — 提醒等级筛选选项 */
|
/** 安评业务提醒 — 提醒等级筛选选项 */
|
||||||
export const WARING_STATUS_OPTIONS = [
|
export const WARING_STATUS_OPTIONS = [
|
||||||
{ label: "首次预警(6个月)", value: "first" },
|
{ label: "暂时不预警", value: "non_warn" },
|
||||||
{ label: "二次提醒(3个月)", value: "second" },
|
{ label: "首次预警", value: "first_waring" },
|
||||||
{ label: "紧急预警(1个月)", value: "urgent" },
|
{ label: "二次预警", value: "second_waring" },
|
||||||
{ label: "已逾期", value: "overdue" },
|
{ label: "紧急预警", value: "emergency_waring" },
|
||||||
{ label: "正常", value: "normal" },
|
{ label: "逾期预警", value: "overdue_warning" },
|
||||||
|
{ label: "结束预警", value: "end_warning" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const NODE_LABELS = {
|
export const NODE_LABELS = {
|
||||||
|
|
|
||||||
|
|
@ -137,11 +137,6 @@ const menuItems = [
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: "/safetyEval/container/MonitorManage/RiskCenter",
|
|
||||||
label: "风险预警中心",
|
|
||||||
icon: <ExperimentOutlined />,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: "/safetyEval/container/Supervision/InspectionNotice",
|
key: "/safetyEval/container/Supervision/InspectionNotice",
|
||||||
label: "监督检查告知",
|
label: "监督检查告知",
|
||||||
|
|
|
||||||
|
|
@ -16,24 +16,24 @@ import SearchForm from "@cqsjjb/jjb-react-admin-component/SearchForm";
|
||||||
import ControlWrapper from "@cqsjjb/jjb-react-admin-component/ControlWrapper";
|
import ControlWrapper from "@cqsjjb/jjb-react-admin-component/ControlWrapper";
|
||||||
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
|
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
|
||||||
import { WARING_STATUS_MAP, WARING_STATUS_OPTIONS } from "~/enumerate/constant";
|
import { WARING_STATUS_MAP, WARING_STATUS_OPTIONS } from "~/enumerate/constant";
|
||||||
|
import {
|
||||||
|
QUALIFICATION_INDUSTRY_OPTIONS,
|
||||||
|
QUALIFICATION_INDUSTRY_OPTIONS_MAP,
|
||||||
|
} from "~/enumerate/enterpriseOptions";
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||||
import { tools } from "@cqsjjb/jjb-common-lib";
|
import { tools } from "@cqsjjb/jjb-common-lib";
|
||||||
|
import CustomerDetailModal from "~/components/CustomerDetailModal";
|
||||||
import "./index.less";
|
import "./index.less";
|
||||||
|
|
||||||
const { router } = tools;
|
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 BusinessReminder = (props) => {
|
||||||
const [searchForm] = Form.useForm();
|
const [searchForm] = Form.useForm();
|
||||||
const [dataSource, setDataSource] = useState([]);
|
const [dataSource, setDataSource] = useState([]);
|
||||||
const [total, setTotal] = useState(0);
|
const [total, setTotal] = useState(0);
|
||||||
const [statData, setStatData] = useState({});
|
const [statData, setStatData] = useState({});
|
||||||
|
const [customerDetailOpen, setCustomerDetailOpen] = useState(false);
|
||||||
|
const [customerId, setCustomerId] = useState(null);
|
||||||
|
|
||||||
const { projectWaringRemindPageLoading } = props.safetyEvalBusiness;
|
const { projectWaringRemindPageLoading } = props.safetyEvalBusiness;
|
||||||
|
|
||||||
|
|
@ -84,7 +84,8 @@ const BusinessReminder = (props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleViewCustomer = (record) => {
|
const handleViewCustomer = (record) => {
|
||||||
// TODO: 查看企业资料
|
setCustomerId(record.customerId);
|
||||||
|
setCustomerDetailOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatCycle = (days) => {
|
const formatCycle = (days) => {
|
||||||
|
|
@ -99,19 +100,22 @@ const BusinessReminder = (props) => {
|
||||||
const renderWaringStatus = (status) => {
|
const renderWaringStatus = (status) => {
|
||||||
const cfg = WARING_STATUS_MAP[status];
|
const cfg = WARING_STATUS_MAP[status];
|
||||||
if (!cfg) return <Tag>{status}</Tag>;
|
if (!cfg) return <Tag>{status}</Tag>;
|
||||||
const labelMap = {
|
return <Tag color={cfg.color}>{cfg.text}</Tag>;
|
||||||
first: "首次预警 · 6个月",
|
|
||||||
second: "二次提醒 · 3个月",
|
|
||||||
urgent: "紧急预警 · 1个月",
|
|
||||||
overdue: "已逾期",
|
|
||||||
normal: "正常",
|
|
||||||
};
|
|
||||||
return <Tag color={cfg.color}>{labelMap[status] || cfg.text}</Tag>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ title: "客户名称", dataIndex: "customerName", width: 180, ellipsis: true },
|
{ title: "客户名称", dataIndex: "customerName", width: 180, ellipsis: true },
|
||||||
{ title: "行业 / 场景", dataIndex: "industryCode", width: 160, ellipsis: true },
|
{
|
||||||
|
title: "业务范围",
|
||||||
|
dataIndex: "industryCode",
|
||||||
|
width: 160,
|
||||||
|
ellipsis: true,
|
||||||
|
render: (val) =>
|
||||||
|
val
|
||||||
|
?.split(",")
|
||||||
|
.map((code) => QUALIFICATION_INDUSTRY_OPTIONS_MAP[code])
|
||||||
|
.join("、"),
|
||||||
|
},
|
||||||
{ title: "最近报告完成日", dataIndex: "archiveDate", width: 140 },
|
{ title: "最近报告完成日", dataIndex: "archiveDate", width: 140 },
|
||||||
{
|
{
|
||||||
title: "周期",
|
title: "周期",
|
||||||
|
|
@ -203,16 +207,16 @@ const BusinessReminder = (props) => {
|
||||||
</Form.Item>,
|
</Form.Item>,
|
||||||
<Form.Item key="industryCode" name="industryCode">
|
<Form.Item key="industryCode" name="industryCode">
|
||||||
<ControlWrapper.Select
|
<ControlWrapper.Select
|
||||||
label="行业 / 场景"
|
label="业务范围"
|
||||||
placeholder="全部"
|
placeholder="请选择业务范围"
|
||||||
allowClear
|
allowClear
|
||||||
options={INDUSTRY_OPTIONS}
|
options={QUALIFICATION_INDUSTRY_OPTIONS}
|
||||||
/>
|
/>
|
||||||
</Form.Item>,
|
</Form.Item>,
|
||||||
<Form.Item key="waringStatus" name="waringStatus">
|
<Form.Item key="waringStatus" name="waringStatus">
|
||||||
<ControlWrapper.Select
|
<ControlWrapper.Select
|
||||||
label="提醒等级"
|
label="提醒等级"
|
||||||
placeholder="全部"
|
placeholder="请选择提醒等级"
|
||||||
allowClear
|
allowClear
|
||||||
options={WARING_STATUS_OPTIONS}
|
options={WARING_STATUS_OPTIONS}
|
||||||
/>
|
/>
|
||||||
|
|
@ -227,8 +231,8 @@ const BusinessReminder = (props) => {
|
||||||
下一次应开展日期 = 最近一次正式报告完成日期 + 对应行业评价周期
|
下一次应开展日期 = 最近一次正式报告完成日期 + 对应行业评价周期
|
||||||
</span>
|
</span>
|
||||||
<Space>
|
<Space>
|
||||||
<Button>导出清单</Button>
|
{/* <Button>导出清单</Button>
|
||||||
<Button type="primary">批量提醒</Button>
|
<Button type="primary">批量提醒</Button> */}
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -248,6 +252,12 @@ const BusinessReminder = (props) => {
|
||||||
}}
|
}}
|
||||||
onChange={handlePageChange}
|
onChange={handlePageChange}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<CustomerDetailModal
|
||||||
|
open={customerDetailOpen}
|
||||||
|
customerId={customerId}
|
||||||
|
onCancel={() => setCustomerDetailOpen(false)}
|
||||||
|
/>
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,12 @@ import {
|
||||||
Row,
|
Row,
|
||||||
Col,
|
Col,
|
||||||
message,
|
message,
|
||||||
Descriptions,
|
|
||||||
Flex,
|
Flex,
|
||||||
Tag,
|
Tag,
|
||||||
Space,
|
Space,
|
||||||
|
Tooltip,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
|
|
||||||
import { PlusOutlined } from "@ant-design/icons";
|
import { PlusOutlined } from "@ant-design/icons";
|
||||||
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
||||||
import SearchForm from "@cqsjjb/jjb-react-admin-component/SearchForm";
|
import SearchForm from "@cqsjjb/jjb-react-admin-component/SearchForm";
|
||||||
|
|
@ -22,12 +23,14 @@ import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
|
||||||
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
|
import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace";
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||||
import BaiduMapPicker from "~/components/BaiduMapPicker";
|
import BaiduMapPicker from "~/components/BaiduMapPicker";
|
||||||
|
import AttachmentUpload from "~/components/AttachmentUpload";
|
||||||
|
import CustomerDetailModal from "~/components/CustomerDetailModal";
|
||||||
import { tools } from "@cqsjjb/jjb-common-lib";
|
import { tools } from "@cqsjjb/jjb-common-lib";
|
||||||
import {
|
import {
|
||||||
district,
|
district,
|
||||||
ENTERPRISE_STATUS_OPTIONS,
|
ENTERPRISE_STATUS_OPTIONS,
|
||||||
ENTERPRISE_SCALE_OPTIONS,
|
ENTERPRISE_SCALE_OPTIONS,
|
||||||
EVAL_TYPE_MAP,
|
NODE_LABELS
|
||||||
} from "~/enumerate/constant";
|
} from "~/enumerate/constant";
|
||||||
import { QUALIFICATION_INDUSTRY_OPTIONS } from "~/enumerate/enterpriseOptions";
|
import { QUALIFICATION_INDUSTRY_OPTIONS } from "~/enumerate/enterpriseOptions";
|
||||||
import { phoneRule, creditCodeRule } from "~/utils/validators";
|
import { phoneRule, creditCodeRule } from "~/utils/validators";
|
||||||
|
|
@ -42,10 +45,16 @@ const CustomerManage = (props) => {
|
||||||
const [mapPickerVisible, setMapPickerVisible] = useState(false);
|
const [mapPickerVisible, setMapPickerVisible] = useState(false);
|
||||||
const [modalOpen, setModalOpen] = useState(false);
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
const [detailOpen, setDetailOpen] = useState(false);
|
const [detailOpen, setDetailOpen] = useState(false);
|
||||||
|
const [detailCustomerId, setDetailCustomerId] = useState(null);
|
||||||
|
const [projectModalOpen, setProjectModalOpen] = useState(false);
|
||||||
const [currentDetail, setCurrentDetail] = useState(null);
|
const [currentDetail, setCurrentDetail] = useState(null);
|
||||||
const [editingId, setEditingId] = useState(null);
|
const [editingId, setEditingId] = useState(null);
|
||||||
const { customerLoading, customerModifyLoading, customerSaveLoading } =
|
const {
|
||||||
props.safetyEvalBusiness;
|
customerLoading,
|
||||||
|
customerModifyLoading,
|
||||||
|
customerSaveLoading,
|
||||||
|
customerDetailLoading,
|
||||||
|
} = props.safetyEvalBusiness;
|
||||||
|
|
||||||
const getData = async (pagination) => {
|
const getData = async (pagination) => {
|
||||||
const params = {
|
const params = {
|
||||||
|
|
@ -103,22 +112,32 @@ const CustomerManage = (props) => {
|
||||||
setModalOpen(true);
|
setModalOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOpenEdit = async (record) => {
|
const handleOpenEdit = (record) => {
|
||||||
const res = await props.customerDetail({ id: record.id });
|
setEditingId(record.id);
|
||||||
if (res?.success !== false) {
|
setCurrentDetail(null);
|
||||||
setEditingId(record.id);
|
modalForm.resetFields();
|
||||||
setCurrentDetail(res?.data || {});
|
setModalOpen(true);
|
||||||
modalForm.setFieldsValue(res?.data || {});
|
props.customerDetail({ id: record.id }).then((res) => {
|
||||||
setModalOpen(true);
|
if (res?.success !== false) {
|
||||||
}
|
setCurrentDetail(res?.data || {});
|
||||||
|
modalForm.setFieldsValue(res?.data || {});
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleViewDetail = async (record) => {
|
const handleViewDetail = (record) => {
|
||||||
const res = await props.customerDetail({ id: record.id });
|
setDetailCustomerId(record.id);
|
||||||
if (res?.success !== false) {
|
setDetailOpen(true);
|
||||||
setCurrentDetail(res?.data || {});
|
};
|
||||||
setDetailOpen(true);
|
|
||||||
}
|
const handleViewProjects = (record) => {
|
||||||
|
setCurrentDetail(null);
|
||||||
|
setProjectModalOpen(true);
|
||||||
|
props.customerDetail({ id: record.id }).then((res) => {
|
||||||
|
if (res?.success !== false) {
|
||||||
|
setCurrentDetail(res?.data || {});
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = async (record) => {
|
const handleDelete = async (record) => {
|
||||||
|
|
@ -182,8 +201,13 @@ const CustomerManage = (props) => {
|
||||||
title: "服务项目数",
|
title: "服务项目数",
|
||||||
dataIndex: "projectCount",
|
dataIndex: "projectCount",
|
||||||
width: 110,
|
width: 110,
|
||||||
render: (count) => (
|
render: (count, record) => (
|
||||||
<Button type="link" size="small" style={{ padding: 0 }}>
|
<Button
|
||||||
|
type="link"
|
||||||
|
|
||||||
|
size="small"
|
||||||
|
onClick={() => handleViewProjects(record)}
|
||||||
|
>
|
||||||
{count || 0}
|
{count || 0}
|
||||||
</Button>
|
</Button>
|
||||||
),
|
),
|
||||||
|
|
@ -197,7 +221,6 @@ const CustomerManage = (props) => {
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
size="small"
|
size="small"
|
||||||
|
|
||||||
onClick={() => handleViewDetail(record)}
|
onClick={() => handleViewDetail(record)}
|
||||||
>
|
>
|
||||||
查看
|
查看
|
||||||
|
|
@ -205,7 +228,7 @@ const CustomerManage = (props) => {
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
size="small"
|
size="small"
|
||||||
|
|
||||||
onClick={() => handleOpenEdit(record)}
|
onClick={() => handleOpenEdit(record)}
|
||||||
>
|
>
|
||||||
编辑
|
编辑
|
||||||
|
|
@ -223,6 +246,14 @@ const CustomerManage = (props) => {
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
const parseProjectNode = (data) => {
|
||||||
|
if (Array.isArray(data)) return data;
|
||||||
|
try {
|
||||||
|
return JSON.parse(data || "[]");
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageLayout
|
<PageLayout
|
||||||
|
|
@ -300,6 +331,7 @@ const CustomerManage = (props) => {
|
||||||
<Modal
|
<Modal
|
||||||
title={editingId ? "编辑客户" : "新建客户"}
|
title={editingId ? "编辑客户" : "新建客户"}
|
||||||
open={modalOpen}
|
open={modalOpen}
|
||||||
|
loading={editingId ? customerDetailLoading : false}
|
||||||
onCancel={() => setModalOpen(false)}
|
onCancel={() => setModalOpen(false)}
|
||||||
onOk={handleCreateSubmit}
|
onOk={handleCreateSubmit}
|
||||||
confirmLoading={editingId ? customerModifyLoading : customerSaveLoading}
|
confirmLoading={editingId ? customerModifyLoading : customerSaveLoading}
|
||||||
|
|
@ -440,123 +472,107 @@ const CustomerManage = (props) => {
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
{/* 客户详情弹窗 */}
|
{/* 客户详情弹窗 */}
|
||||||
<Modal
|
<CustomerDetailModal
|
||||||
title={`客户详情 - ${currentDetail?.customerName || ""}`}
|
|
||||||
open={detailOpen}
|
open={detailOpen}
|
||||||
|
customerId={detailCustomerId}
|
||||||
onCancel={() => setDetailOpen(false)}
|
onCancel={() => setDetailOpen(false)}
|
||||||
footer={<Button onClick={() => setDetailOpen(false)}>关闭</Button>}
|
/>
|
||||||
width={700}
|
|
||||||
destroyOnHidden
|
|
||||||
>
|
|
||||||
{currentDetail && (
|
|
||||||
<>
|
|
||||||
<Descriptions
|
|
||||||
column={2}
|
|
||||||
bordered
|
|
||||||
size="small"
|
|
||||||
style={{ marginBottom: 16 }}
|
|
||||||
>
|
|
||||||
<Descriptions.Item label="客户名称">
|
|
||||||
{currentDetail.customerName}
|
|
||||||
</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="统一社会信用代码">
|
|
||||||
{currentDetail.creditCode}
|
|
||||||
</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="企业状态">
|
|
||||||
{(() => {
|
|
||||||
const statusOption = ENTERPRISE_STATUS_OPTIONS.find(
|
|
||||||
(opt) => opt.value === currentDetail.enterpriseStatusCode,
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
statusOption?.label || currentDetail.enterpriseStatusName
|
|
||||||
);
|
|
||||||
})()}
|
|
||||||
</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="企业规模">
|
|
||||||
{(() => {
|
|
||||||
const scaleOption = ENTERPRISE_SCALE_OPTIONS.find(
|
|
||||||
(opt) => opt.value === currentDetail.enterpriseScaleCode,
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
scaleOption?.label || currentDetail.enterpriseScaleName
|
|
||||||
);
|
|
||||||
})()}
|
|
||||||
</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="所属行业">
|
|
||||||
{currentDetail.industryName || currentDetail.industryCode}
|
|
||||||
</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="属地">
|
|
||||||
{currentDetail.districtName}
|
|
||||||
</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="联系人">
|
|
||||||
{currentDetail.principalName}
|
|
||||||
</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="联系电话">
|
|
||||||
{currentDetail.principalPhone}
|
|
||||||
</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="主要负责人">
|
|
||||||
{currentDetail.principalName}
|
|
||||||
</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="负责人电话">
|
|
||||||
{currentDetail.principalPhone}
|
|
||||||
</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="法定代表人">
|
|
||||||
{currentDetail.legalRepresentative}
|
|
||||||
</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="法人电话">
|
|
||||||
{currentDetail.legalRepresentativePhone}
|
|
||||||
</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="经营地址" span={2}>
|
|
||||||
{currentDetail.businessAddress}
|
|
||||||
</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="经度">
|
|
||||||
{currentDetail.longitude}
|
|
||||||
</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="纬度">
|
|
||||||
{currentDetail.latitude}
|
|
||||||
</Descriptions.Item>
|
|
||||||
</Descriptions>
|
|
||||||
|
|
||||||
<h4 style={{ margin: "12px 0 8px" }}>安全评价项目列表</h4>
|
|
||||||
<Table
|
|
||||||
rowKey="id"
|
|
||||||
dataSource={currentDetail.projects || []}
|
|
||||||
columns={[
|
|
||||||
{ title: "项目名称", dataIndex: "projectName" },
|
|
||||||
{
|
|
||||||
title: "评价类型",
|
|
||||||
dataIndex: "evalTypeCode",
|
|
||||||
width: 120,
|
|
||||||
render: (s) => EVAL_TYPE_MAP[s] || s || "",
|
|
||||||
},
|
|
||||||
{ title: "报告完成日期", dataIndex: "planEndDate", width: 130 },
|
|
||||||
{
|
|
||||||
title: "项目状态",
|
|
||||||
dataIndex: "status",
|
|
||||||
width: 100,
|
|
||||||
fixed: "right",
|
|
||||||
render: (phase) => {
|
|
||||||
const color =
|
|
||||||
phase === "延期"
|
|
||||||
? "error"
|
|
||||||
: phase === "正常"
|
|
||||||
? "success"
|
|
||||||
: undefined;
|
|
||||||
return <Tag color={color}>{phase || "-"}</Tag>;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
pagination={false}
|
|
||||||
size="small"
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Modal>
|
|
||||||
<BaiduMapPicker
|
<BaiduMapPicker
|
||||||
visible={mapPickerVisible}
|
visible={mapPickerVisible}
|
||||||
onCancel={() => setMapPickerVisible(false)}
|
onCancel={() => setMapPickerVisible(false)}
|
||||||
onConfirm={handleMapConfirm}
|
onConfirm={handleMapConfirm}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* 服务项目列表弹窗 */}
|
||||||
|
<Modal
|
||||||
|
title={`服务项目列表 - ${currentDetail?.customerName || ""}`}
|
||||||
|
open={projectModalOpen}
|
||||||
|
loading={customerDetailLoading}
|
||||||
|
onCancel={() => setProjectModalOpen(false)}
|
||||||
|
footer={
|
||||||
|
<Button onClick={() => setProjectModalOpen(false)}>关闭</Button>
|
||||||
|
}
|
||||||
|
width={800}
|
||||||
|
|
||||||
|
destroyOnHidden
|
||||||
|
>
|
||||||
|
<Table
|
||||||
|
rowKey="id"
|
||||||
|
dataSource={currentDetail?.projects || []}
|
||||||
|
columns={[
|
||||||
|
{ title: "项目名称", dataIndex: "projectName" },
|
||||||
|
{
|
||||||
|
title: "状态",
|
||||||
|
width: 200,
|
||||||
|
render: (_, record) => {
|
||||||
|
const nodes = parseProjectNode(record.projectNode);
|
||||||
|
if (nodes.length === 0)
|
||||||
|
return <span className="mp-progress-empty">暂无</span>;
|
||||||
|
const total = nodes.length;
|
||||||
|
const done = nodes.filter((n) => n.state === 1).length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="mp-progress-dots">
|
||||||
|
{nodes.map((n, idx) => (
|
||||||
|
<Tooltip
|
||||||
|
key={n.type || idx}
|
||||||
|
title={NODE_LABELS[n.type] || n.type}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={`mp-progress-dot ${n.state === 1 ? "mp-progress-dot-done" : "mp-progress-dot-wait"}`}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="mp-progress-text">
|
||||||
|
{done}/{total} · {Math.round((done / total) * 100)}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ title: "负责人", dataIndex: "projectLeaderName", width: 130 },
|
||||||
|
{
|
||||||
|
title: "项目状态",
|
||||||
|
dataIndex: "status",
|
||||||
|
width: 100,
|
||||||
|
fixed: "right",
|
||||||
|
render: (phase, record) => {
|
||||||
|
if (record.archiveFlag === 1) {
|
||||||
|
return <Tag color="success">已归档</Tag>;
|
||||||
|
}
|
||||||
|
if (record.projectPhaseCode === "NORMAL") {
|
||||||
|
return <Tag color="success">正常</Tag>;
|
||||||
|
}
|
||||||
|
if (record.projectPhaseCode === "DELAY") {
|
||||||
|
return <Tag color="error">已延期</Tag>;
|
||||||
|
}
|
||||||
|
return record.projectPhaseName;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "操作",
|
||||||
|
width: 100,
|
||||||
|
|
||||||
|
render: (_, record) => (
|
||||||
|
<Space>
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
onClick={() => {
|
||||||
|
props.history.push(`/container/safetyEvalBusiness/ProjectFlow?id=${record.id}`)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
pagination={false}
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -79,17 +79,7 @@ const RiskWarning = (props) => {
|
||||||
getData();
|
getData();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCloseRisk = async (record) => {
|
|
||||||
Modal.confirm({
|
|
||||||
title: "确认闭环",
|
|
||||||
content: `确定将"${record.projectName}"的风险标记为闭环吗?`,
|
|
||||||
onOk: async () => {
|
|
||||||
// TODO: 调用闭环接口
|
|
||||||
message.success("已闭环");
|
|
||||||
getData();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ title: "项目编号", dataIndex: "projectNo", width: 130 },
|
{ title: "项目编号", dataIndex: "projectNo", width: 130 },
|
||||||
|
|
@ -130,18 +120,7 @@ const RiskWarning = (props) => {
|
||||||
return cfg ? <Tag color={cfg.color}>{cfg.text}</Tag> : "";
|
return cfg ? <Tag color={cfg.color}>{cfg.text}</Tag> : "";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: "操作",
|
|
||||||
width: 130,
|
|
||||||
fixed: "right",
|
|
||||||
render: (_, record) => (
|
|
||||||
<Space>
|
|
||||||
<Button type="link" size="small" onClick={() => handleCloseRisk(record)}>
|
|
||||||
闭环
|
|
||||||
</Button>
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue