|
@@ -1,41 +1,130 @@
|
1
|
1
|
import React from 'react';
|
2
|
|
-import { Modal, Form, Input, Select, Button } from 'antd';
|
|
2
|
+import { Upload, Spin, Collapse, Space, Typography, Button } from 'antd';
|
|
3
|
+import { InboxOutlined } from '@ant-design/icons';
|
|
4
|
+import { read, utils } from 'xlsx';
|
|
5
|
+import { addRawDevice } from '@/services/device';
|
3
|
6
|
|
4
|
|
-const formItemLayout = { labelCol: { span: 6 }, wrapperCol: { span: 14 } };
|
5
|
|
-const FormItem = Form.Item;
|
|
7
|
+const { Dragger } = Upload;
|
|
8
|
+const { Panel } = Collapse;
|
|
9
|
+const { Text } = Typography;
|
|
10
|
+const deviceKind = 'feifang';
|
6
|
11
|
|
7
|
|
-export default (props) => {
|
|
12
|
+export default React.forwardRef((props, ref) => {
|
8
|
13
|
const { onCancel, onFinish } = props;
|
9
|
14
|
|
10
|
|
- const [form] = Form.useForm();
|
|
15
|
+ const [loading, setLoading] = React.useState(false);
|
|
16
|
+ const [finished, setFinished] = React.useState(false);
|
|
17
|
+ const [deviceNoList, setDeviceNoList] = React.useState([]);
|
|
18
|
+ const [okList, setOkList] = React.useState([]);
|
|
19
|
+ const [failList, setFailList] = React.useState([]);
|
|
20
|
+
|
|
21
|
+ const okListRef = React.useRef();
|
|
22
|
+ okListRef.current = okList;
|
|
23
|
+ const failListRef = React.useRef();
|
|
24
|
+ failListRef.current = failList;
|
|
25
|
+
|
|
26
|
+ const loadingTip = React.useMemo(() => {
|
|
27
|
+ return `正在处理 ${okList.length + failList.length} / ${deviceNoList.length}`;
|
|
28
|
+ }, [deviceNoList, okList, failList]);
|
|
29
|
+
|
|
30
|
+ const beforeUpload = (file) => {
|
|
31
|
+ const reader = new FileReader();
|
|
32
|
+ reader.onload = (e) => {
|
|
33
|
+ const wb = read(e.target.result);
|
|
34
|
+ // data 格式为 [{ "设备号": "xxx" }], 其中 xxx 为设备号
|
|
35
|
+ const data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]) || [];
|
|
36
|
+ const list = data.map((x) => x['设备号']);
|
|
37
|
+ setDeviceNoList(list || []);
|
|
38
|
+ setOkList([]);
|
|
39
|
+ setFailList([]);
|
|
40
|
+ setFinished(false);
|
|
41
|
+ };
|
|
42
|
+ reader.readAsArrayBuffer(file);
|
|
43
|
+
|
|
44
|
+ // 不上传
|
|
45
|
+ return false;
|
|
46
|
+ };
|
|
47
|
+
|
|
48
|
+ React.useEffect(() => {
|
|
49
|
+ if (!deviceNoList || !deviceNoList.length) return;
|
|
50
|
+
|
|
51
|
+ setLoading(true);
|
|
52
|
+ setOkList([]);
|
|
53
|
+ setFailList([]);
|
|
54
|
+
|
|
55
|
+ let i = 0;
|
|
56
|
+ for (let deviceNo of deviceNoList) {
|
|
57
|
+ addRawDevice({ deviceKind, deviceNo }, { showType: 0 })
|
|
58
|
+ .then(() => {
|
|
59
|
+ i += 1;
|
|
60
|
+ okListRef.current = okListRef.current.concat(deviceNo);
|
|
61
|
+ setOkList(okListRef.current);
|
|
62
|
+ setFinished(i >= deviceNoList.length);
|
|
63
|
+ })
|
|
64
|
+ .catch(() => {
|
|
65
|
+ i += 1;
|
|
66
|
+ failListRef.current = failListRef.current.concat(deviceNo);
|
|
67
|
+ setFailList(failListRef.current);
|
|
68
|
+ setFinished(i >= deviceNoList.length);
|
|
69
|
+ });
|
|
70
|
+ }
|
|
71
|
+ }, [deviceNoList]);
|
|
72
|
+
|
|
73
|
+ React.useImperativeHandle(
|
|
74
|
+ ref,
|
|
75
|
+ () => ({
|
|
76
|
+ refresh: () => {
|
|
77
|
+ setLoading(false);
|
|
78
|
+ setFinished(false);
|
|
79
|
+ setDeviceNoList([]);
|
|
80
|
+ setOkList([]);
|
|
81
|
+ setFailList([]);
|
|
82
|
+ },
|
|
83
|
+ }),
|
|
84
|
+ [],
|
|
85
|
+ );
|
11
|
86
|
|
12
|
87
|
return (
|
13
|
|
- <Form {...formItemLayout} onFinish={onFinish} form={form}>
|
14
|
|
- <FormItem
|
15
|
|
- label="设备大类"
|
16
|
|
- name="deviceKind"
|
17
|
|
- initialValue="feifang"
|
18
|
|
- rules={[{ required: true, message: '请选择设备大类' }]}
|
19
|
|
- >
|
20
|
|
- <Select placeholder="请选择">
|
21
|
|
- <Select.Option value="feifang">飞防</Select.Option>
|
22
|
|
- </Select>
|
23
|
|
- </FormItem>
|
24
|
|
- <FormItem
|
25
|
|
- label="设备编号"
|
26
|
|
- name="deviceNo"
|
27
|
|
- rules={[{ required: true, message: '请输入设备编号' }]}
|
28
|
|
- >
|
29
|
|
- <Input placeholder="请输入" />
|
30
|
|
- </FormItem>
|
31
|
|
- <FormItem label=" " colon={false}>
|
32
|
|
- <Button type="default" onClick={onCancel}>
|
33
|
|
- 取消
|
34
|
|
- </Button>
|
35
|
|
- <Button type="primary" htmlType="Submit" style={{ marginLeft: '2em' }}>
|
36
|
|
- 确认
|
37
|
|
- </Button>
|
38
|
|
- </FormItem>
|
39
|
|
- </Form>
|
|
88
|
+ <div>
|
|
89
|
+ {!finished && (
|
|
90
|
+ <Spin spinning={loading} tip={loadingTip}>
|
|
91
|
+ <Dragger accept=".xls,.xlsx" fileList={[]} beforeUpload={beforeUpload}>
|
|
92
|
+ <p className="ant-upload-drag-icon">
|
|
93
|
+ <InboxOutlined />
|
|
94
|
+ </p>
|
|
95
|
+ <p className="ant-upload-text">点击或拖拽 Excel 文件到此区域</p>
|
|
96
|
+ <p className="ant-upload-hint">
|
|
97
|
+ Excel 要求只有一列, 标题为"设备号"(不带引号), 数据从第二行开始
|
|
98
|
+ </p>
|
|
99
|
+ </Dragger>
|
|
100
|
+ </Spin>
|
|
101
|
+ )}
|
|
102
|
+ {finished && (
|
|
103
|
+ <Space direction="vertical">
|
|
104
|
+ <Collapse collapsible="header" defaultActiveKey={['1']}>
|
|
105
|
+ <Panel header="成功设备" key="1">
|
|
106
|
+ <Typography>
|
|
107
|
+ {okList.map((x) => (
|
|
108
|
+ <Text copyable key={x}>
|
|
109
|
+ {x}
|
|
110
|
+ </Text>
|
|
111
|
+ ))}
|
|
112
|
+ </Typography>
|
|
113
|
+ </Panel>
|
|
114
|
+ </Collapse>
|
|
115
|
+ <Collapse collapsible="header" defaultActiveKey={['1']}>
|
|
116
|
+ <Panel header="失败设备" key="1">
|
|
117
|
+ <Typography>
|
|
118
|
+ {failList.map((x) => (
|
|
119
|
+ <Text copyable key={x}>
|
|
120
|
+ {x}
|
|
121
|
+ </Text>
|
|
122
|
+ ))}
|
|
123
|
+ </Typography>
|
|
124
|
+ </Panel>
|
|
125
|
+ </Collapse>
|
|
126
|
+ </Space>
|
|
127
|
+ )}
|
|
128
|
+ </div>
|
40
|
129
|
);
|
41
|
|
-};
|
|
130
|
+});
|