zoukankan      html  css  js  c++  java
  • 【后台管理系统】—— Ant Design Pro组件使用(一)

    一、搜索Search

        

    • 搜索框
      <Search placeholder="请输入关键字" 
              defaultValue={kw && kw != 'null' ? kw : ''}
              className={styles.search} 
              onChange={() => this.handleKwChange()} 
              onSearch={(e) => this.handleSearch(e)}
      />
    • 引入工具方法:去掉收尾空格

      import {trimStr} from '@/utils/utils';
      
      // utils.js
      export function trimStr(str){
        return str.replace(/(^s*)|(s*$)/g,"");
      }
    • 搜索按钮触发搜索方法,输入内容改变自动搜索

      handleSearch = e => {
          const { dispatch } = this.props;
          const { currentPage } = this.state;
          let kw = trimStr(e);
          this.setState({ keyword : kw });
          dispatch({
            type: 'newMallOrder/fetch',
            payload: {
              currentPage,
              e: {
                keyword: kw
              },
              showCount: 10
            },
          });
        };
      
        handleKwChange = () => {
          const { dispatch } = this.props;
          const { currentPage } = this.state;
          if(event && event.target && event.target.value){
            let value = event.target.value;
            this.handleSearch(value)
          }else{
            dispatch({
              type: 'newMallOrder/fetch',
              payload: {
                currentPage,
                e: {
                  keyword: null
                },
                showCount: 10
              },
            });
          }
        }

    二、选择器Select & TreeSelect

            

    • 表单中嵌入Select选择器
      <FormItem>
           {getFieldDecorator('tempTypeId',{
                initialValue: 0
           })(
            <Select placeholder="请选择" style={{  '100%' }} 
                    onChange={this.handleTempType}>
                <Option value={0}>H5在线编辑</Option>
                <Option value={1}>贺卡</Option>
                <Option value={2}>海报</Option>
                <Option value={3}>壁纸</Option>
                <Option value={4}>全部</Option>
            </Select>
           )}
      </FormItem>

      选择方法:

      handleTempType = value => {
          const { dispatch } = this.props;
          const { keyword } = this.state;
      
          this.setState({
            tempType: tempTypeMap[value]
          })
          dispatch({
            type: 'temp/fetch',
            payload: {
              currentPage: 1,
              e: {
                keyword: keyword,
                subjectClass: tempTypeMap[value]
              },
              showCount: 2
            }
          });
          dispatch({
            type: 'temp/fetchType',
            payload: {
              ofClass: tempTypeMap[value]
            },
            callback: (res) => {
              if(res.code == 200){
                 let typeList = res.data;  // 获取联动选择框的数据
        
                 typeList.forEach((typeItem, index) => {
                    dispatch({
                      type: 'temp/fetchThirdType',
                      payload: typeItem.id,
                      callback: (res) => {
                          if(res.code == 200 && res.data.length){
                             typeList[index].list = res.data;
                          }
                      }
                    })
                 })
                 setTimeout(() => this.setState({ typeList }), 0)
              }
            }
          });
        }
    • 联动选择的第一个选择框的父级数据
      let ParentTypeData = [
          {
            title: 'H5在线编辑',
            value: 0,
            key: 0,
          },
          {
            title: '贺卡',
            value: 1,
            key: 1,
          },
          {
            title: '海报',
            value: 2,
            key: 2,
          },
          {
            title: '壁纸',
            value: 3,
            key: 3,
          },
          {
            title: '全部',
            value: 4,
            key: 4,
          },
        ];
    • 处理获取到的联动选择第二个选择框的数据为TreeSelect需要的数据格式
      let typeData = [];
      const typeTree = (typeList, typeData) => {
            if(typeList.length) {
              for(let i=0; i<typeList.length; i++){
                typeData[i] = {
                  title: typeList[i].kind,
                  value: typeList[i].id,
                  key: typeList[i].id
                }
                //二级分类
                if(typeList[i].list){
                  typeData[i].children = [];
                  typeTree(typeList[i].list, typeData[i].children)
                }
              }
            }
        }
      typeTree(typeList, typeData);
    • 表单中嵌入TreeSelect选择器

       <FormItem label="主题类别" {...formLayout}>
               <TreeSelect
                     defaultValue={tempType == null ? 4 : tempTypeMap.indexOf(tempType)}
                     value={parentTypeId}
                     style={{display: `${editDisable ? 'none' : 'inline-block'}`,  '47%', marginRight: '6%'}}
                     dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
                     treeData={ParentTypeData}
                     placeholder="请选择"
                     onChange={handleParentType}
                 />
                {form.getFieldDecorator('typeIds', {
                     rules: [{ type:"array", required: true, message: '请选择主题类别'}],
                     initialValue: detail.types && detail.types.length
                                  ? detail.types.map((type) => type.id)
                                  : []
                })(
                <TreeSelect
                     multiple   // 多选
                     style={{ `${editDisable ? '100%' : '47%'}`}}
                     dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
                     treeData={typeData}
                     placeholder="请选择"
                     disabled={editDisable}
                     onChange={handleTypeChange}
                />
             )}
      </FormItem>

    三、图片视频音频上传Upload

    • 弹框表单中上传一张图片、一个音频

             

    1. 引入upload.js中封装的handImageUpload文件上传七牛云的方法
      import { handleImageUpload } from '@/utils/upload';
      
      // 预览文件时url前面需要加七牛云服务器前缀
      // eg:  'http://fileserver.liuliu123.cn/'
      import { setFileHost } from '@/utils/utils';

      upload.js

      var qiniu = require('qiniu-js')
      import axios from 'axios';
      import configs from '@/utils/env'
      import { message } from 'antd';
      
      //七牛云上传,input, onchange事件
      export function handleImageUpload(file, type, resName) {
          // console.log(file,'handleImageUpload')
          let suffix = file.type.split('/')[1];
      
          return new Promise(function(resolve, reject){
      
              if(!file) {
                  reject('file is undefined')
              }
      
              function dataURItoBlob(base64Data) {
                  var byteString;
                  if(base64Data.split(',')[0].indexOf('base64') >= 0)
                      byteString = atob(base64Data.split(',')[1]);
                  else
                      byteString = unescape(base64Data.split(',')[1]);
                  var mimeString = base64Data.split(',')[0].split(':')[1].split(';')[0];
                  var ia = new Uint8Array(byteString.length);
                  for(var i = 0; i < byteString.length; i++) {
                      ia[i] = byteString.charCodeAt(i);
                  }
                  return new Blob([ia], {
                      type: mimeString
                  });
              }
      
              function randomString(len) {
                  len = len || 32;
                  var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
                  var maxPos = $chars.length;
                  var pwd = '';
                  for (let i = 0; i < len; i++) {
                      pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
                  }
                  return pwd;
              }
      
              var reader = new FileReader();
              reader.readAsDataURL(file);
              reader.onload = function(e) {
      
                  var fileBlob =  dataURItoBlob(e.target.result);
                  var key;
                  switch(type){
                    case 'audio':
                      key = 'sys/file/music/' + resName + '.' + suffix;
                      break;
                    case 'video':
                      key = 'liveWallPaper/' + resName + '.' + suffix;
                      break;
                    case 'tutorial': //教程文件
                      key = 'sys/tutorial/' + new Date().getTime() + randomString(5) + '.' + suffix;
                      break;
                    case 'tutorialVideo': //针对IOS富文本视频显示问题单独处理教程视频
                      key = 'yihezo/' + new Date().getTime() +randomString(5) + '.' + suffix;
                      break;
                    default:
                      key = 'user/h5/' + new Date().getTime() +randomString(5) + '.' + suffix;
                  }
      
      
                  var putExtra = {
                      fname: file.name,
                      params: {},
                      mimeType: ["image/png", "image/jpeg", "image/jpg", "image/gif", "image/webp", "image/apng", "image/svg",
                                 "audio/mp3", "audio/mp4", "audio/ogg", "audio/mpeg",
                                 "video/mp4", "video/ogg", "video/webm"]
                  };
      
                  var config = {
                      useCdnDomain: true,
                  };
      
                  if(type == 'tutorialVideo' ){  //针对IOS富文本视频显示问题单独处理教程视频
                    axios.post(configs[process.env.API_ENV]['BG_SERVER']+'/file/qiniu/token/video', {
                      key: 'yihezo/' + new Date().getTime() +randomString(5)  //入参:教程视频的key
                    }, {
                      headers: {
                        AuthorizationToken: localStorage.getItem('login_token')
                      }
                    }).then(res =>{
                      let {data} = res;
                      if(data.code == 200) {
                        let token = data.data.token;
                        let observable = qiniu.upload(fileBlob, key, token, putExtra, config)
      
                        let subscription = observable.subscribe({next(res){
                            // console.log(res, 'loading')
                          }, error(res){
                            message.error('上传失败');
                          }, complete(res) {
                            resolve(res.key)
                          }})
                        //subscription.unsubscribe() // 上传取消
      
                      } else {
                        message.error('获取七牛云token失败');
                      }
                    }).catch(error => {
                      console.error(error)
                      reject(error)
                    })
      
                  }else{
                    axios.post(configs[process.env.API_ENV]['BG_SERVER']+'/file/qiniu/token', {}, {
                      headers: {
                        AuthorizationToken: localStorage.getItem('login_token')
                      }
                    }).then(res =>{
                      let {data} = res;
                      if(data.code == 200) {
                        let token = data.data.token;
                        let observable = qiniu.upload(fileBlob, key, token, putExtra, config)
      
                        let subscription = observable.subscribe({next(res){
                            // console.log(res, 'loading')
                          }, error(res){
                            message.error('上传失败');
                          }, complete(res) {
                            resolve(res.key)
                          }})
                        //subscription.unsubscribe() // 上传取消
      
                      } else {
                        message.error('获取七牛云token失败');
                      }
                    }).catch(error => {
                      console.error(error)
                      reject(error)
                    })
                  }
      
              }
          })
      
      }
      View Code
    2. state中定义初始值
      fileThumb: null,      // 存储上传七牛云后返回的图片url
      fileUri: null,        // 存储上传七牛云后返回的文件url
      fileVisible: false,   // 控制预览文件的弹框是否visible  
      previewVisible: false,// 控制预览图片的弹框是否visible
      previewImage: '',     //预览要上传的图片和上传后的图片的url
      previewFile: ''       //预览要上传的图片和上传后的图片的url
    3. 弹框表单中Upload组件

      // 上传按钮
      const ImgUpButton = (
           <div>
                <Icon type="plus" />
                <div className="ant-upload-text">Upload</div>
           </div>
      );
      
      const FileUpButton = (
            <Button>
                <Icon type="upload" /> Upload
            </Button>
       )
      <FormItem label="资源图片" {...this.formLayout}>
           {
                getFieldDecorator('thumb', {
                      rules: [{ required: true, message: '请上传图片' }],
                      initialValue: current.thumb ? [{     // 默认必须是数组
                             uid: '-1',
                             status: 'done',
                             name: current.resName,
                             url: `${setFileHost()+current.thumb}`,
                             thumbUrl: `${setFileHost()+current.thumb}`
                      }] : ""                              // 无值时必须是空串
                })(
                <div>
                      <Upload
                          accept="image/*"       // 限制上传的文件类型
                          action={(file) => handleImageUpload(file, 'image').then(res => {
                              const newFileThumb = [];
                              newFileThumb.push(res);
                              this.setState({
                                fileThumb: newFileThumb,
                              })
                           })}                             // 上传七牛云后存储url
                          listType="picture-card"
                          fileList={imgList}       //  显示的图片数组
                          onRemove={this.handleImgRemove}
                          onPreview={this.handleImgPreview}
                          onChange={this.handleImgChange}
                      >
                            {imgList.length >= 1 ? null : ImgUpButton}
                      </Upload>
                      <Modal visible={previewVisible} footer={null} onCancel={this.handleImgCancel}>
                        <img alt="资源图片" style={{  '100%' }} src={previewImage} />
                      </Modal>
                    </div>
                  )}
                </FormItem>
                <FormItem label="资源文件" extra={resNameError || resName == null ? <span style={{color:'#1890FF'}}>请先输入资源名称</span> : ''} {...this.formLayout}>
                  {getFieldDecorator('uri', {
                    rules: [{ required: true, message: '请上传文件' }],
                    initialValue: current.uri ? [{
                      uid: '-1',
                      status: 'done',
                      name: current.uri,
                      url: `${setFileHost()+current.uri}`
                    }] : ""
                  })(
                    <div>
                      <Upload
                        accept="audio/mp3, audio/mp4, audio/ogg, audio/mpeg"
                        disabled={ resNameError || resName == null ? true : false }
                        action={(file) => handleImageUpload(file, 'audio', resName).then(res => {
                            const newFileUri = [];
                            newFileUri.push(res);
                            this.setState({
                              fileUri: newFileUri
                            })
                          })}
                        fileList={fileList}
                        onRemove={this.handleFileRemove}
                        onPreview={this.handleFilePreview}
                        onChange={this.handleFileChange}
                      >
                          {fileList.length >= 1 ? null : FileUpButton}
                      </Upload>
                      <Modal visible={fileVisible} footer={null} onCancel={this.handleFileCancel} style={{textAlign: 'center'}}>
                        <audio src={previewFile} style={{  '80%' }} controls="controls" autoPlay="autoplay">
                            您的浏览器不支持 audio 标签。
                        </audio>
                      </Modal>
                  </div>
             )}
      </FormItem>
      // 上传图片 使用的方法
      // 删除、预览弹框关闭、预览图片url和预览弹框打开,存储改变的图片url
      handleImgRemove = () => {
          this.setState({
            imgList: [],
            fileThumb: [''],
          })
          return true
        }
      
      handleImgCancel = () => this.setState({ previewVisible: false })
      
      handleImgPreview = (file) => {
          this.setState({
            previewImage: file.url || file.thumbUrl,
            previewVisible: true,
          });
      }
      
      handleImgChange = ({ fileList }) => this.setState({ imgList: fileList })
      
      // 上传文件 使用的方法
      // 删除、预览弹框关闭、预览文件url和预览弹框打开,存储文件的图片url
      handleFileRemove = () => {
          this.setState({
            fileList: [],
            fileUri: [''],
          })
          return true
      }
      
      handleFileCancel = () => this.setState({ fileVisible: false })
      
      handleFilePreview = (file) => {
          file.url ?
          this.setState({
            previewFile: file.url,
            fileVisible: true,
          }) :
          message.error('请先保存');
      }
      
      handleFileChange = ({ fileList }) => this.setState({ fileList })
    • 弹框表单中上传多张图片

            

    1. 引入upload.js中封装的handImageUpload文件上传七牛云的方法

      import { handleImageUpload } from '@/utils/upload';
      import {setFileHost} from '@/utils/utils';
    2. state中定义初始数据
      // 上传多张轮播图(可上传视频)
      imgList: [],
      fileThumbs: [],
      previewVisible: false,
      previewImage: '',
          
      //  上传一张图片
      introImgList: [],
      introFileThumb: '',
      introPreviewVisible: false,
      introPreviewImage: '',
    3. showModal显示弹框的方法中: 处理获得的图片数组存入state

      showEditModal = item => {
          const { dispatch } = this.props;
      
          dispatch({
            type: 'project/fetchDetail',
            payload: {
                goodsId: item.id
            },
            callback: (res) => {
              if(res){
                this.setState({
                  detail: res.data,
                  imgList: res.data.rotationChart && res.data.rotationChart.length
                            ? this.initImgList(res.data) : "",    // Upload显示图片本地存储的图片url数组
                  fileThumbs: res.data.rotationChart && res.data.rotationChart.length                            
                            ? this.initFileThumbs(res.data) : "", // 上传七牛云后存储的用于传给后端的图片url数组
                  introImgList: res.data.introPic
                            ? [{
                              uid: '-1',
                              status: 'done',
                              name: res.data.introPic,
                              url: `${setFileHost()+res.data.introPic}`,
                              thumbUrl: `${setFileHost()+res.data.introPic}`
                            }] : '',
                  introFileThumb: res.data.introPic ? res.data.introPic : '',
                  current: item,
                  addSubmit: false
                }, () => {
                  this.setState({
                    visible: true
                  })
                });
              }
            }
          })
      };
    4. 弹框表单中嵌入Upload组件

       const ImgUpButton = (       //  上传图片的按钮
          <div> 
            <Icon type="plus" />
            <div className="ant-upload-text">Upload</div>
          </div>
        );
      <FormItem label="产品图片" {...formLayout}>
          { getFieldDecorator('rotationChart', {
               rules: [{ required: true, message: '请上传1-7张图片'}],
               //  默认显示是图片数组,无值也是空数组
               initialValue: current && detail && detail.rotationChart && detail.rotationChart.length
                             ? initImgList(detail) : []    
          })(
               <div>
                   <Upload
                       accept="image/*"
                       // action={(file) => handleImageUpload(file, 'image').then(res => {
                       //    handleFileThumb(res, file, imgList)
                       //  })}
                       listType="picture-card"
                       fileList={imgList}
                       onPreview={handleImgPreview}
                       onRemove={handleImgRemove}
                       // beforeUpload上传前的处理函数: 嵌套handleImageUpload方法  (上传一张图片或一个文件时,如果需要上传前判断文件类型、文件大小也是这么做)
                       // 1.包含handleFileThumb方法,代替action实现上传七牛云服务器后存储state;2.同时将新的图片数组imgArray存入本地imgList改变Upload组件显示的图片
                       beforeUpload={beforeUpload}  
                       // onChange={handleImgChange}
                   >
                       {imgList.length >= 7 ? null : ImgUpButton}   
                   </Upload>
                   <Modal visible={previewVisible} footer={null} onCancel={handleImgCancel} style={{textAlign: 'center'}}>
                       { previewType == 'liveWallPaper' ?
                         <video src={previewImage} style={{  '50%' }} controls="controls" autoPlay="autoplay">
                             您的浏览器不支持 video 标签。
                         </video>
                         : <img alt="产品图片" style={{  '100%' }} src={previewImage} />}
                    </Modal>
              </div>
          )}
      </FormItem>
    5. 使用到的方法

      initImgList = (item) => {   // 处理Upload默认显示的数据
          let defaultImgList = [];
          item.rotationChart.forEach((imgListItem, index) => {
              defaultImgList.push ({
                  uid: `${-1-index}`,
                  status: 'done',
                  name: item.name,
                  url: imgListItem.img ? `${setFileHost()+imgListItem.img}` : '',
                  thumbUrl: imgListItem.thumb ? `${setFileHost()+imgListItem.thumb}` : ''
              })
          })
          return defaultImgList
      }
      initFileThumbs = (item) => {  // 不更改不上传新的图片时默认向后端传的图片url数组
          let defaultFileThumbs = [];
          item.rotationChart.forEach((fileThumb, index) => {
            defaultFileThumbs[index] = fileThumb;
          })
          return defaultFileThumbs
      }
      handleFileThumb = (res, file, imgList) => {  // 更改fileThumbs数组
          let  { fileThumbs } = this.state;
          fileThumbs[imgList.length-1] = {
            img: res,
            index: imgList.length-1,
            type: file.type.split('/')[0],
            thumb: res
          };
          this.setState({
            fileThumbs
          })
      }
      // 关闭预览弹框
      handleImgCancel = () => this.setState({ previewVisible: false })
      
      // 显示预览弹框
      handleImgPreview = (file) => {
          this.setState({
            previewImage: file.url || file.thumbUrl,
            previewVisible: true,
          });
      }
      
      // 删除预览弹框
      handleImgRemove = (file)  => {
          const { fileThumbs, imgList } = this.state;
          let newList = [...imgList];
          let newFileThumbs = [...fileThumbs];
          newList.forEach((imgItem, index) => {
            if(imgItem.uid == file.uid){
              newList.splice(index, 1)
              newFileThumbs.splice(index, 1)
            }
          })
          this.setState({
            imgList: newList,
            fileThumbs: newFileThumbs
          }, () => {
            return true
          })
      }
      beforeUpload = (file) => {
            let type = file.type.split('/')[0];
            let name = file.name.split('.')[0];
            
            // 判断文件类型 -- 如果是视频url直接存入imgList,存入fileThumb
            if(type == 'video') {
              let imgArray = [...this.state.imgList];
              imgArray.push(file);
      
              handleImageUpload(file, 'video', name).then(res => {
                this.setState({
                  imgList: imgArray
                })
                this.handleFileThumb(res, file, imgArray)
              })
            }else{
              // 如果是图片,使用react-cropper插件相关设置进行裁剪处理
              // 当打开同一张图片的时候清除上一次的缓存
              if (this.refs.cropper) {
                this.refs.cropper.reset();
              }
      
              var reader = new FileReader();
              const image = new Image();
              //因为读取文件需要时间,所以要在回调函数中使用读取的结果
              reader.readAsDataURL(file); //开始读取文件
      
              reader.onload = (e) => {
                image.src = reader.result;
                image.onload = () => {
                this.setState({
                    srcCropper: e.target.result, //cropper的图片路径
                    selectImgName: file.name, //文件名称
                    selectImgSize: (file.size / 1024 / 1024), //文件大小
                    selectImgSuffix: file.type.split("/")[1], //文件类型
                    editImageModalVisible: true, //打开控制裁剪弹窗的变量,为true即弹窗
               })
                if (this.refs.cropper) {
                    this.refs.cropper.replace(e.target.result);
                }
                }
              }
              return false;
            }
      }
    • 不需要裁剪的使用beforeUpload判断文件大小的上传一张图片

      <FormItem label="人物介绍图片" {...formLayout}>
                {getFieldDecorator('introPic', {
                   initialValue: current && detail && detail.introPic
                     ? [{
                       uid: '-1',
                       status: 'done',
                       name: detail.introPic,
                       url: `${setFileHost()+detail.introPic}`,
                       thumbUrl: `${setFileHost()+detail.introPic}`
                     }] : ''
                 })(
                   <div>
                     <Upload
                       accept="image/*"
                       // action={(file) => handleImageUpload(file, 'image').then(res => {
                       //    handleIntroFileThumb(res)
                       //  })}
                       listType="picture-card"
                       fileList={introImgList}
                       onPreview={handleIntroImgPreview}
                       onRemove={handleIntroImgRemove}
                       beforeUpload={beforeIntroUpload}
                       // onChange={handleIntroImgChange}
                     >
                       {introImgList.length >= 1 ? null : ImgUpButton}
                     </Upload>
                     <Modal visible={introPreviewVisible} footer={null} onCancel={handleIntroImgCancel} style={{textAlign: 'center'}}>
                       <img alt="人物介绍图片" style={{  '100%' }} src={introPreviewImage} />
                     </Modal>
                   </div>
                 )}
      </FormItem>
      beforeIntroUpload = (file) => {
          const isLt3M = file.size / 1024 / 1024 < 3;
          if (!isLt3M) { //添加文件限制
            message.error('文件大小不能超过3M');
            return false;
          }
          // console.log('file', file)
      
          handleImageUpload(file, 'image').then(res => {
            this.setState({              // 存入introImgList
              introImgList: [{
                uid: file.uid,
                status: 'done',
                name: file.name,
                url: `${setFileHost()+res}`,
                thumbUrl: `${setFileHost()+res}`
              }]
            })
            this.handleIntroFileThumb(res)   // 存入introFileThumbs
          })
      
          return true
        }

    转载请注明出处

  • 相关阅读:
    pygame各个模块概述
    安装pygame
    pygame系列
    把字符串转换成整数
    不用加减乘除做加法
    求1+2+3+...+n
    孩子们的游戏(圆圈中最后剩下的数)
    翻转单词顺序列
    左旋转字符串
    和为s的两个数字
  • 原文地址:https://www.cnblogs.com/ljq66/p/11904760.html
Copyright © 2011-2022 走看看