Browse Source

fix(compiler): 新增故障模块

shylock 1 year ago
parent
commit
334e8b4ed0

+ 4 - 3
config/proxy.ts

@@ -18,14 +18,15 @@ export default {
     },
     '/web/': {
       // 要代理的地址
-      target: 'http://192.168.0.224:8199', // 开发
+      // target: 'http://192.168.0.224:8199', // 开发
       // target: 'http://192.168.0.18:8199', // 秀本地
-      // target: 'https://app.yongxulvjian.com', // 生产
+      target: 'https://app.yongxulvjian.com', // 生产
       changeOrigin: true,
     },
     '/s/': {
       // 要代理的地址
-      target: 'http://192.168.0.224:18199/',
+      // target: 'http://192.168.0.224:18199/', // 开发
+      target: 'https://app.yongxulvjian.com', // 生产
       changeOrigin: true,
     },
   },

+ 7 - 0
config/routes.ts

@@ -139,6 +139,13 @@
     layout: false,
     component: './DataBoard',
   },
+  // 故障管理
+  {
+    path: '/deviceFaults',
+    name: '版本管理',
+    icon: 'Appstore',
+    component: './DeviceFaults',
+  },
   // 房间列表
   {
     path: '/roomList',

+ 66 - 0
src/pages/DeviceFaults/check.tsx

@@ -0,0 +1,66 @@
+import React from 'react';
+import { Descriptions, Modal, Image } from 'antd';
+
+interface checkProps {
+  params: any;
+  visible: boolean;
+  callback: () => void;
+}
+
+/**
+ * 故障详情
+ * @param props
+ * @constructor
+ */
+const Check: React.FC<checkProps> = (props) => {
+  const { visible, callback, params } = props;
+
+  const onOk = () => {
+    callback();
+  };
+
+  const onCancel = () => {
+    callback();
+  };
+  return (
+    <Modal title="查看详情" open={visible} onOk={onOk} onCancel={onCancel} width={1000}>
+      <Descriptions title="报警详情" bordered column={4}>
+        <Descriptions.Item label="设备编号" span={2}>
+          {params.device_code}
+        </Descriptions.Item>
+        <Descriptions.Item label="分控编号" span={2}>
+          {params.sub_device_code}
+        </Descriptions.Item>
+        <Descriptions.Item label="故障码" span={2}>
+          {params.code}
+        </Descriptions.Item>
+        <Descriptions.Item label="故障描述" span={2}>
+          {params.desc}
+        </Descriptions.Item>
+        <Descriptions.Item label="故障状态" span={2}>
+          {params.status}
+        </Descriptions.Item>
+        <Descriptions.Item label="上报时间" span={2}>
+          {params.created_at}
+        </Descriptions.Item>
+        <Descriptions.Item label="通知时间" span={2}>
+          {params.notice_time}
+        </Descriptions.Item>
+        <Descriptions.Item label="客户名称" span={2}>
+          {params.user_name}
+        </Descriptions.Item>
+        <Descriptions.Item label="解决办法" span={4}>
+          {params.solution}
+        </Descriptions.Item>
+        <Descriptions.Item label="图片">
+          {params && params.files
+            ? params.files.map((res: any) => {
+                return <Image width={50} key={res.record_id} src={res.url} />;
+              })
+            : null}
+        </Descriptions.Item>
+      </Descriptions>
+    </Modal>
+  );
+};
+export default Check;

+ 232 - 0
src/pages/DeviceFaults/index.tsx

@@ -0,0 +1,232 @@
+import React, { useEffect, useState } from 'react';
+import { PageContainer } from '@ant-design/pro-components';
+import { Button, Card, Form, Input, Space, Table } from 'antd';
+import type { ColumnsType } from 'antd/es/table';
+import { queryDeviceFaults, queryDeviceFaultsDetail } from '@/services/DeviceFaults';
+import moment from 'moment';
+import { ReloadOutlined, SearchOutlined } from '@ant-design/icons';
+import UpdateFaults from '@/pages/DeviceFaults/updateFaults';
+import Check from '@/pages/DeviceFaults/check';
+
+interface DataType {
+  key: React.ReactNode;
+  user_name: string;
+  record_id: string;
+  device_code: string;
+  code: string;
+  desc: string;
+  created_at: string;
+  status: number;
+}
+
+const DeviceFaults: React.FC = () => {
+  const [form] = Form.useForm();
+  const [loading, setLoading] = useState(false);
+  const [dataList, setDataList] = useState([]);
+  const [pagination, setPagination] = useState({ total: 0, current: 1, pageSize: 10 });
+  const [searchData, setSearchData] = useState<object | null>({});
+  const [visible, setVisible] = useState(false);
+  const [faultsData, setFaultsData] = useState(null);
+  const [checkVisible, setCheckVisible] = useState(false);
+  const [checkData, setCheckData] = useState(null);
+
+  const getList = () => {
+    const params = {
+      q: 'page',
+      current: pagination.current,
+      pageSize: pagination.pageSize,
+      ...searchData,
+    };
+    queryDeviceFaults(params).then((res) => {
+      if (res && res.code === 0) {
+        setDataList(res.data.list);
+        setPagination(res.data.pagination);
+        setLoading(false);
+      }
+    });
+  };
+
+  // 初始化数据
+  useEffect(() => {
+    setLoading(true);
+    getList();
+  }, []);
+
+  //  更新
+  const toUpdate = (record: any) => {
+    queryDeviceFaultsDetail(record.record_id).then((res) => {
+      if (res && res.code === 0) {
+        setVisible(true);
+        setFaultsData(res.data);
+      }
+    });
+  };
+
+  // 查询
+  const onFinish = () => {
+    form.validateFields().then((data) => {
+      setLoading(true);
+      setSearchData(data);
+    });
+  };
+
+  //  重置
+  const onReset = () => {
+    form.resetFields();
+    setLoading(true);
+    setSearchData(null);
+  };
+
+  useEffect(() => {
+    getList();
+  }, [searchData]);
+
+  // 分页切换
+  const tableChange = (page: any) => {
+    setLoading(true);
+    const params = {
+      q: 'page',
+      current: page.current,
+      pageSize: page.pageSize,
+      ...searchData,
+    };
+    queryDeviceFaults(params).then((res) => {
+      if (res && res.code === 0) {
+        setDataList(res.data.list);
+        setPagination(res.data.pagination);
+        setLoading(false);
+      }
+    });
+  };
+
+  // 更新回调
+  const onFaultsCallback = () => {
+    setVisible(false);
+    getList();
+    setFaultsData(null);
+  };
+
+  //  查看详情
+  const onCheck = (record: any) => {
+    setCheckVisible(true);
+    setCheckData(record);
+  };
+
+  const onCheckCallback = () => {
+    setCheckVisible(false);
+  };
+
+  const columns: ColumnsType<DataType> = [
+    {
+      title: '序号',
+      align: 'center',
+      key: 'index',
+      render: (_: any, row: any, index: number) => index + 1,
+    },
+    {
+      title: '设备编号',
+      dataIndex: 'device_code',
+      key: 'device_code',
+    },
+    {
+      title: '故障码',
+      dataIndex: 'code',
+      key: 'code',
+    },
+    {
+      title: '故障描述',
+      dataIndex: 'desc',
+      key: 'desc',
+    },
+    {
+      title: '故障状态',
+      dataIndex: 'status',
+      key: 'status',
+      render: (v) => <span>{{ 0: '未处理', 1: '已处理' }[v]}</span>,
+    },
+    {
+      title: '上报时间',
+      dataIndex: 'created_at',
+      key: 'created_at',
+      render: (v) => v && <span>{moment(v).format('YYYY-MM-DD HH:mm')}</span>,
+    },
+    {
+      title: '客户名称',
+      dataIndex: 'user_name',
+      key: 'user_name',
+    },
+    {
+      title: '操作',
+      key: 'action',
+      render: (_, record) => (
+        <Space size="middle">
+          <a
+            onClick={() => {
+              toUpdate(record);
+            }}
+          >
+            更新
+          </a>
+          <a
+            onClick={() => {
+              onCheck(record);
+            }}
+          >
+            查看详情
+          </a>
+        </Space>
+      ),
+    },
+  ];
+
+  const paginationProps = {
+    showSizeChanger: true,
+    showQuickJumper: true,
+    showTotal: (total: number) => {
+      return <span> 共 {total}条 </span>;
+    },
+    ...pagination,
+  };
+
+  return (
+    <PageContainer>
+      <div>
+        <Card>
+          <Form form={form} layout="inline" onFinish={onFinish}>
+            <Form.Item name="device_code" label="设备编号">
+              <Input placeholder="请输入设备编号" />
+            </Form.Item>
+            <Form.Item style={{ marginBottom: '10px' }}>
+              <Space>
+                <Button type="primary" htmlType="submit">
+                  <SearchOutlined />
+                  查询
+                </Button>
+                <Button htmlType="button" onClick={onReset}>
+                  <ReloadOutlined />
+                  重置
+                </Button>
+              </Space>
+            </Form.Item>
+          </Form>
+          <Table
+            columns={columns}
+            dataSource={dataList}
+            rowKey={(record) => record.record_id}
+            pagination={paginationProps}
+            loading={loading}
+            onChange={tableChange}
+          />
+
+          {visible && faultsData && (
+            <UpdateFaults visible={visible} params={faultsData} editCallback={onFaultsCallback} />
+          )}
+          {checkVisible && (
+            <Check params={checkData} visible={checkVisible} callback={onCheckCallback} />
+          )}
+        </Card>
+      </div>
+    </PageContainer>
+  );
+};
+export default DeviceFaults;

+ 107 - 0
src/pages/DeviceFaults/updateFaults.tsx

@@ -0,0 +1,107 @@
+import React, { useState } from 'react';
+import { Col, Form, Input, message, Modal, Row } from 'antd';
+import UploadImage from '@/components/UploadImage';
+import { updateDeviceFaults } from '@/services/DeviceFaults';
+
+interface editPros {
+  visible: boolean;
+  editCallback: () => void;
+  params: any;
+}
+
+/**
+ * 更新故障
+ * @param props
+ * @constructor
+ */
+const UpdateFaults: React.FC<editPros> = (props) => {
+  const { params, visible, editCallback } = props;
+  const [form] = Form.useForm();
+  const [filesList, setFilesList] = useState([]);
+
+  const { TextArea } = Input;
+
+  const onOk = () => {
+    form.validateFields().then((values) => {
+      if (values) {
+        const data = { ...values };
+        data.files = filesList;
+        data.record_id = params.record_id;
+        updateDeviceFaults(data)
+          .then((res) => {
+            if (res && res.code === 0) {
+              message.success('更新成功');
+              editCallback();
+            } else {
+              message.error(res?.message);
+              editCallback();
+            }
+          })
+          .catch((e) => {
+            message.error(e?.message);
+            editCallback();
+          });
+      }
+    });
+  };
+
+  const onCancel = () => {
+    editCallback();
+  };
+
+  // 上传图片回调
+  const onUploadChange = (files: any) => {
+    if (files && files.length) {
+      const arr: any = [];
+      files.forEach((el: any) => {
+        arr.push({ url: el?.response?.data?.url });
+      });
+      setFilesList(arr);
+    }
+  };
+
+  const formItemLayout24 = {
+    labelCol: { span: 3 },
+    wrapperCol: { span: 21 },
+  };
+
+  if (params) {
+    return (
+      <Modal title="更新" open={visible} onOk={onOk} onCancel={onCancel} width={800}>
+        <Form form={form}>
+          <Row>
+            <Col span={24}>
+              <Form.Item
+                {...formItemLayout24}
+                name="solution"
+                label="解决办法"
+                rules={[{ required: true, message: '请输入解决办法' }]}
+                initialValue={params?.solution}
+              >
+                <TextArea placeholder="请输入解决办法" />
+              </Form.Item>
+            </Col>
+            <Col span={24}>
+              <Form.Item
+                {...formItemLayout24}
+                name="files"
+                label="上传图片"
+                rules={[{ required: true, message: '请选择图片' }]}
+                initialValue={params?.files || []}
+              >
+                <UploadImage
+                  maxCount={9}
+                  onChange={onUploadChange}
+                  value={[{ url: params?.url }]}
+                />
+              </Form.Item>
+            </Col>
+          </Row>
+        </Form>
+      </Modal>
+    );
+  } else {
+    return null;
+  }
+};
+export default UpdateFaults;

+ 142 - 142
src/pages/setting/UserManagement/edit.tsx

@@ -1,9 +1,9 @@
 import React, { useEffect, useState } from 'react';
-import type { UploadProps } from 'antd';
-import { Cascader } from 'antd';
-import { Checkbox, Col, Form, Input, message, Modal, Row, Select, Upload } from 'antd';
-import { createUser, editUser, queryRoleUser, queryTreeList } from '@/services/setting';
-import { LoadingOutlined, PlusOutlined } from '@ant-design/icons';
+// import type { UploadProps } from 'antd';
+// import { Cascader } from 'antd';
+import { Checkbox, Col, Form, Input, message, Modal, Row } from 'antd';
+import { createUser, editUser } from '@/services/setting';
+// import { LoadingOutlined, PlusOutlined } from '@ant-design/icons';
 import md5 from 'js-md5';
 import { queryRoleList } from '@/services/role';
 import { infoQuery } from '@/services/ReportingManagement';
@@ -22,24 +22,24 @@ interface userEditPros {
 const Edit: React.FC<userEditPros> = (props) => {
   const { visible, editCallback, detailData } = props;
   const [form] = Form.useForm();
-  const uploadHeaders = { Authorization: `${localStorage.getItem('token')}` };
-  const [fileUrl, setFileUrl]: any = useState(
-    detailData && detailData.photo ? detailData.photo : '',
-  );
-  const [loading, setLoading] = useState(false);
+  // const uploadHeaders = { Authorization: `${localStorage.getItem('token')}` };
+  // const [fileUrl, setFileUrl]: any = useState(
+  //   detailData && detailData.photo ? detailData.photo : '',
+  // );
+  // const [loading, setLoading] = useState(false);
   const [roleList, setRoleList] = useState([]);
-  const [selectList, setSelectList] = useState([]);
-  const [areaList, setAreaList] = useState([]);
+  // const [selectList, setSelectList] = useState([]);
+  // const [areaList, setAreaList] = useState([]);
   const [isCurrent, setIsCurrent] = useState(false);
 
-  const getBase64 = (img: any) => {
-    const reader = new FileReader();
-    reader.readAsDataURL(img);
-    reader.onloadend = () => {
-      const url = reader.result;
-      setFileUrl(url);
-    };
-  };
+  // const getBase64 = (img: any) => {
+  //   const reader = new FileReader();
+  //   reader.readAsDataURL(img);
+  //   reader.onloadend = () => {
+  //     const url = reader.result;
+  //     setFileUrl(url);
+  //   };
+  // };
 
   useEffect(() => {
     // 编辑时
@@ -73,20 +73,20 @@ const Edit: React.FC<userEditPros> = (props) => {
       });
 
       // 编辑时,所属地区根据角色id回显数据
-      const data = [...detailData?.user_role].sort((a: any, b: any) => b.level - a.level);
-      if (data && data.length) {
-        const param = {
-          q: 'list',
-          role_id: data[0].role_id,
-          user_id: detailData.record_id,
-        };
-        // 根据角色id请求用户列表接口 保证所属名称字段编辑时回显
-        queryRoleUser(param).then((item) => {
-          if (item.code === 0) {
-            setSelectList(item?.data || []);
-          }
-        });
-      }
+      // const data = [...detailData?.user_role].sort((a: any, b: any) => b.level - a.level);
+      // if (data && data.length) {
+      //   const param = {
+      //     q: 'list',
+      //     role_id: data[0].role_id,
+      //     user_id: detailData.record_id,
+      //   };
+      //   // 根据角色id请求用户列表接口 保证所属名称字段编辑时回显
+      //   queryRoleUser(param).then((item) => {
+      //     if (item.code === 0) {
+      //       setSelectList(item?.data || []);
+      //     }
+      //   });
+      // }
     } else {
       // 新增
       // 角色列表
@@ -98,61 +98,61 @@ const Edit: React.FC<userEditPros> = (props) => {
     }
 
     //  地区列表
-    queryTreeList({ q: 'tree' }).then((res) => {
-      if (res && res.code === 0) {
-        setAreaList(res.data.list || []);
-      }
-    });
+    // queryTreeList({ q: 'tree' }).then((res) => {
+    //   if (res && res.code === 0) {
+    //     setAreaList(res.data.list || []);
+    //   }
+    // });
   }, []);
 
-  const handleLevel = (values: any) => {
-    const data: any = roleList.filter((option: { record_id: string }) =>
-      values.includes(option.record_id),
-    );
-    return [...data].sort((a: any, b: any) => b.level - a.level);
-  };
+  // const handleLevel = (values: any) => {
+  //   const data: any = roleList.filter((option: { record_id: string }) =>
+  //     values.includes(option.record_id),
+  //   );
+  //   return [...data].sort((a: any, b: any) => b.level - a.level);
+  // };
 
   // 角色选择
-  const onRoleChange = (selectedValues: any) => {
-    // 切换角色时,所属名称要清空重新选择
-    form.setFieldsValue({ parent_id: '' });
-    const sortedData = handleLevel(selectedValues);
-    if (sortedData && sortedData.length > 0) {
-      const maxLevelObject = sortedData[0];
-      const param = {
-        q: 'list',
-        role_id: maxLevelObject.record_id,
-      };
-      queryRoleUser(param).then((res) => {
-        if (res.code === 0) {
-          setSelectList(res?.data || []);
-        }
-      });
-    } else {
-      setSelectList([]);
-    }
-  };
+  // const onRoleChange = (selectedValues: any) => {
+  //   // 切换角色时,所属名称要清空重新选择
+  //   form.setFieldsValue({ parent_id: '' });
+  //   const sortedData = handleLevel(selectedValues);
+  //   if (sortedData && sortedData.length > 0) {
+  //     const maxLevelObject = sortedData[0];
+  //     const param = {
+  //       q: 'list',
+  //       role_id: maxLevelObject.record_id,
+  //     };
+  //     queryRoleUser(param).then((res) => {
+  //       if (res.code === 0) {
+  //         setSelectList(res?.data || []);
+  //       }
+  //     });
+  //   } else {
+  //     setSelectList([]);
+  //   }
+  // };
 
-  const filesProps: UploadProps = {
-    maxCount: 1,
-    action: '/web/v1/files',
-    headers: uploadHeaders,
-    listType: 'picture-card',
-    showUploadList: false,
-    onChange(info) {
-      if (info.file.status === 'uploading') {
-        setLoading(true);
-        return;
-      }
-      if (info.file.status === 'done') {
-        setLoading(false);
-        getBase64(info.file.originFileObj);
-      } else if (info.file.status === 'error') {
-        setLoading(false);
-        message.error('文件上传失败');
-      }
-    },
-  };
+  // const filesProps: UploadProps = {
+  //   maxCount: 1,
+  //   action: '/web/v1/files',
+  //   headers: uploadHeaders,
+  //   listType: 'picture-card',
+  //   showUploadList: false,
+  //   onChange(info) {
+  //     if (info.file.status === 'uploading') {
+  //       setLoading(true);
+  //       return;
+  //     }
+  //     if (info.file.status === 'done') {
+  //       setLoading(false);
+  //       getBase64(info.file.originFileObj);
+  //     } else if (info.file.status === 'error') {
+  //       setLoading(false);
+  //       message.error('文件上传失败');
+  //     }
+  //   },
+  // };
 
   /**
    * 确定
@@ -247,12 +247,12 @@ const Edit: React.FC<userEditPros> = (props) => {
     },
   };
 
-  const uploadButton = (
-    <div>
-      {loading ? <LoadingOutlined /> : <PlusOutlined />}
-      <div className="ant-upload-text">上传</div>
-    </div>
-  );
+  // const uploadButton = (
+  //   <div>
+  //     {loading ? <LoadingOutlined /> : <PlusOutlined />}
+  //     <div className="ant-upload-text">上传</div>
+  //   </div>
+  // );
 
   return (
     <Modal
@@ -327,61 +327,61 @@ const Edit: React.FC<userEditPros> = (props) => {
                   record_id: option.record_id,
                 }))}
                 disabled={isCurrent}
-                onChange={onRoleChange}
+                // onChange={onRoleChange}
               />
             </Form.Item>
           </Col>
-          <Col span={24}>
-            <Form.Item
-              {...formItemLayoutTwo}
-              name="parent_id"
-              label="上级用户"
-              initialValue={detailData?.parent_id || ''}
-            >
-              <Select placeholder="请选择所属名称" disabled={isCurrent}>
-                {selectList && selectList.length
-                  ? selectList.map(
-                      (res: { user_name: string; record_id: string; parent_id: string }) => {
-                        return (
-                          <Select.Option key={res.record_id} value={res.record_id}>
-                            {res?.user_name}
-                          </Select.Option>
-                        );
-                      },
-                    )
-                  : null}
-              </Select>
-            </Form.Item>
-          </Col>
-          <Col span={24}>
-            <Form.Item
-              {...formItemLayoutTwo}
-              name="area"
-              label="所属地区"
-              initialValue={
-                detailData?.province || detailData?.city || detailData?.district
-                  ? [detailData?.province, detailData?.city, detailData?.district]
-                  : []
-              }
-            >
-              <Cascader
-                options={areaList}
-                placeholder="请选择所属地区"
-                fieldNames={{ label: 'name', value: 'name', children: 'children' }}
-              />
-            </Form.Item>
-          </Col>
-          <Col span={12}>
-            <Form.Item {...formItemLayout} name="photo" label="头像" initialValue={[]}>
-              <Upload {...filesProps}>
-                {fileUrl === '' ? (
-                  uploadButton
-                ) : (
-                  <img src={fileUrl} alt="data" style={{ width: '100%' }} />
-                )}
-              </Upload>
-            </Form.Item>
-          </Col>
+          {/*<Col span={24}>*/}
+          {/*  <Form.Item*/}
+          {/*    {...formItemLayoutTwo}*/}
+          {/*    name="parent_id"*/}
+          {/*    label="上级用户"*/}
+          {/*    initialValue={detailData?.parent_id || ''}*/}
+          {/*  >*/}
+          {/*    <Select placeholder="请选择所属名称" disabled={isCurrent}>*/}
+          {/*      {selectList && selectList.length*/}
+          {/*        ? selectList.map(*/}
+          {/*            (res: { user_name: string; record_id: string; parent_id: string }) => {*/}
+          {/*              return (*/}
+          {/*                <Select.Option key={res.record_id} value={res.record_id}>*/}
+          {/*                  {res?.user_name}*/}
+          {/*                </Select.Option>*/}
+          {/*              );*/}
+          {/*            },*/}
+          {/*          )*/}
+          {/*        : null}*/}
+          {/*    </Select>*/}
+          {/*  </Form.Item>*/}
+          {/*</Col>*/}
+          {/*<Col span={24}>*/}
+          {/*  <Form.Item*/}
+          {/*    {...formItemLayoutTwo}*/}
+          {/*    name="area"*/}
+          {/*    label="所属地区"*/}
+          {/*    initialValue={*/}
+          {/*      detailData?.province || detailData?.city || detailData?.district*/}
+          {/*        ? [detailData?.province, detailData?.city, detailData?.district]*/}
+          {/*        : []*/}
+          {/*    }*/}
+          {/*  >*/}
+          {/*    <Cascader*/}
+          {/*      options={areaList}*/}
+          {/*      placeholder="请选择所属地区"*/}
+          {/*      fieldNames={{ label: 'name', value: 'name', children: 'children' }}*/}
+          {/*    />*/}
+          {/*  </Form.Item>*/}
+          {/*</Col>*/}
+          {/*<Col span={12}>*/}
+          {/*  <Form.Item {...formItemLayout} name="photo" label="头像" initialValue={[]}>*/}
+          {/*    <Upload {...filesProps}>*/}
+          {/*      {fileUrl === '' ? (*/}
+          {/*        uploadButton*/}
+          {/*      ) : (*/}
+          {/*        <img src={fileUrl} alt="data" style={{ width: '100%' }} />*/}
+          {/*      )}*/}
+          {/*    </Upload>*/}
+          {/*  </Form.Item>*/}
+          {/*</Col>*/}
         </Row>
       </Form>
     </Modal>

+ 29 - 0
src/services/DeviceFaults.ts

@@ -0,0 +1,29 @@
+import { request } from '@@/plugin-request/request';
+import { stringify } from 'qs';
+
+/**
+ * 查询设备故障列表
+ * @param param
+ */
+export async function queryDeviceFaults(param: object) {
+  return request(`/web/v1/device_faults?${stringify(param)}`);
+}
+
+/**
+ * 查询设备故障详情
+ * @param id
+ */
+export async function queryDeviceFaultsDetail(id: object) {
+  return request(`/web/v1/device_faults/${id}`);
+}
+
+/**
+ * 更新故障信息
+ * @param params
+ */
+export async function updateDeviceFaults(params: any) {
+  return request(`/web/v1/device_faults/${params.record_id}`, {
+    method: 'PUT',
+    data: params,
+  });
+}