1 | import React, { useReducer } from "react";
|
2 | import styled from "styled-components";
|
3 | import axios from "axios";
|
4 |
|
5 | const initState = {
|
6 | percent: 0,
|
7 | };
|
8 | const reducer = (state, action) => {
|
9 | return { ...state, ...action };
|
10 | };
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 | export default function UploadInput({
|
24 | url = "",
|
25 | value = "",
|
26 | accept = "",
|
27 | onChange,
|
28 | title = "选择文件",
|
29 | headers,
|
30 | }) {
|
31 | const [state, dispatch] = useReducer(reducer, initState);
|
32 | const loading = state.percent > 0 && state.percent <= 100;
|
33 |
|
34 | const matchFileName = value.match(/[^\/]+$/);
|
35 | const fileName = matchFileName ? matchFileName[0] : "";
|
36 |
|
37 | const _onChange = async e => {
|
38 | const file = e.target.files[0];
|
39 | const form = new FormData();
|
40 | form.append("file", file);
|
41 | const res = await axios.post(url, form, {
|
42 | headers: {
|
43 | "Content-Type": "multipart/form-data;charset=UTF-8",
|
44 | ...headers,
|
45 | },
|
46 | onUploadProgress: e => {
|
47 | const percent = ((e.loaded / e.total) * 100) | 0;
|
48 | dispatch({ percent });
|
49 | },
|
50 | });
|
51 | const filePath = res.data.data;
|
52 | setTimeout(() => {
|
53 | dispatch({ percent: 0 });
|
54 | onChange(filePath);
|
55 | }, 300);
|
56 | };
|
57 |
|
58 | return (
|
59 | <>
|
60 | <SBox>
|
61 | {loading ? (
|
62 | <span style={{ color: "#ff0000" }}>
|
63 | 正在上传({state.percent}%)...
|
64 | </span>
|
65 | ) : (
|
66 | <SLabel>
|
67 | <div style={{ height: "100%" }}>
|
68 | {title}
|
69 | <span style={{ color: "gray", fontSize: "12px" }}>
|
70 | (限制30M以内)
|
71 | </span>
|
72 | </div>
|
73 | <input
|
74 | accept={accept}
|
75 | type="file"
|
76 | onChange={_onChange}
|
77 | style={{ width: "1px", display: "none" }}
|
78 | />
|
79 | </SLabel>
|
80 | )}
|
81 | </SBox>
|
82 | <SFiles>{fileName}</SFiles>
|
83 | </>
|
84 | );
|
85 | }
|
86 |
|
87 | const SBox = styled.div`
|
88 | display: flex;
|
89 | align-items: center;
|
90 | justify-content: center;
|
91 | border: 1px dashed #d4d4d4;
|
92 | background-color: #f3f3f3;
|
93 | height: 50px;
|
94 | line-height: 50px;
|
95 | `;
|
96 |
|
97 | const SLabel = styled.label`
|
98 | width: 100%;
|
99 | height: 50px;
|
100 | line-height: 50px;
|
101 | color: #2a2aa0;
|
102 | display: flex;
|
103 | flex-direction: column;
|
104 | align-items: center;
|
105 | justify-content: center;
|
106 | `;
|
107 | const SFiles = styled.div`
|
108 | margin-top: 3px;
|
109 | color: #0e41ad;
|
110 | `;
|