一、搜索Search

    【后台管理系统】—— Ant Design Pro组件使用(一)-LMLPHP

  • 搜索框

    <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

        【后台管理系统】—— Ant Design Pro组件使用(一)-LMLPHP

  • 表单中嵌入Select选择器

    <FormItem>
    {getFieldDecorator('tempTypeId',{
    initialValue: 0
    })(
    <Select placeholder="请选择" style={{ width: '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'}`, width: '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={{width: `${editDisable ? '100%' : '47%'}`}}
    dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
    treeData={typeData}
    placeholder="请选择"
    disabled={editDisable}
    onChange={handleTypeChange}
    />
    )}
    </FormItem>

三、图片视频音频上传Upload

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

【后台管理系统】—— Ant Design Pro组件使用(一)-LMLPHP

  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)
    })
    } }
    }) }
  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={{ width: '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={{ width: '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 })
  • 弹框表单中上传多张图片

【后台管理系统】—— Ant Design Pro组件使用(一)-LMLPHP

  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={{ width: '50%' }} controls="controls" autoPlay="autoplay">
    您的浏览器不支持 video 标签。
    </video>
    : <img alt="产品图片" style={{ width: '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={{ width: '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
    }

转载请注明出处

05-15 21:07