天天看点

react中使用富文本编辑器wangeditor

在开发react开发过程中在做一些表单内容提交修改过程中:用到了上传和下载附件;富文本编辑等,话不多说上代码:

index.js文件是一个list表格:

/*
 * 项目需求列表
 */
import React, { Component } from "react";
import Storage from "store2";
// import History from "@utils/history";
import { Modal, Button, Row, Col, Table, Notification } from "antd";
import Request from "@utils/request";
import { areaName, bankName } from "@utils/codeToName";
import Form from "./form.js";
let version = Storage.get("version");
const columns = _this => [
  {
    title: "id",
    dataIndex: "id",
  },
  {
    title: "需求名称",
    dataIndex: "demandName",
  },
  {
    title: "需求编码",
    dataIndex: "demandCode",
  },
  {
    title: "需求描述",
    dataIndex: "note",
    width: 200,
    render: text => {
      const re = new RegExp("<[^<>]+>", "g");
      const text1 = text.replace(re, "");
      return <textarea defaultValue={text1}></textarea>;
    }
  },
  {
    title: "地区",
    dataIndex: "areaCode",
    align: "center",
    render: (text) => areaName(text)
  },
  {
    title: "银行",
    dataIndex: "bankCode",
    align: "center",
    render: (text) => bankName(text)
  },
  {
    title: "创建时间",
    dataIndex: "createTime",
    width: 200,
  },
  {
    title: "操作",
    dataIndex: "操作",
    fixed: "right",
    align: "center",
    width: 240,
    render: (text, record) => (
      <div style={{ textAlign: "right" }}>
        <Button
          type="link"
          onClick={() => {
            Modal.confirm({
              title: "确定删除此项目吗?",
              content: (
                <div>
                  <p>项目名称:{record.demandName}</p>
                </div>
              ),
              okText: "确认",
              cancelText: "取消",
              onOk() {
                Request.POST(`/api/demand/delete/${record.id}`, {
                  params: {
                    loginKey: Storage.get("Authorization"),
                  }
                }).then((res) => {
                  if (res.success) {
                    Notification.success({
                      message: res.msg || "删除成功"
                    });
                    _this.loadData();
                  } else {
                    Notification.error({
                      message: res.msg || "删除失败"
                    });
                  }
                });
              }
            });
          }}
        >
          删除
        </Button>
        {
          record.loginname !== "admin"
          &&
          <Button
            type="link"
            onClick={() => {
              _this.setState({
                taskModal: true,
                taskModalType: "edit",
                demandInfo: record.id
              })
            }}
          >
            修改
          </Button>
        }
        <Button
          type="link"
          onClick={() => {
            // 获取任详情
            Request.GET(`/api/demand/get/${record.id}`, {
              params: {
                loginKey: Storage.get("Authorization"),
              }
            }).then((res) => {
              if (res.success) {
                _this.setState({
                  downloadtaskModal: true,
                  downloadDemandInfo: res.data.attachmentList
                });
              } else {
                Notification.warning({
                  message: res.msg || "获取任详情失败",
                });
              }
            });
          }}
        >
          下载附件
        </Button>
      </div>
    )
  }
];
class View extends Component {
  constructor(props) {
    super(props);
    this.state = {
      tableSource: [],
      taskModal: false,
      downloadtaskModal: false,
      taskModalType: "add", //创建:add   修改:edit
      demandInfo: "",
      downloadDemandInfo: []  //附件信息
    };
  }
  componentDidMount() {
    this.loadData(); // 获取数据
  }
  // 渲染页面数据
  loadData = async () => {
    // 获取任务列表
    Request.GET("/api/demand/list", {
      params: {
        loginKey: Storage.get("Authorization"),
      }
    }).then((res) => {
      if (res.success) {
        this.setState({
          tableSource: res.data
        });
      } else {
        Notification.warning({
          message: res.msg || "获取户失败",
        });
      }
    });
  };
  CancelTaskModal = () => {
    this.setState({
      taskModal: false
    })
  }
  CanceldownloadtaskModal = () => {
    this.setState({
      downloadtaskModal: false
    })
  }
  render() {
    const {
      tableSource,
      taskModalType,
      demandInfo,
      downloadtaskModal,
      downloadDemandInfo
    } = this.state;
    console.log(downloadDemandInfo)
    return (
      <div>
        <Row>
          <Col>
            <Button type="primary"
              size="large"
              onClick={() => {
                this.setState({
                  taskModal: true,
                  taskModalType: "add"
                })
              }}
            >新增需求</Button>
          </Col>
        </Row>
        <Table
          style={{
            marginTop: "20px"
          }}
          scroll={{ x: 1200 }}
          dataSource={tableSource}
          columns={columns(this)}
          rowKey="id"
        />
        <Modal
          title={taskModalType === "edit" ? "修改需求" : "新增需求"}
          footer={null}
          width={900}
          destroyOnClose
          visible={this.state.taskModal}
          onCancel={() => { this.CancelTaskModal() }}
        >
          <Form parentThis={this}
            taskModalType={taskModalType}
            demandInfo={demandInfo}
          />
        </Modal>
        <Modal
          title="下载附件"
          footer={null}
          width={900}
          destroyOnClose
          visible={downloadtaskModal}
          onCancel={() => { this.CanceldownloadtaskModal() }}
        >
          {
            (downloadDemandInfo && downloadDemandInfo.length > 0)
              ?
              downloadDemandInfo.map(item => {
                return <Button
                  type="link"
                  key={item.id}
                  onClick={() => {
                    // 下载附件
                    window.location.href = `${version}/attachment/download/${item.uuid}?loginKey=${Storage.get("Authorization")}`;
                  }}>
                  {item.fileName}
                </Button>
              })
              :
              "无附件"
          }

        </Modal>
      </div>
    );
  }
}

export default View;
           

form.js表单新增,修改

/*
 * 创建修改需求
 */
import React from "react";
import { Form, Notification, Button, Input, Row, Col, Select, Radio, message, Upload, Icon } from "antd";
import Request from "@utils/request";
import Storage from "store2";
import Edit from "./edit"

const FormItem = Form.Item;
class ViewForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      demandInfo: {},
      areaArr: [],
      bankArr: [],
      editorContent: "",
      fileList: [],//要上传的附件list
      zzfileList: [], //回显的附件list
    };
  }
  componentDidMount() {
    this.areaData();
    this.bankData();
    const { taskModalType } = this.props;
    if (taskModalType === "edit") {
      this.loadData(); // 获取数据
    }

  }
  // 获取地区
  areaData = () => {
    Request.GET("/api/area/list", {
      params: {
        loginKey: Storage.get("Authorization"),
      }
    }).then(res => {
      if (res.success) {
        this.setState({
          areaArr: res.data
        });
      }
    })
  };
  // 获取银行
  bankData = () => {
    Request.GET("/api/bank/list", {
      params: {
        loginKey: Storage.get("Authorization"),
      }
    }).then(res => {
      if (res.success) {
        this.setState({
          bankArr: res.data
        });
      }
    })
  };
  // 根据地区换银行
  changeArea = (value) => {
    let areaCode = value;
    Request.GET(`/api/area/getByAreaCode/${areaCode}`, {
      params: {
        loginKey: Storage.get("Authorization"),
      }
    }).then(res => {
      if (res.success) {
        this.setState({
          bankArr: res.data.bankList
        });
      } else {
        this.setState({
          bankArr: []
        });
      }
    })
  };
  // 编辑器内容
  saveEditor = (text) => {
    const { form: { setFieldsValue } } = this.props;
    this.setState({
      editorContent: text
    });
    setFieldsValue({
      "note": text
    });
  };
  // 获取项目信息
  loadData = async () => {
    Request.GET(`/api/demand/get/${this.props.demandInfo}`, {
      params: {
        loginKey: Storage.get("Authorization"),
      }
    }).then((res) => {
      if (res.success) {
        this.setState({
          demandInfo: res.data,
          editorContent: res.data.note,
          zzfileList: res.data.attachmentList, // 原始数据
          fileList: (this.props.taskModalType === "edit" && res.data.attachmentList && res.data.attachmentList.length > 0)
            ?
            res.data.attachmentList.map(f => {
              const temp = {
                // 为了提供给上传组件回显
                id: f.id,
                uid: f.uuid,  // 这是上传组件规定的文件唯一标识,内部会提供给Form以便正常渲染回显列表
                name: f.fileName,
                status: "done",
                url: "",
                fileExt: f.fileExt,
                filePath: f.filePath,
                fileSize: f.fileSize,
              }
              return temp;
            })
            :
            []
        });
      } else {
        Notification.warning({
          message: res.msg || "获取项目信息失败",
        });
      }
    });
  };
  handleSubmit = () => {
    const { form: { validateFields }, taskModalType } = this.props;
    const { demandInfo, zzfileList, editorContent } = this.state;
    validateFields((err, values) => {
      if (!err) {
        if (taskModalType === "edit") {
          Request.POST("/api/demand/update", {
            params: {
              loginKey: Storage.get("Authorization"),
            },
            body: {
              demandName: values.demandName,
              demandCode: values.demandCode,
              id: demandInfo.id,
              areaCode: values.areaCode,
              bankCode: values.bankCode,
              demandGeneral: values.demandGeneral,
              attachmentList: zzfileList,
              note: editorContent,
            }
          }).then((res) => {
            if (res.success) {
              Notification.success({
                message: res.msg || "修改成功",
              });
              this.props.parentThis.CancelTaskModal();
              this.props.parentThis.loadData();
            } else {
              Notification.warning({
                message: res.msg || "修改失败",
              });
            }
          });
        } else {
          Request.POST("/api/demand/add", {
            params: {
              loginKey: Storage.get("Authorization"),
            },
            body: {
              demandName: values.demandName,
              areaCode: values.areaCode,
              demandCode: values.demandCode,
              bankCode: values.bankCode,
              demandGeneral: values.demandGeneral,
              attachmentList: zzfileList,
              note: editorContent,
            }
          }).then((res) => {
            if (res.success) {
              Notification.success({
                message: res.msg || "新增需求成功",
              });
              this.props.parentThis.CancelTaskModal();
              this.props.parentThis.loadData();
            } else {
              Notification.warning({
                message: res.msg || "新增需求失败",
              });
            }
          });
        }
      }
    });
  };
  render() {
    const { demandInfo, fileList, zzfileList, editorContent, areaArr, bankArr } = this.state;
    const { taskModalType } = this.props;
    if (taskModalType === "edit" && Object.keys(demandInfo).length === 0) return <div></div>;
    const { getFieldDecorator } = this.props.form;
    const formItemLayout = {
      labelCol: { span: 4 },
      wrapperCol: { span: 12 },
    };
    const formItemLayoutNote = {
      labelCol: { span: 4 },
      wrapperCol: { span: 20 },
    }
    let _this = this;
    const props = {
      accept: ".rar,.zip,.doc,.docx,.xlsx,.xls,.pdf,.jpg,.png",
      name: "file",
      action: `${Storage.get("version")}/attachment/upload?loginKey=${Storage.get("Authorization")}`,
      defaultFileList: fileList,
      beforeUpload(file) {
        const isLt10M = file.size / 1024 / 1024 <= 100;
        if (!isLt10M) {
          message.error("文件大小限制在100M以下!");
          this.onRemove(file);
          return false;
        }
      },
      onRemove(file) {
        Request.GET(`/api/attachment/del/${file.uid}`, {
          params: {
            loginKey: Storage.get("Authorization"),
          }
        }).then((res) => {
          if (res.success) {
            Notification.success({
              message: res.msg || "删除附件成功",
            });
          } else {
            Notification.warning({
              message: res.msg || "删除附件失败",
            });
          }
        });
        _this.setState({
          fileList: fileList.filter(item => item.name !== file.name),
          zzfileList: zzfileList.filter(item => item.fileName !== file.name),
        }, () => {
          _this.props.form.setFieldsValue({ fileList: fileList });
        });

      },
      onChange(info) { // 上传中、完成、失败都会调用这个函数
        let curFileList = [...info.fileList];
        curFileList = curFileList.map((file) => {
          if (file.response) {
            console.log(file.response);
            // 这里上传组件回调的数据,有些是提供给上传组件自身使用的,所以不能不要
            // 而需要向后端提交的数据这里提前封装起来,以方便最终的提交
            // let saveParams = {};
            file["fileName"] = file.response.data.fileName;
            file["filePath"] = file.response.data.filePath;
            file["fileSize"] = file.response.data.fileSize;
            file["fileExt"] = file.response.data.fileExt;
            file["uuid"] = file.response.data.uuid;
            file["id"] = file.response.data.id;
          }
          return file;
        });
        curFileList = curFileList.filter(file => {
          if (file.size / 1024 / 1024 <= 100) {
            if (file.response) {
              return file.response.code === 0;
            }
            return true;
          } else {
            return false;
          }
        });
        _this.setState({
          zzfileList: [
            ..._this.state.zzfileList,
            ...curFileList
          ]
        });
      },
      // fileList: fileList, // 上传组件已使用Form进行代理,所以不要再直接设置
    };
    return (
      <Row>
        <Col>
          <Form>
            <FormItem label="需求名称"
              {...formItemLayout}
            >
              {getFieldDecorator("demandName", {
                initialValue: taskModalType === "edit" ? demandInfo.demandName : "",
                rules: [{ required: true, message: "请填写需求名称!" }],
              })(
                <Input placeholder="请填写需求名称" />
              )}
            </FormItem>
            <FormItem label="需求编号"
              {...formItemLayout}
            >
              {getFieldDecorator("demandCode", {
                initialValue: taskModalType === "edit" ? demandInfo.demandCode : "",
                rules: [{ required: true, message: "请填写需求编号!" }],
              })(
                <Input placeholder="请填写需求编号" />
              )}
            </FormItem>
            <FormItem label="地区"
              {...formItemLayout}
            >
              {getFieldDecorator("areaCode", {
                initialValue: taskModalType === "edit" ? demandInfo.areaCode : "",
                rules: [{ required: true, message: "请输入实施地区!" }],
              })(
                <Select
                  showSearch
                  placeholder="请选择实施的地区"
                  optionFilterProp="children"
                  onChange={(e) => this.changeArea(e)}
                  filterOption={(input, option) =>
                    option.props.children.indexOf(input) >= 0
                  }
                >
                  {
                    areaArr.map((item, index) => {
                      return <Select.Option
                        value={item.areaCode}
                        key={index}
                      >
                        {item.areaName}
                      </Select.Option>
                    })
                  }
                </Select>
              )}
            </FormItem>
            <FormItem label="银行"
              {...formItemLayout}
            >
              {getFieldDecorator("bankCode", {
                initialValue: taskModalType === "edit" ? demandInfo.bankCode : "",
                rules: [{ required: true, message: "请输入实施银行!" }],
              })(
                <Select
                  showSearch
                  placeholder="请选择实施的银行"
                  optionFilterProp="children"
                  filterOption={(input, option) =>
                    option.props.children.indexOf(input) >= 0
                  }
                >
                  {
                    bankArr.map((item, index) => {
                      return <Select.Option
                        value={item.bankCode}
                        key={index}
                      >
                        {item.bankName}
                      </Select.Option>
                    })
                  }
                </Select>
              )}
            </FormItem>
            <FormItem label="是否通用"
              {...formItemLayout}
            >
              {getFieldDecorator("demandGeneral", {
                initialValue: taskModalType === "edit" ? demandInfo.demandGeneral : 1,
                rules: [{ required: true, message: "请选择是否通用!" }],
              })(
                <Radio.Group >
                  <Radio value={1}>通用版本</Radio>
                  <Radio value={2}>非通用版本</Radio>
                </Radio.Group>
              )}
            </FormItem>
            <FormItem {...formItemLayout}
              label="上传附件">
              {getFieldDecorator("attachmentList", {
                rules: [{
                  required: false, message: "请上传证明材料"
                }],
                valuePropName: "attachmentList",
                getValueFromEvent: (e) => {
                  if (Array.isArray(e)) {
                    return e;
                  }
                  return e && e.fileList;
                }
              })(
                <Upload {...props}>
                  <Button>
                    <Icon type="upload" /> 上传文件
                  </Button>
                  <span className="upload-desc">支持附件:.rar .zip .xlsx .xls .doc .pdf .jpg .png</span>
                </Upload>
              )}
            </FormItem>
            <FormItem label="需求描述"
              {...formItemLayoutNote}
            >
              {getFieldDecorator("note", {
                initialValue: taskModalType === "edit" ? editorContent : "",
              })(
                <Edit
                  parentThis={this}
                  getFieldDecorator={getFieldDecorator}
                  editWord={editorContent}
                />
              )}
            </FormItem>
          </Form>
        </Col>
        <Col style={{ "textAlign": "right", marginTop: "10px" }}>
          <Button type="primary"
            htmlType="submit"
            onClick={() => {
              this.handleSubmit()
            }}
          >确定</Button>
          <Button style={{ "marginLeft": 8 }}
            onClick={() => {
              this.props.parentThis.CancelTaskModal();
            }}
          >取消</Button>
        </Col>
      </Row>
    );
  }
}

const View = Form.create()(ViewForm);
export default View;
           

edit.js表单中的富文本编辑器

import React, { Component } from "react";
import E from "wangeditor"

class Wangeditor extends Component {
  constructor(props, context) {
    super(props, context);
    this.myRefOne = React.createRef();
    this.state = {
      editorContent: ""
    }
  }
  componentDidMount() {
    const elem = this.myRefOne;
    this.editor = new E(elem);
    // 使用 onchange 函数监听内容的变化,并实时更新到 state 中
    this.editor.customConfig.onchange = html => {
      this.setState({
        editorContent: html
      });
      // let wordText = this.editor.txt.text();
      this.props.parentThis.saveEditor(html);
    }
    this.editor.create();
    this.editor.txt.html(this.state.editorContent);
  }
  // 注意此处有个需要注意的坑,在回显过程中,需要对比props修改的传值问题
  shouldComponentUpdate(nextProps) {
    if (this.state.editorContent !== nextProps.value) {
      this.setState({
        editorContent: nextProps.value
      }, () => {
        this.editor.txt.html(this.state.editorContent);
      });
      return true;
    } else {
      return false;
    }

  }
  render() {
    // const { getFieldDecorator, value: { note }, parentThis } = this.props;
    return (
      <div className="editor">
        {/* 将生成编辑器 */}
        <div
          ref={(ref) => this.myRefOne = ref}
          style={{
            textAlign: "left"
          }}
        >
        </div>
      </div>
    );
  }
}

export default Wangeditor;
           

继续阅读