123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932 |
- import ThresholdDetail from '@/components/ThresholdDetail';
- import ThresholdModal from '@/components/ThresholdDetail/ThresholdModal';
- import { changeRecordStatus, getDumuDetail } from '@/services/eqSelfInspection';
- import { UnityAction } from '@/utils/utils';
- import { connect, useRequest } from '@umijs/max';
- import {
- Card,
- Col,
- DatePicker,
- Form,
- Input,
- Modal,
- Row,
- Select,
- Spin,
- Table,
- Tabs,
- message,
- } from 'antd';
- import dayjs from 'dayjs';
- import { useEffect, useMemo, useState } from 'react';
- import ReactZmage from 'react-zmage';
- import styles from './PatrolReportDetail.less';
- function Detail(props) {
- const { data, userList, projectId, dispatch, loading = false } = props;
- const [select, setSelect] = useState();
- const [dumuList, setDumuList] = useState([]);
- const sendMessageToUnity = (select, data) => {
- setSelect(select);
- // console.log(data);
- if (window.HightlightEquipment) {
- window.HightlightEquipment(data);
- }
- };
- const getTextColor = (status) => {
- switch (status) {
- case '警告':
- return '#FFE26D';
- case '异常':
- return '#FF8600';
- case '正常':
- return '#60FE76';
- default:
- return '#60FE76';
- }
- };
- const { run: detailRun } = useRequest(getDumuDetail, {
- manual: true,
- fetchKey: (id) => id,
- onSuccess: (data) => {
- var item = dumuList?.find((child) => child.id === data.id);
- if (item) {
- item.url = base64ToImageUrl(data.event_bg);
- }
- setDumuList([...dumuList]);
- },
- });
- const result = useMemo(() => {
- var resultArr = [];
- var tempResult = data?.PatrolResult;
- var tempArr = tempResult?.split(';');
- if (tempArr?.length > 0) {
- tempArr?.forEach((item, index) => {
- var tempItem = item;
- var itemSplit = tempItem.split(':');
- if (itemSplit?.length > 1) {
- var label = '';
- var value = itemSplit[1];
- if (index === 0) label = '设备自检';
- else if (index === 1) label = '工艺自检';
- else {
- label = '安全隐患';
- value = data?.secureStatus === 0 ? '正常' : '异常';
- }
- resultArr.push({
- label,
- value,
- color: getTextColor(value),
- });
- }
- });
- }
- return resultArr;
- }, [data]);
- useEffect(() => {
- dispatch({
- type: 'eqSelfInspection/fetchUserList',
- payload: {
- projectId,
- },
- });
- }, []);
- useEffect(() => {
- setDumuList(data?.dumuList);
- data?.dumuList?.map((item) => {
- detailRun(item.id);
- });
- }, [data?.dumuList]);
- // useEffect(() => {
- // dispatch({
- // type: 'eqSelfInspection/getPatrolRecordMandateInfo',
- // payload: {
- // extend_id: data.Id,
- // project_id: projectId,
- // mandate_type: 2
- // },
- // });
- // }, [data]);
- return (
- <Spin spinning={loading}>
- <div className={styles.card}>
- <Card title="自检报告">
- <div>
- <Row>
- <Col span={24} style={{ fontSize: 20 }}>
- 自检时间:{data?.CreatedTime}
- </Col>
- </Row>
- <Row>
- <Col span={8} style={{ fontSize: 20 }}>
- 自检路线:{data?.RouteInfo?.Name}
- </Col>
- <Col span={8} style={{ fontSize: 20 }}>
- 工艺段:{data?.RouteInfo?.GroupID}
- </Col>
- </Row>
- <Row>
- {result?.map((item) => {
- return (
- <Col span={8} style={{ display: 'flex', fontSize: 20 }}>
- <div>{item?.label}:</div>
- <div style={{ color: item.color }}>{item?.value}</div>
- </Col>
- );
- })}
- </Row>
- {/* <Row>
- <Col span={8} style={{ display: 'flex', fontSize: 20 }}>
- <div>任务类型:</div>
- <div style={{ color: '#7bfffb' }}>系统自检</div>
- </Col>
- <Col span={8} style={{ display: 'flex', fontSize: 20 }}>
- <div>任务负责人:</div>
- <div style={{ color: '#fff' }}>{userList.find(item => item.ID === mandateInfo?.ResponsiblePeople)?.CName || ''}</div>
- </Col>
- <Col span={8} style={{ display: 'flex', fontSize: 20 }}>
- <div>任务状态:</div>
- <div style={{ color: '#7bfffb' }}>{getStatusText(mandateInfo?.Status)}</div>
- </Col>
- </Row> */}
- </div>
- </Card>
- </div>
- {/* 设备自检报告 */}
- <ReportCom
- sendMessageToUnity={sendMessageToUnity}
- select={select}
- waringData={data?.extendWarningData}
- allData={data?.extendWarningAllData}
- key="extend"
- type={'extend'}
- userList={userList}
- title={
- <>
- <div className={styles.text}>设备自检报告</div>
- </>
- }
- ></ReportCom>
- {/* 工艺自检报告"> */}
- <div>
- <div className={styles.tabBarExtraContent}>
- <div className={styles.text} style={{ height: 52, width: '50%' }}>
- <>
- <div>工艺自检报告</div>
- </>
- </div>
- <div className={styles.abnormal}>
- <div className={styles.text} style={{ float: 'right' }}>
- 异常({data?.FaultAnalysis?.length || 0})
- </div>
- </div>
- </div>
- <AalysisTable
- onClickItem={sendMessageToUnity}
- select={select}
- data={data}
- />
- </div>
- {/* 安全隐患自检报告"> */}
- <div>
- <div className={styles.tabBarExtraContent}>
- <div className={styles.text} style={{ height: 52, width: '50%' }}>
- <>
- <div>安全隐患自检报告</div>
- </>
- </div>
- </div>
- {/* 环境异常 */}
- <ReportCom
- sendMessageToUnity={sendMessageToUnity}
- select={select}
- waringData={data?.sensorWaringData}
- allData={data?.sensor}
- data={data?.sensorWaringData}
- key="sensor"
- type={'sensor'}
- userList={userList}
- title={<div style={{ color: '#7bfffb', fontSize: 22 }}>环境异常</div>}
- ></ReportCom>
- {/* 安防检测异常 */}
- <ReportDumCom
- data={dumuList}
- title={
- <div style={{ color: '#7bfffb', fontSize: 22 }}>安防检测异常</div>
- }
- />
- {/* 电器检测异常 */}
- <ReportCom
- sendMessageToUnity={sendMessageToUnity}
- select={select}
- waringData={[]}
- allData={[]}
- key="extend"
- type={'extend'}
- userList={userList}
- title={
- <div style={{ color: '#7bfffb', fontSize: 22 }}>电气检测异常</div>
- }
- ></ReportCom>
- {/* 密闭空间检测异常 */}
- <ReportCom
- sendMessageToUnity={sendMessageToUnity}
- select={select}
- waringData={[]}
- allData={[]}
- key="extend"
- type={'extend'}
- userList={userList}
- title={
- <div style={{ color: '#7bfffb', fontSize: 22 }}>
- 密闭空间检测异常
- </div>
- }
- ></ReportCom>
- </div>
- {/* </Card> */}
- </Spin>
- );
- }
- export function DeviceTable(props) {
- const {
- onClickItem,
- data = {},
- items,
- onErrorHandle,
- select,
- userList,
- type,
- } = props;
- const { ProjectId, Id } = data;
- const [loading, setLoading] = useState(false);
- const [visible, setVisible] = useState(false);
- const [errVisible, setErrVisible] = useState(false);
- const [currentItem, setCurrentItem] = useState({});
- const isSensor = type == 'sensor';
- const onClickThreshold = (record) => {
- setCurrentItem(record);
- setVisible(true);
- };
- const onClickError = (record) => {
- setCurrentItem(record);
- setErrVisible(true);
- };
- const handleError = async (values) => {
- setLoading(true);
- var res = await changeRecordStatus({
- ...values,
- Id: currentItem.Id,
- DeviceCode: currentItem.DeviceCode,
- DeviceName: currentItem.DeviceName,
- RecordId: data.Id,
- RepairMan: values.RepairMan * 1,
- });
- setLoading(false);
- if (res) {
- message.success('操作成功');
- setErrVisible(false);
- }
- };
- const columns = [
- {
- title: '设备名称',
- width: '25%',
- dataIndex: 'DeviceName',
- },
- {
- title: '巡检项',
- width: '20%',
- dataIndex: 'TemplateItem.Name',
- },
- // {
- // title: '设备位号',
- // width: '16%',
- // dataIndex: 'DeviceCode',
- // },
- {
- title: '设定值范围',
- width: '30%',
- render: (record) => (
- <ThresholdDetail
- current={record.Value || 0}
- data={record || {}}
- // onClick={() => onClickThreshold(record)}
- />
- ),
- },
- {
- title: '状态',
- width: '13%',
- dataIndex: 'Status',
- render: (Status) => {
- switch (Status) {
- case -1:
- case 0:
- return (
- <div>
- <i
- className={styles.iconStatus}
- style={{ background: '#60FE76' }}
- ></i>
- 正常
- </div>
- );
- case 1:
- return (
- <div>
- <i
- className={styles.iconStatus}
- style={{ background: '#FF8600' }}
- ></i>
- 异常
- </div>
- );
- case 2:
- return (
- <div>
- <i
- className={styles.iconStatus}
- style={{ background: '#FFE26D' }}
- ></i>
- 警告
- </div>
- );
- }
- },
- },
- ];
- const handleClickItem = (data) => {
- if (!isSensor) {
- onClickItem(`DeviceTable-${data.Id}`, {
- type: data.Status,
- deviceCode: data.DeviceCode,
- });
- } else {
- onClickItem(`DeviceTable-${data.Id}`, {
- // type: data.Status,
- deviceCode: data.DeviceCode,
- value: Number(data.Value || 0),
- threshold: data.JsonNumThreshold,
- });
- UnityAction.sendMsg('SinglePowerEnvironFromWeb', JSON.stringify(data));
- }
- };
- useEffect(() => {
- console.log('温控', items);
- if (isSensor)
- UnityAction.sendMsg('PowerEnvironsFromWeb', JSON.stringify(items));
- }, [items]);
- if (!isSensor) {
- columns.push({
- title: '操作',
- width: '12%',
- render: (record) =>
- record.Status == 1 && (
- <a style={{ color: '#7BFFFB' }} onClick={() => onClickError(record)}>
- 异常处理
- </a>
- ),
- });
- }
- return (
- <div>
- <Table
- columns={columns}
- dataSource={items}
- rowKey="Id"
- onRow={(data) => {
- return {
- onClick: () => {
- handleClickItem(data);
- },
- };
- }}
- locale={{
- emptyText: <Empty />,
- }}
- rowClassName={(record) =>
- `DeviceTable-${record.Id}` == select ? styles.select : null
- }
- />
- <ThresholdModal
- open={visible}
- data={currentItem.JsonNumThreshold}
- onClose={() => setVisible(false)}
- />
- <ErrorHandleModal
- open={errVisible}
- userList={userList}
- onCancel={() => setErrVisible(false)}
- onOk={handleError}
- />
- </div>
- );
- }
- function AalysisTable(props) {
- const { onClickItem, data = {}, select } = props;
- const { FaultAnalysis } = data;
- const columns = [
- {
- title: '异常名称',
- width: '18%',
- dataIndex: 'device_name',
- },
- // {
- // title: '位号',
- // width: '15%',
- // dataIndex: 'device_code',
- // },
- {
- title: '可能原因',
- width: '30%',
- render: (record) => record.reason,
- },
- {
- title: '解决方案',
- width: '52%',
- render: (record) => {
- if (record.fix_plan instanceof Array) {
- return (
- <div>
- {record.fix_plan.map((item) => (
- <div>
- {item.content}
- <br />
- </div>
- ))}
- </div>
- );
- } else {
- return record.fix_plan;
- }
- },
- },
- ];
- return (
- <div>
- <Table
- columns={columns}
- dataSource={FaultAnalysis}
- rowKey="device_code"
- onRow={(data) => {
- return {
- onClick: () => {
- onClickItem(`AalysisTable-${data.device_code}`, {
- deviceCode: data.device_code,
- });
- }, // 点击行
- };
- }}
- locale={{
- emptyText: <Empty />,
- }}
- rowClassName={(record) =>
- `AalysisTable-${record.device_code}` == select ? styles.select : null
- }
- />
- </div>
- );
- }
- function ErrorHandleModal(props) {
- const { visible, onCancel, onOk, userList } = props;
- const [form] = Form.useForm();
- const status = form.getFieldValue('Status');
- const handleOk = () => {
- form.validateFields((error, values) => {
- if (error) return;
- onOk({
- ...values,
- PlanTime: values?.PlanTime?.format('YYYY-MM-DD HH:mm:ss'),
- });
- });
- };
- return (
- <Modal
- title="异常处理"
- open={visible}
- onCancel={onCancel}
- onOk={handleOk}
- destroyOnClose
- >
- <Form labelCol={{ span: 7 }} wrapperCol={{ span: 16 }}>
- <Form.Item label="异常处理备注" name="ExceptionHandling">
- <Input.TextArea />
- </Form.Item>
- <Form.Item
- label="审核状态"
- name="Status"
- rules={[{ required: true, message: '请选择验收状态' }]}
- >
- <Select style={{ width: '100%' }} placeholder="请选择验收状态">
- <Select.Option value={1}>已派遣</Select.Option>
- <Select.Option value={2}>已通过</Select.Option>
- </Select>
- </Form.Item>
- <Form.Item
- label="维修人"
- name="RepairMan"
- rules={[{ required: true, message: '请选择维修人' }]}
- >
- <Select
- showSearch
- placeholder="请选择维修人"
- filterOption={(input, option) =>
- option.props.children.indexOf(input) >= 0
- }
- style={{ width: '100%' }}
- >
- {userList?.map((item) => (
- <Select.Option key={item.ID}>{item.CName}</Select.Option>
- ))}
- </Select>
- </Form.Item>
- {status == 1 && (
- <>
- <Form.Item
- label="难度级别"
- name="DifficultyLevel"
- rules={[{ required: true, message: '请选择难度级别' }]}
- >
- <Select placeholder="请选择难度级别" style={{ width: '100%' }}>
- <Select.Option value={0}>大修</Select.Option>
- <Select.Option value={1}>项目维修</Select.Option>
- <Select.Option value={2}>小修</Select.Option>
- </Select>
- </Form.Item>
- <Form.Item
- label="维修方式"
- name="RepairType"
- rules={[{ required: true, message: '请选择维修方式' }]}
- >
- <Select placeholder="请选择维修方式" style={{ width: '100%' }}>
- <Select.Option value={0}>自维</Select.Option>
- <Select.Option value={1}>外委</Select.Option>
- </Select>
- </Form.Item>
- <Form.Item
- label="计划完成日期"
- name="PlanTime"
- rules={[{ required: true, message: '请选择计划完成日期' }]}
- >
- <DatePicker />
- </Form.Item>
- </>
- )}
- </Form>
- </Modal>
- );
- }
- export function WarningTable(props) {
- const {
- onClickItem,
- data = {},
- onErrorHandle,
- select,
- userList,
- type,
- items,
- } = props;
- const { ProjectId, Id } = data;
- const [loading, setLoading] = useState(false);
- const [visible, setVisible] = useState(false);
- const [errVisible, setErrVisible] = useState(false);
- const [currentItem, setCurrentItem] = useState({});
- const isSensor = type == 'sensor';
- const onClickThreshold = (record) => {
- setCurrentItem(record);
- setVisible(true);
- };
- const onClickError = (record) => {
- setCurrentItem(record);
- setErrVisible(true);
- };
- const handleError = async (values) => {
- setLoading(true);
- var res = await changeRecordStatus({
- ...values,
- Id: currentItem.Id,
- DeviceCode: currentItem.DeviceCode,
- DeviceName: currentItem.DeviceName,
- RecordId: data.Id,
- RepairMan: values.RepairMan * 1,
- });
- setLoading(false);
- if (res) {
- message.success('操作成功');
- setErrVisible(false);
- }
- };
- const columns = [
- {
- title: '设备名称',
- width: '25%',
- dataIndex: 'DeviceName',
- },
- {
- title: '巡检项',
- width: '20%',
- dataIndex: 'TemplateItem.Name',
- },
- // {
- // title: '设备位号',
- // width: '16%',
- // dataIndex: 'DeviceCode',
- // },
- {
- title: '设定值范围',
- width: '30%',
- render: (record) => (
- <ThresholdDetail
- current={record.Value || 0}
- data={record || {}}
- // onClick={() => onClickThreshold(record)}
- />
- ),
- },
- {
- title: '状态',
- width: '13%',
- dataIndex: 'Status',
- render: (Status) => {
- switch (Status) {
- case -1:
- case 0:
- return (
- <div>
- <i
- className={styles.iconStatus}
- style={{ background: '#60FE76' }}
- ></i>
- 正常
- </div>
- );
- case 1:
- return (
- <div>
- <i
- className={styles.iconStatus}
- style={{ background: '#FF8600' }}
- ></i>
- 异常
- </div>
- );
- case 2:
- return (
- <div>
- <i
- className={styles.iconStatus}
- style={{ background: '#FFE26D' }}
- ></i>
- 警告
- </div>
- );
- }
- },
- },
- ];
- const handleClickItem = (data) => {
- if (!isSensor) {
- onClickItem(`DeviceTable-${data.Id}`, {
- type: data.Status,
- deviceCode: data.DeviceCode,
- });
- } else {
- onClickItem(`DeviceTable-${data.Id}`, {
- // type: data.Status,
- deviceCode: data.DeviceCode,
- value: Number(data.Value || 0),
- threshold: data.JsonNumThreshold,
- });
- UnityAction.sendMsg('SinglePowerEnvironFromWeb', JSON.stringify(data));
- }
- };
- if (!isSensor) {
- columns.push({
- title: '操作',
- width: '12%',
- render: (record) =>
- record.Status == 1 && (
- <a style={{ color: '#7BFFFB' }} onClick={() => onClickError(record)}>
- 异常处理
- </a>
- ),
- });
- }
- useEffect(() => {
- if (isSensor)
- UnityAction.sendMsg('PowerEnvironsFromWeb', JSON.stringify(items));
- }, [items]);
- return (
- <div>
- {/* <div className="table-total">当前列表总数 {Items?.length || 0}</div> */}
- <Table
- columns={columns}
- dataSource={items}
- rowKey="Id"
- onRow={(data) => {
- return {
- onClick: () => {
- handleClickItem(data);
- },
- };
- }}
- locale={{
- emptyText: <Empty />,
- }}
- rowClassName={(record) =>
- `DeviceTable-${record.Id}` == select ? styles.select : null
- }
- />
- <ThresholdModal
- open={visible}
- data={currentItem.JsonNumThreshold}
- onClose={() => setVisible(false)}
- />
- <ErrorHandleModal
- open={errVisible}
- userList={userList}
- onCancel={() => setErrVisible(false)}
- onOk={handleError}
- />
- </div>
- );
- }
- function ReportCom(props) {
- const {
- sendMessageToUnity,
- select,
- waringData = [],
- allData = [],
- userList,
- type,
- title,
- data,
- } = props;
- const [activeKey, setActiveKey] = useState('1');
- const handleTabsChange = (activeKey) => {
- setActiveKey(activeKey);
- };
- return (
- <div className={styles.detailCard}>
- <Tabs
- defaultActiveKey="1"
- tabBarExtraContent={
- <div className={styles.tabBarExtraContent}>{title} </div>
- }
- onChange={handleTabsChange}
- >
- <Tabs.TabPane tab={`异常/警告(${waringData.length || 0})`} key="1">
- {activeKey == '1' && (
- <WarningTable
- onClickItem={sendMessageToUnity}
- select={select}
- items={waringData}
- key={type}
- data={data}
- type={type}
- userList={userList}
- />
- )}
- </Tabs.TabPane>
- <Tabs.TabPane tab={`全部(${allData.length || 0})`} key="2">
- {activeKey == '2' && (
- <DeviceTable
- onClickItem={sendMessageToUnity}
- select={select}
- items={allData}
- data={data}
- key={type}
- type={type}
- userList={userList}
- />
- )}
- </Tabs.TabPane>
- </Tabs>
- </div>
- );
- }
- function ReportDumCom(props) {
- const { data = [], title } = props;
- const columns = [
- {
- title: '报警时间',
- dataIndex: 'event_time',
- render: (time) => dayjs(time).format('YYYY-MM-DD HH:mm:ss'),
- },
- {
- title: '设备名称',
- dataIndex: 'device_name',
- },
- {
- title: '报警类型',
- dataIndex: 'event_type',
- // render: type => alarmType[type],
- },
- {
- title: '报警图片',
- render: (item) => (
- <ReactZmage
- controller={{
- // 关闭按钮
- close: true,
- // 旋转按钮
- rotate: true,
- // 缩放按钮
- zoom: false,
- // 下载按钮
- download: false,
- // 翻页按钮
- flip: false,
- // 多页指示
- pagination: false,
- }}
- backdrop="rgba(255,255,255,0.5)"
- style={{ height: '90px' }}
- src={item.url}
- />
- ),
- },
- ];
- return (
- <div>
- <div className={styles.tabBarExtraContent}>
- <div className={styles.text} style={{ height: 52, width: '60%' }}>
- <>
- <div>{title}</div>
- </>
- </div>
- <div className={styles.abnormal}>
- <div className={styles.text} style={{ float: 'right' }}>
- 异常({data?.length || 0})
- </div>
- </div>
- </div>
- <Table
- bordered
- rowKey="event_time"
- columns={columns}
- dataSource={data}
- locale={{
- emptyText: <Empty />,
- }}
- />
- </div>
- );
- }
- function base64ToImageUrl(base64String) {
- const byteCharacters = atob(base64String);
- const byteArrays = [];
- for (let i = 0; i < byteCharacters.length; i++) {
- byteArrays.push(byteCharacters.charCodeAt(i));
- }
- const byteArray = new Uint8Array(byteArrays);
- const blob = new Blob([byteArray], { type: 'image/png' });
- const imageUrl = URL.createObjectURL(blob);
- return imageUrl;
- }
- function Empty() {
- return (
- <div style={{}}>
- {/* <img src={require('@/assets/empty.png')} style={{ margin: '20px 0' }} /> */}
- <p style={{ textAlign: 'center' }}>自检正常</p>
- </div>
- );
- }
- export default connect(({ eqSelfInspection }) => ({
- userList: eqSelfInspection.userList,
- mandateInfo: eqSelfInspection.mandateInfo,
- }))(Detail);
|