• react实现单击或者拖动文件上传


    1.You can drag files to a specific area, to upload. Alternatively, you can also upload by selecting.

    2.We can upload serveral files at once in modern browsers by giving the input the multiple attribute.

    实现效果如下

    点击或者将文件拖动到下图指定区域后,点击upload order 按钮进行文件上传,而download按钮是实现单击后下载模板文档功能的

     UploadRePOS.jsx 

    下面该类中为单击或拖动的组件

    1. import {DownloadOutlined, InboxOutlined, PlusOutlined, UploadOutlined} from '@ant-design/icons';
    2. import {Button, Col, message, Row, Upload,Typography} from 'antd';
    3. import React, {Component} from 'react';
    4. import classes from "../ManualOrder/ManualOrder.module.css";
    5. import {uploadRecord} from "../../api/order";
    6. import Constants from '../../utils/constants';
    7. import PagenHeader from '../../components/PagenHeader'
    8. const { Dragger } = Upload;
    9. export default class UploadRePOS extends Component {
    10. constructor(props) {
    11. super(props)
    12. this.state = {
    13. fileList: [],
    14. uploading: false,
    15. errorMsg: ''
    16. }
    17. }
    18. handleUpload = () => {
    19. const { fileList } = this.state;
    20. this.setState({ uploading: true });
    21. const formData = new FormData()
    22. formData.append('file', fileList[0])
    23. uploadRecord(formData).then(res => {
    24. if (res.code === 4) {
    25. const resultMessage = 'Successfully updated your production record'
    26. const pageResult = { statusCode: 0, message: resultMessage }
    27. this.setState({ uploading: false, errorMsg: ''})
    28. this.props.onPageResultChange(pageResult)
    29. this.props.parsePOData(res.data)
    30. this.props.onUploadSuccessfully(true)
    31. } else {
    32. const resultMessage = `Error submitting the record: ${res.message || res.msg}`
    33. const pageResult = { statusCode: 1, message: resultMessage }
    34. this.props.onPageResultChange(pageResult)
    35. this.props.parsePOData(res.data)
    36. this.props.onUploadSuccessfully(false)
    37. this.setState({ uploading: false, errorMsg:resultMessage,uploadSuccessfully:false});
    38. //this.setState({ uploading: false, errorMsg:res.message || res.msg ,uploadSuccessfully:false});
    39. }
    40. }, err => {
    41. const resultMessage = 'Error submitting the record:' + err + ". Please contact Avery Dennison Software Support Team software.support@ap.averydennison.com"
    42. const pageResult = { statusCode: 1, message: resultMessage }
    43. this.setState({ uploading: false,errorMsg:err,uploadSuccessfully:false , pageResult: pageResult });
    44. })
    45. }
    46. handleDownloadClick = () => {
    47. window.open(`${Constants.API_ROOT_URL}/record/v1.0/downloadRecordForm`)
    48. }
    49. handleRemove = (file) => {
    50. this.setState(state => {
    51. const index = state.fileList.indexOf(file);
    52. const newFileList = state.fileList.slice();
    53. newFileList.splice(index, 1);
    54. return {
    55. fileList: newFileList,
    56. errorMsg:''
    57. }
    58. })
    59. }
    60. handleBeforeUpload = (file) => {
    61. this.setState({ fileList: [file] })
    62. return false
    63. }
    64. render() {
    65. const {
    66. uploading,
    67. fileList,
    68. errorMsg
    69. } = this.state
    70. return (
    71. <div>
    72. <PagenHeader titleClass={classes.sitePageHeader}> Select data filePagenHeader>
    73. <Dragger
    74. name="file"
    75. onRemove={ this.handleRemove }
    76. beforeUpload={ this.handleBeforeUpload }
    77. fileList={ fileList }
    78. className={ classes.item_width }>
    79. <p className="ant-upload-drag-icon">
    80. <InboxOutlined/>
    81. p>
    82. <p className="ant-upload-text">Click or drag file to this area to uploadp>
    83. Dragger>
    84. <PagenHeader titleClass={classes.sitePageHeader}>Order Form SamplePagenHeader>
    85. <Row xs={2} md={4} lg={6}>
    86. <Col className={classes.item}>
    87. <Button icon={<DownloadOutlined/>} onClick={this.handleDownloadClick}
    88. className={classes.item_widths}>DownloadButton>
    89. Col>
    90. <Col >
    91. <Button type="primary"
    92. className={ classes.item_width }
    93. onClick={ this.handleUpload }
    94. icon={ <UploadOutlined /> }
    95. disabled={ fileList.length === 0 }
    96. >
    97. { uploading ? 'Uploading' : 'Upload' }
    98. Button>
    99. Col>
    100. Row>
    101. {(errorMsg !== '') &&
    102. <Row justify='center' className={ classes.error_msg }>
    103. <Col span={ 24 } ><Typography.Text type="danger">Error: {errorMsg}Typography.Text>Col>
    104. Row>
    105. }
    106. div>
    107. )
    108. }
    109. }

    RecordUpload.jsx

    为父组件,在其中引用UploadRePOS.jsx 子组件.

    该类中的handleUpload方法中的uploadRecord为在/api/order.js中设置的组件。用来管理后台跳转路径

    1. import React, { Component } from 'react'
    2. import { Table, Button, Row, Col, Divider, Select } from 'antd'
    3. import PagenHeader from '../../components/PagenHeader'
    4. import UploadPO from './UploadRePOS'
    5. import classes from '../../pages/ManualOrder/ManualOrder.module.css'
    6. import { getLocalStorage } from '../../utils/storage'
    7. import { submitOrder } from '../../api/order'
    8. import PageResult from '../../components/PageResult'
    9. export default class RecordUpload extends Component {
    10. state = {
    11. manualOrder: {
    12. },
    13. poDataList: [],
    14. isBillFormVisible: false,
    15. selectedRowKeys: [],
    16. submiting: false,
    17. submitSuccessfully: false,
    18. uploadSuccessfully: false,
    19. disableSelected: false,
    20. pageResult: {
    21. statusCode: 0,
    22. message: null
    23. },
    24. successMsg: '',
    25. errorMsg: ''
    26. }
    27. parsePOData = (data) => {
    28. const poDataList = [];
    29. data.items.forEach(item => poDataList.push(item));
    30. this.setState({ manualOrder: data, poDataList: poDataList });
    31. };
    32. onPageResultChange = (resultChange)=>{
    33. this.setState({pageResult: resultChange});
    34. }
    35. onUploadSuccessfully = (flag) => {
    36. this.setState({ uploadSuccessfully: flag })
    37. }
    38. handleDirectorCreateOrder = () => {
    39. window.location.href = '/kaloud/order/manualOrder'
    40. }
    41. onSelectChange = (selectedRowKeys, selectedRows) => {
    42. this.setState({selectedRowKeys:selectedRowKeys,selectedRows:selectedRows})
    43. };
    44. handleCloseForm = () => {
    45. this.setState({ isBillFormVisible: false })
    46. }
    47. onBillShipChange = (billShipFormData) => {
    48. this.setState({ billShipInfo: billShipFormData })
    49. }
    50. onUploadPORef = (ref) => {
    51. this.child = ref
    52. };
    53. constructorManualOrder = (manualOrder) => {
    54. let orderData = Object.assign({}, this.state.manualOrder, {
    55. items: this.state.selectedRows
    56. })
    57. const result = orderData;
    58. result.user = manualOrder.user === null ? getLocalStorage('user') : manualOrder.user
    59. this.setState({ manualOrder: result })
    60. return result;
    61. }
    62. goBack = () =>{
    63. this.setState({manualOrder: {},
    64. poDataList: [],
    65. selectedRowKeys: [],
    66. submiting: false,
    67. validateSuccessfully: false,
    68. submitSuccessfully: false,
    69. uploadSuccessfully: false,
    70. disableSelected: false,
    71. pageResult: {
    72. statusCode: 0,
    73. message: null
    74. },
    75. successMsg: '',
    76. errorMsg: ''})
    77. }
    78. incorrectItemsColumns = () =>{
    79. return [
    80. {
    81. title: 'Line#',
    82. dataIndex: 'rowNo',
    83. with:100
    84. }, {
    85. title: 'Serial#',
    86. dataIndex: 'serialNumber',
    87. with:100
    88. }, {
    89. title: 'Production Date',
    90. dataIndex: 'productionDate',
    91. with:50
    92. }, {
    93. title: 'SKU',
    94. dataIndex: 'sku',
    95. with:100
    96. }, {
    97. title: 'COO',
    98. dataIndex: 'coo',
    99. with:100
    100. }, {
    101. title: 'Message',
    102. dataIndex: 'errorMsg',
    103. with:300
    104. },
    105. ]
    106. }
    107. renderColumns = () => {
    108. return [
    109. {
    110. title: 'Message',
    111. dataIndex: 'validateMsg',
    112. render: text => {
    113. if (text === 'Ready' || text === 'Success') {
    114. return <span>{text}span>
    115. } else {
    116. return <span className="ant-typography ant-typography-danger" direction="ltr">{text}span>
    117. }
    118. }
    119. },
    120. {
    121. title: 'Line No',
    122. dataIndex: 'rowNo'
    123. },
    124. {
    125. title: 'Serial Number ',
    126. dataIndex: 'serialNumber'
    127. },
    128. {
    129. title: 'Production Date',
    130. dataIndex: 'productionDate'
    131. },
    132. {
    133. title: 'SKU',
    134. dataIndex: 'sku'
    135. },
    136. {
    137. title: 'COO',
    138. dataIndex: 'coo'
    139. }
    140. ];
    141. }
    142. render() {
    143. //const user = getLocalStorage('user');
    144. const result =new URLSearchParams(this.props.location.search)
    145. const user = result.get('user');
    146. //const { manualOrder, poDataList, billShipInfo, isBillFormVisible, printTypeList ,disableSelected,selectedRowKeys,uploadSuccessfully,showBillButton,submitSuccessfully,submiting, pageResult} = this.state;
    147. const { manualOrder, poDataList,disableSelected,selectedRowKeys,uploadSuccessfully,submitSuccessfully,submiting, pageResult} = this.state;
    148. const rowSelection = {
    149. selectedRowKeys,
    150. onChange: this.onSelectChange,
    151. getCheckboxProps: (record) => ({
    152. disabled: record.validateMsg !== 'Ready' || disableSelected
    153. })
    154. };
    155. return (
    156. <div>
    157. <PagenHeader titleClass={classes.title}> KaloudPagenHeader>
    158. <PagenHeader titleClass={classes.title}> Update production recordsPagenHeader>
    159. {
    160. (uploadSuccessfully === false) &&
    161. <UploadPO parsePOData={this.parsePOData} onPageResultChange={this.onPageResultChange} onUploadPORef={this.onUploadPORef} onUploadSuccessfully={this.onUploadSuccessfully} />
    162. }
    163. {
    164. (manualOrder.valid === false) &&
    165. <div>
    166. <PageResult result={{ statusCode: 1, message: manualOrder.errorMsg }} titleClass={classes.error_msg}>{manualOrder.errorMsg}PageResult>
    167. {
    168. (manualOrder.items.length > 0) &&
    169. <Table dataSource={manualOrder.items} pagination={{defaultCurrent:1,defaultPageSize:20}} columns={this.incorrectItemsColumns()} rowKey={record => record.rowNo}>Table>
    170. }
    171. div>
    172. }
    173. {
    174. (manualOrder.valid === true) &&
    175. <div>
    176. <Divider orientation="left">Divider>
    177. <Table
    178. rowSelection={rowSelection}
    179. pagination={false}
    180. columns={this.renderColumns()}
    181. dataSource={poDataList}
    182. disabled={this.state.submitSuccessfully}
    183. rowKey={record => record.rowNo}
    184. />
    185. {
    186. (manualOrder.valid === true ) &&
    187. <PageResult result={pageResult} titleClass={pageResult.statusCode === 0 ? classes.success_msg : classes.error_msg}>{pageResult.message}PageResult>
    188. }
    189. <Row justify="center" className={classes.submit}>
    190. { <Col span={2} >
    191. <Button onClick={this.goBack} size="large" style={{ display: (submitSuccessfully ? 'none' : 'block') }}>BackButton>
    192. Col>}
    193. Row>
    194. div>
    195. }
    196. div>
    197. )
    198. }
    199. }

    order.js

    1. import request from '../utils/request'
    2. export function uploadManualOrder(data){
    3. return request({
    4. url: `/order/v1.0/uploadManualOrder`,
    5. method: 'post',
    6. data: data,
    7. contentType: 'multipart/form-data'
    8. })
    9. }
    10. export function uploadRecord(data){
    11. return request({
    12. url: `/record/v1.0/uploadRecord`,
    13. method: 'post',
    14. data: data,
    15. contentType: 'multipart/form-data'
    16. })
    17. }
    18. export function submitOrder(data){
    19. return request({
    20. url: `/order/v1.0/submitOrder`,
    21. method: 'post',
    22. data: data,
    23. contentType: 'application/json'
    24. })
    25. }
    26. export function downloadOrderForm(){
    27. return request({
    28. url: `/order/v1.0/downloadOrderForm`,
    29. method: 'get',
    30. contentType: 'multipart/form-data'
    31. })
    32. }
    33. export function downloadRecordForm(){
    34. return request({
    35. url: `/record/v1.0/downloadRecordForm`,
    36. method: 'get',
    37. contentType: 'multipart/form-data'
    38. })
    39. }

    request.js(在order.js中需要引用的)

    1. import React from 'react';
    2. import ReactDOM from 'react-dom';
    3. import { Spin } from 'antd';
    4. import axios from 'axios'
    5. import Constants from './constants'
    6. import { getLocalStorage, setLocalStorage } from './storage'
    7. let isLock = false;
    8. let refreshSubscribers = [];
    9. let requestCount = 0
    10. function showLoading() {
    11. if (requestCount === 0) {
    12. var dom = document.createElement('div')
    13. dom.setAttribute('id', 'loading')
    14. document.body.appendChild(dom)
    15. ReactDOM.render(<Spin tip="Loading..." size="large" />, dom)
    16. }
    17. requestCount++
    18. }
    19. function hideLoading() {
    20. requestCount--
    21. if (requestCount === 0) {
    22. document.body.removeChild(document.getElementById('loading'))
    23. }
    24. }
    25. //push所有请求到数组中
    26. function subscribeTokenRefresh(cb) {
    27. refreshSubscribers.push(cb)
    28. }
    29. //刷新请求(refreshSubscribers数组中的请求得到新的token之后会自执行,用新的token去请求数据)
    30. function onRrefreshed(token) {
    31. refreshSubscribers.map(cb => cb(token))
    32. }
    33. //刷新token
    34. function refreshToken(config, token, resolve, reject) {
    35. axios({
    36. method: "get",
    37. url: `${Constants.API_ROOT_URL}/oauth/v1.0/getUserInfo?token=${token}`,
    38. }).then(response => {
    39. isLock = false;//释放锁
    40. const res = response.data
    41. // if the custom code is not 20000, it is judged as an error.
    42. if (res.code === 401) {
    43. window.location.href = '/kaloud/loginexpired';
    44. return reject(res);
    45. } else if (res.code === 412) {
    46. window.location.href = '/kaloud/userdeactivated';
    47. return reject(res);
    48. } if (res.code !== 4) {
    49. // message.error(`Error: ${res.msg || res.message}`)
    50. return res;
    51. }
    52. setLocalStorage('user', res.data.user)
    53. setLocalStorage('needRefreshToken', false)
    54. config.headers['token'] = token
    55. config.headers['user'] = res.data.user
    56. resolve(config);
    57. //执行数组里的函数,重新发起被挂起的请求
    58. onRrefreshed(res.data.user)
    59. //清空数组中保存的请求
    60. refreshSubscribers = []
    61. }).catch(err => {
    62. return err;
    63. });
    64. }
    65. // create an axios instance
    66. const service = axios.create({
    67. baseURL: Constants.API_ROOT_URL, // url = base url + request url
    68. withCredentials: true, // send cookies when cross-domain requests
    69. timeout: 120000 // request timeout
    70. })
    71. // request interceptor
    72. service.interceptors.request.use(
    73. config => {
    74. if(config.method === 'get'){
    75. config.params = {
    76. _t: Date.now(),
    77. ...config.params,
    78. };
    79. }
    80. // do something before request is sent
    81. if (config.isLoading !== false) {
    82. showLoading()
    83. }
    84. config.headers['retailer'] = Constants.RETAILER
    85. config.headers['Content-Type'] = config.contentType || 'application/json'
    86. const user = getLocalStorage('user')
    87. const token = getLocalStorage('token')
    88. const needRefreshToken = getLocalStorage('needRefreshToken')
    89. if ((!user && token) || needRefreshToken) {
    90. //判断当前是否正在请求刷新token
    91. if (!isLock) {
    92. isLock = true;//isLock设置true,锁住防止死循环。
    93. //使用Promise等待刷新完成返回配置信息
    94. let refresh = new Promise((resolve, reject) => {
    95. refreshToken(config, token, resolve, reject);
    96. })
    97. return refresh
    98. } else {
    99. //判断当前url是否是刷新token的请求地址,如果是直接下一步。
    100. if (config.url.indexOf("/kaloud/loginexpired") === -1 || config.url.indexOf("/kaloud/userdeactivated") === -1) {
    101. //把请求(token)=>{....}都push到一个数组中
    102. let retry = new Promise((resolve, reject) => {
    103. //(token) => {...}这个函数就是回调函数
    104. subscribeTokenRefresh((user) => {
    105. config.headers['token'] = token
    106. config.headers['user'] = user
    107. //将请求挂起
    108. resolve(config)
    109. })
    110. })
    111. return retry
    112. } else {
    113. config.headers['token'] = getLocalStorage('token')
    114. config.headers['user'] = user
    115. return config;
    116. }
    117. }
    118. } else {
    119. config.headers['token'] = token
    120. config.headers['user'] = user
    121. return config
    122. }
    123. },
    124. error => {
    125. // do something with request error
    126. hideLoading()
    127. console.log(error) // for debug
    128. return Promise.reject(error)
    129. }
    130. )
    131. // response interceptor
    132. service.interceptors.response.use(
    133. /**
    134. * If you want to get http information such as headers or status
    135. * Please return response => response
    136. */
    137. /**
    138. * Determine the request status by custom code
    139. * Here is just an example
    140. * You can also judge the status by HTTP Status Code
    141. */
    142. response => {
    143. hideLoading()
    144. const res = response.data
    145. // if the custom code is not 20000, it is judged as an error.
    146. if (res.code === 401) {
    147. window.location.href = '/kaloud/loginexpired';
    148. return Promise.reject(res);
    149. } else if (res.code === 412) {
    150. window.location.href = '/kaloud/userdeactivated';
    151. return Promise.reject(res);
    152. } if (res.code !== 4) {
    153. // message.error(`Error: ${res.msg || res.message}`)
    154. return res;
    155. } else {
    156. return res
    157. }
    158. },
    159. error => {
    160. console.log('err' + error) // for debug
    161. hideLoading()
    162. // Message({
    163. // message: error.message,
    164. // type: 'error',
    165. // duration: 5 * 1000
    166. // })
    167. return Promise.reject(error)
    168. }
    169. )
    170. export default service

    其他为相关辅助功能组件

    PageResult.jsx

    1. import React, { Component } from 'react'
    2. import { Row, Col, Typography } from 'antd'
    3. export default class PageResult extends Component {
    4. render() {
    5. const { children, result, titleClass } = this.props;
    6. return (
    7. <Row className={titleClass} justify='center'>
    8. {
    9. (result.statusCode === 0) &&
    10. <Col span={24}>
    11. <Typography.Text variant="h4" component="h4" type="success">
    12. {children}
    13. Typography.Text>
    14. Col>
    15. }
    16. {
    17. (result.statusCode === 1) &&
    18. <Col span={24}>
    19. <Typography.Text variant="h4" component="h4" type="danger">
    20. {children}
    21. Typography.Text>
    22. Col>
    23. }
    24. Row>
    25. );
    26. }
    27. }

    PagenHeader.jsx

    1. import React, { Component } from 'react'
    2. import { Row, Col, Typography } from 'antd';
    3. export default class PagenHeader extends Component {
    4. render() {
    5. const { children, titleClass } = this.props;
    6. return (
    7. <Row className={ titleClass }>
    8. <Col span={ 24 }>
    9. <Typography variant="h5" component="h2">
    10. { children }
    11. Typography>
    12. Col>
    13. Row>
    14. );
    15. }
    16. }

    storage.js

    1. export const setLocalStorage = (key, value) => {
    2. if (!key) return
    3. let content = value
    4. if (typeof value !== 'string') {
    5. content = JSON.stringify(value)
    6. }
    7. window.localStorage.setItem(key, content)
    8. }
    9. /**
    10. * 获取localStorage
    11. */
    12. export const getLocalStorage = key => {
    13. if (!key) return
    14. return window.localStorage.getItem(key)
    15. }

    constants.js

    1. let apiRootUrl = "/api/kaloud-api"
    2. if(process.env.NODE_ENV === "production") {
    3. apiRootUrl = "/kloud-api"
    4. }
    5. const Constants = {
    6. API_ROOT_URL: apiRootUrl,
    7. RETAILER: "Kloud"
    8. }
    9. export default Constants;

    ManualOrder.module.css

    1. .title {
    2. text-align: center;
    3. }
    4. .content {
    5. text-align: center;
    6. }
    7. .submit {
    8. margin-top: 20px;
    9. }
    10. .error_msg {
    11. margin-top: 20px;
    12. font-size: large;
    13. text-align: center;
    14. }
    15. /* Upload PO */
    16. .item {
    17. text-align: left;
    18. margin-bottom: 15px;
    19. }
    20. .item_width {
    21. width: 150px;
    22. }
    23. .label {
    24. text-align: center;
    25. padding: 5px 0;
    26. }
    27. /* bill ship form */
    28. .bill_ship_form {
    29. margin-left: 50px;
    30. }
    31. .c_form_item {
    32. margin-bottom: 4px;
    33. }
    34. .bill_ship_text {
    35. margin-bottom: 10px;
    36. text-align: center;
    37. font-weight: bold;
    38. }
    39. .table_item_error {
    40. font-style: normal;
    41. }
    42. .table_item_success {
    43. font-style: normal;
    44. }
    45. .message_error{
    46. color: crimson;
    47. }
    48. .success_msg{
    49. margin-top: 20px;
    50. font-size: large;
    51. text-align: center;
    52. }
    53. .black{
    54. background-color: gray;
    55. text-align: center;
    56. text-decoration-color: aliceblue;
    57. }
    58. .sitePageHeader {
    59. text-align: center;
    60. border: 1px solid rgb(235, 237, 240);
    61. background-color: gray;
    62. }
    63. .item_widths {
    64. width: 150px;
    65. margin-left: 600px;
    66. }

  • 相关阅读:
    Facebook投资百亿打造元宇宙,扎克伯格:放长线钓大鱼!
    使用webpack-bundle-analyzer分析uni-app 的微信小程序包大小(HbuilderX运行)
    【已解决】将一个2708行64列的在GPU上的张量z0矩阵保存下来,格式为csv
    scroll-view 实现滑动分类
    【毕业设计】电影评论情感分析 - GRU 深度学习
    C# 从代码入门 Mysql 数据库事务
    python web框架哪家强?Flask、Django、FastAPI对比
    Mathematica清除全局变量以及避免与内置命令冲突
    Android 复杂UI界面分模块解耦的一次实践
    windows不能修改hosts?有这篇文章就够了
  • 原文地址:https://blog.csdn.net/wl_sqfn/article/details/126227409