提交 47dcb386 authored 作者: chscls@163.com's avatar chscls@163.com

富文本bug

上级 fbb8c007
......@@ -64,7 +64,7 @@ export default class DraftEditor extends React.Component {
constructor(props) {
super(props);
const value = props.value || {};
const editorState = changeToDraftState2(blocks)
this.state = {
editorState: value.editorState,
......
import React from 'react'
import styles from './DraftEditor.less';
import { Modal, Form, Input, Button, message, Upload, Icon } from 'antd'
import b from '../assets/专家经验系统切图/智能报告/B.png'
import ii from '../assets/专家经验系统切图/智能报告/_.png'
import it from '../assets/专家经验系统切图/智能报告/I.png'
import h from '../assets/专家经验系统切图/智能报告/H.png'
import blockQu from '../assets/专家经验系统切图/智能报告/blockQu.png'
import code from '../assets/专家经验系统切图/智能报告/___.png'
import prjectNum from '../assets/专家经验系统切图/智能报告/prjectNum.png'
import num from '../assets/专家经验系统切图/智能报告/num.png'
import t from '../assets/专家经验系统切图/智能报告/T.png'
import lk from '../assets/专家经验系统切图/智能报告/lk.png'
import pic from '../assets/专家经验系统切图/智能报告/pic.png'
import video from '../assets/专家经验系统切图/智能报告/video.png'
import sum from '../assets/专家经验系统切图/智能报告/sum.png'
import attrs from '../assets/专家经验系统切图/智能报告/attr.png'
import config from '@/webPublic/one_stop_public/config'
import MyBlockRender from './MyBlockRender'
import { changeToDraftState2, changeFromDraftState2,changeToDraftState } from '../utils/myutils'
import {
Editor, EditorState, AtomicBlockUtils, convertFromRaw, convertToRaw, CompositeDecorator, RichUtils
} from 'draft-js';
const FormItem = Form.Item;
function getBlockStyle(block) {
switch (block.getType()) {
case 'blockquote': return 'RichEditor-blockquote';
default: return null;
}
}
const StyleControls = (props) => {
const { editorState } = props;
const selection = editorState.getSelection();
const blockType = editorState
.getCurrentContent()
.getBlockForKey(selection.getStartKey())
.getType();
var currentStyle = props.editorState.getCurrentInlineStyle();
return (
<div style={{ borderBottom: "1px solid gray", borderTop: "1px solid gray" ,height:50,paddingTop:10}}>
{props.btns.map((fn) =>
<StyleButton
key={fn.label}
active={fn.type == "block" ? fn.style === blockType : currentStyle.has(fn.style)}
label={fn}
onToggle={fn.type == "block" ? props.toggleBlockType : props.toggleInlineStyle}
style={fn.style}
/>
)}
</div>
);
};
export default class DraftEditorCom extends React.Component {
constructor(props) {
super(props);
const value = props.value || {};
const editorState = changeToDraftState(value)
this.state = {
editorState: editorState,
modalVisible: false,
fnKey: "",
styleMap: {
'RED': {
color: 'red',
},
}
};
this.setEditor = (editor) => {
this.editor = editor;
};
this.onChange = (editorState,callback) => {
if (!('value' in this.props)) {
this.setState({ editorState },()=>{
if(callback)callback()
});
}
this.triggerChange({ editorState },()=>{
if(callback)callback()
});
}
this.focusEditor = () => {
if (this.editor) {
this.editor.focus();
}
};
this.triggerChange = (changedValue,callback) => {
// Should provide an event to pass value to Form.
const onChange = this.props.onChange;
const x = changeFromDraftState2(changedValue.editorState)
if (onChange) {
onChange(JSON.stringify(x));
}
if(callback) callback();
};
}
exchange=(data,editKey,callback)=>{
const blocks = changeFromDraftState2(this.state.editorState)
const bs =blocks.blocks
var b;
for(var i=0;i<bs.length;i++){
if(bs[i].key==editKey){
b=bs[i];
break;
}
}
const entityKey=b.entityRanges[0].key+"";
blocks.entityMap[entityKey].data=data
const editorState = changeToDraftState2(blocks)
this.onChange(editorState,callback)
}
extends=(data,type,text,callback)=>{
var editorState = this.state.editorState
const contentState = editorState.getCurrentContent();
const contentStateWithEntity = contentState.createEntity(type, 'IMMUTABLE', data);
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const newEditorState = EditorState.set(editorState, { currentContent: contentStateWithEntity });
const xx = AtomicBlockUtils.insertAtomicBlock(newEditorState, entityKey, text);
if (!('value' in this.props)) {
this.setState({ editorState: xx }, () => {
callback()
});
}
this.triggerChange({ editorState: xx}, () => {
callback()
});
}
urlChange(event) {
const target = event.target;
this.setState({
url: target.value
});
}
toggleBlockType = (blockType) => {
this.onChange(
RichUtils.toggleBlockType(
this.state.editorState,
blockType
)
);
}
toggleInlineStyle = (inlineStyle) => {
this.onChange(
RichUtils.toggleInlineStyle(
this.state.editorState,
inlineStyle
)
);
}
componentWillReceiveProps(nextProps) {
// Should be a controlled component.
if ('value' in nextProps) {
const value = nextProps.value;
this.setState({editorState: changeToDraftState(value)});
}
}
okHandle = () => {
}
insertAttr = () => {
if (!('value' in this.props)) {
this.setState({ modalVisible: true, fnKey: "attr" });
}
this.triggerChange({ modalVisible: true, fnKey: "attr" });
}
insertPic = () => {
if (!('value' in this.props)) {
this.setState({ modalVisible: true, fnKey: "image" });
}
this.triggerChange({ modalVisible: true, fnKey: "image" });
}
insertFormula = () => {
if (!('value' in this.props)) {
this.setState({ modalVisible: true, fnKey: "formula" });
}
this.triggerChange({ modalVisible: true, fnKey: "formula" });
}
insertVideo = () => {
if (!('value' in this.props)) {
this.setState({ modalVisible: true, fnKey: "video" });
}
this.triggerChange({ modalVisible: true, fnKey: "video" });
}
insertLink = () => {
const x = this.state.editorState.getSelection().getStartOffset()
const y = this.state.editorState.getSelection().getEndOffset()
if ((y - x) == 0) {
message.error("请选择需要插入链接的内容")
return
}
if (!('value' in this.props)) {
this.setState({ modalVisible: true, fnKey: "link" });
}
this.triggerChange({ modalVisible: true, fnKey: "link" });
}
callback3 = (content) => {
const { editorState } = this.state
const contentState = editorState.getCurrentContent();
const contentStateWithEntity = contentState.createEntity('video', 'IMMUTABLE', content);
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const newEditorState = EditorState.set(editorState, { currentContent: contentStateWithEntity });
const xx = AtomicBlockUtils.insertAtomicBlock(newEditorState, entityKey, '[视频]');
if (!('value' in this.props)) {
this.setState({ editorState: xx, modalVisible: false, });
}
this.triggerChange({ editorState: xx, modalVisible: false, });
}
callback4 = (content) => {
const { editorState } = this.state
const contentState = editorState.getCurrentContent();
const contentStateWithEntity = contentState.createEntity('attr', 'IMMUTABLE', content);
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const newEditorState = EditorState.set(editorState, { currentContent: contentStateWithEntity });
const xx = AtomicBlockUtils.insertAtomicBlock(newEditorState, entityKey, '[附件]');
if (!('value' in this.props)) {
this.setState({ editorState: xx, modalVisible: false, });
}
this.triggerChange({ editorState: xx, modalVisible: false, });
}
callback2 = (content) => {
const { editorState } = this.state
const contentState = editorState.getCurrentContent();
const contentStateWithEntity = contentState.createEntity('image', 'IMMUTABLE', content);
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const newEditorState = EditorState.set(editorState, { currentContent: contentStateWithEntity });
const xx = AtomicBlockUtils.insertAtomicBlock(newEditorState, entityKey, '[图片]');
if (!('value' in this.props)) {
this.setState({ editorState: xx, modalVisible: false, });
}
this.triggerChange({ editorState: xx, modalVisible: false, });
}
callback = (content) => {
const { editorState } = this.state;
// 获取contentState
const contentState = editorState.getCurrentContent();
// 在contentState上新建entity
const contentStateWithEntity = contentState.createEntity(
'LINK',
// 'MUTABLE',
// 'IMMUTABLE',
'SEGMENTED',
{ url: content.url },
);
// 获取到刚才新建的entity
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
// 把带有entity的contentState设置到editorState上
const newEditorState = EditorState.set(editorState, { currentContent: contentStateWithEntity });
// 把entity和选中的内容对应
const xx = RichUtils.toggleLink(
newEditorState,
newEditorState.getSelection(),
entityKey
)
if (!('value' in this.props)) {
this.setState({ editorState: xx, modalVisible: false});
}
this.triggerChange({ editorState: xx, modalVisible: false});
}
modelContent = () => {
if (this.state.fnKey == "link") {
return <LinkForm callback={this.callback} />
} else if (this.state.fnKey == "image") {
return <PicForm callback={this.callback2} />
} else if (this.state.fnKey == "video") {
return <VideoForm callback={this.callback3} />
} else if (this.state.fnKey == "formula") {
return <FormulaForm callback={this.callback2} />
}else if (this.state.fnKey == "attr") {
return <AttrForm callback={this.callback4} />
}
}
deleteBlock=(editKey)=>{
const oldObj = changeFromDraftState2(this.state.editorState)
const blocks = JSON.parse(JSON.stringify(oldObj));
const bs =blocks.blocks
var b;
var j;
for(var i=0;i<bs.length;i++){
if(bs[i].key==editKey){
b=bs[i];
j=i;
break;
}
}
const entityKey=b.entityRanges[0].key+"";
delete blocks.entityMap[entityKey]
blocks.blocks.splice(j,1)
const editorState = changeToDraftState2(blocks)
if (!('value' in this.props)) {
this.setState({ editorState });
}
this.triggerChange({ editorState });
}
render() {
const btns = [
{ label: 'Bold', style: 'BOLD', type: "inline", icon: b },
{ label: 'Italic', style: 'ITALIC', type: "inline", icon: it },
{ label: 'line1', type: "line", icon: ii },
{ label: 'H1', style: 'header-one', type: "block", icon: h },
/* {label: 'H2', style: 'header-two',type:"block",icon:b},
{label: 'H3', style: 'header-three',type:"block",icon:b},
{label: 'H4', style: 'header-four',type:"block",icon:b},
{label: 'H5', style: 'header-five',type:"block",icon:b},
{label: 'H6', style: 'header-six',type:"block",icon:b}, */
{ label: 'Blockquote', style: 'blockquote', type: "block", icon: blockQu },
{ label: 'Code Block', style: 'code-block', type: "block", icon: code },
{ label: 'UL', style: 'unordered-list-item', type: "block", icon: prjectNum },
{ label: 'OL', style: 'ordered-list-item', type: "block", icon: num },
{ label: 'line2', type: "line", icon: ii },
{ label: 'lk', type: "fn", icon: lk, fn: this.insertLink },
{ label: 'pic', type: "fn", icon: pic, fn: this.insertPic },
{ label: 'video', type: "fn", icon: video, fn: this.insertVideo },
/* { label: 'sum', type: "fn", icon: sum, fn: this.insertFormula }, */
{ label: 'att', type: "fn", icon: attrs, fn: this.insertAttr },
{ label: 'line3', type: "line", icon: ii },
{ label: 'Del', style: 'STRIKETHROUGH', type: "inline", icon: t },
];
const { modalVisible } = this.state
return (
<div>
<StyleControls
btns={btns}
editorState={this.state.editorState}
toggleInlineStyle={this.toggleInlineStyle} toggleBlockType={this.toggleBlockType}
/>
<div className={styles.basic} style={{
height: '400px',
overflowY: 'auto'
}} onClick={this.focusEditor}>
<Editor
ref={this.setEditor}
blockStyleFn={getBlockStyle}
customStyleMap={this.state.styleMap}
blockRendererFn={MyBlockRender.bind(this,false,null,this.props.editBlock,this.deleteBlock)}
editorState={this.state.editorState}
placeholder={this.props.placeholder || "请输入"}
onChange={this.onChange} />
</div>
<Modal
width='700px'
maskClosable={false}
destroyOnClose
title={"插入对象"}
visible={modalVisible}
footer={null}
onCancel={() => this.setState({ modalVisible: false })}>
{this.modelContent()}
</Modal>
</div>
)
}
}
class StyleButton extends React.Component {
constructor() {
super();
this.onToggle = (e) => {
e.preventDefault();
this.props.onToggle(this.props.style);
};
}
render() {
const { label } = this.props
return (
<a key={label.label} onMouseDown={this.onToggle} onClick={label.fn} style={{ marginLeft: 20 }}>
<img src={label.icon} />
</a>
);
}
}
@Form.create()
class LinkForm extends React.Component {
constructor(props) {
super(props);
}
submit = (e) => {
e.preventDefault();
const { form } = this.props;
form.validateFields((err, fieldsValue) => {
if (err) return;
this.props.callback(fieldsValue)
})
}
render() {
const { form } = this.props;
return (
<Form onSubmit={this.submit}>
<FormItem labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label="链接地址">
{form.getFieldDecorator('url', {
rules: [{ required: true, message: '请输入链接名称' }],
})(<Input placeholder="请输入链接名称" />)}
</FormItem>
<Button type="primary" htmlType="submit">
确定
</Button>
</Form>
);
}
}
@Form.create()
class AttrForm extends React.Component {
constructor(props) {
super(props);
this.state={
url:null,
name:null,
}
}
submit = (e) => {
e.preventDefault();
const { form } = this.props;
form.validateFields((err, fieldsValue) => {
if (err) return;
var src = fieldsValue.src;
src = src[src.length - 1].response
const params = {
...fieldsValue,
src,
name:this.state.name
}
this.props.callback(params)
})
}
normFile = (e) => {
if (Array.isArray(e)) {
return e;
}
return e && e.fileList;
}
onChange=(info) =>{
if (info.file.status === 'done') {
message.success(`文件上传成功`);
this.setState({url:info.file.response,name:info.file.name})
} else if (info.file.status === 'error') {
message.error(`文件上传失败`);
}
};
render() {
const { form } = this.props;
const {url,name} =this.state
return (
<Form onSubmit={this.submit}>
<FormItem labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label="上传附件">
{form.getFieldDecorator('src', {
valuePropName: 'fileList',
getValueFromEvent: this.normFile,
})(<Upload.Dragger onChange={this.onChange} showUploadList={false} name="file" action={config.uploadUrl} onChangemultiple={false} style={{ padding: 0 }}>
{url?<a href={config.httpServer + url} target="_blank" >{name}</a>:<p className="ant-upload-drag-icon" style={{ marginBottom: 0,height:400 }}>
<Icon type="video" />
</p>}
</Upload.Dragger>)}
</FormItem>
<Button type="primary" htmlType="submit">
确定
</Button>
</Form>
);
}
}
@Form.create()
class VideoForm extends React.Component {
constructor(props) {
super(props);
this.state={
url:null
}
}
submit = (e) => {
e.preventDefault();
const { form } = this.props;
form.validateFields((err, fieldsValue) => {
if (err) return;
var src = fieldsValue.src;
src = src[src.length - 1].response
const params = {
...fieldsValue,
src
}
this.props.callback(params)
})
}
normFile = (e) => {
if (Array.isArray(e)) {
return e;
}
return e && e.fileList;
}
beforeUpload=(file)=> {
const isJPG = file.type === 'video/mp4';
if (!isJPG) {
message.error('请上传mp4格式文件!');
}
return isJPG ;
}
onChange=(info) =>{
if (info.file.status === 'done') {
message.success(`视频上传成功`);
this.setState({url:info.file.response})
} else if (info.file.status === 'error') {
message.error(`视频上传失败`);
}
};
render() {
const { form } = this.props;
const {url} =this.state
return (
<Form onSubmit={this.submit}>
<FormItem labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label="上传视频">
{form.getFieldDecorator('src', {
valuePropName: 'fileList',
getValueFromEvent: this.normFile,
})(<Upload.Dragger beforeUpload={this.beforeUpload} onChange={this.onChange} showUploadList={false} name="file" action={config.uploadUrl} onChangemultiple={false} style={{ padding: 0 }}>
{url?<video src={config.httpServer + url} controls="controls">您的浏览器不支持 video 标签。
</video>:<p className="ant-upload-drag-icon" style={{ marginBottom: 0,height:400 }}>
<Icon type="video" />
</p>}
</Upload.Dragger>)}
</FormItem>
<Button type="primary" htmlType="submit">
确定
</Button>
</Form>
);
}
}
@Form.create()
class PicForm extends React.Component {
constructor(props) {
super(props);
this.state={
url:null
}
}
beforeUpload=(file)=> {
const isJPG = (file.type === 'image/jpeg'||file.type === 'image/png') ;
if (!isJPG) {
message.error('请上传jpg或者png格式文件!');
}
return isJPG ;
}
submit = (e) => {
e.preventDefault();
const { form } = this.props;
form.validateFields((err, fieldsValue) => {
if (err) return;
var src = fieldsValue.src;
src = src[src.length - 1].response
const params = {
...fieldsValue,
src
}
this.props.callback(params)
})
}
normFile = (e) => {
if (Array.isArray(e)) {
return e;
}
return e && e.fileList;
}
onChange=(info) =>{
if (info.file.status === 'done') {
message.success(`图片上传成功`);
this.setState({url:info.file.response})
} else if (info.file.status === 'error') {
message.error(`图片上传失败`);
}
};
render() {
const { form } = this.props;
const {url} =this.state
return (
<Form onSubmit={this.submit}>
<FormItem labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label="上传图片">
{form.getFieldDecorator('src', {
valuePropName: 'fileList',
getValueFromEvent: this.normFile,
})(<Upload.Dragger beforeUpload={this.beforeUpload} showUploadList={false} name="file" action={config.uploadUrl} onChange={this.onChange} multiple={false} style={{ padding: 0 }}>
{url?<img src={config.httpServer+url} style={{height:400,width:"100%"}}/>:<p className="ant-upload-drag-icon" style={{ marginBottom: 0,height:400 }}>
<Icon type="video" />
</p>}
</Upload.Dragger>)}
</FormItem>
<Button type="primary" htmlType="submit">
确定
</Button>
</Form>
);
}
}
@Form.create()
class FormulaForm extends React.Component {
constructor(props) {
super(props);
window.latex = (gs) => {
this.props.callback({ src: '/latex?code=' + encodeURI(gs), description: "" })
}
}
render() {
const { form } = this.props;
return (
<iframe src="/gongshi/gongshi.html" style={{ width: '100%', minHeight: '400px', border: 'solid 1px #0062d5' }} ></iframe>
);
}
}
......@@ -71,7 +71,7 @@ import { Base16Encode } from '../Base16/index';
import { getToken } from '../utils/token';
import { formulaList } from '../excelInitFuc/functionList';
import FilePreview from '../filePreview';
import DraftEditor from '../App/DraftEditor';
import DraftEditorCom from '../App/DraftEditorCom';
const Item = MobileList.Item;
const Brief = Item.Brief;
function getBase64(value) {
......@@ -2877,12 +2877,12 @@ export default class tableCom extends Component {
break;
case 'RichText':
cm = getFieldDecorator(dataColumn.base52, {
initialValue: { editorState: changeToDraftState(initValue) },
initialValue: initValue,
rules:
json.vlds && json.vlds.length > 0
? json.vlds
: [{ required: required, message: '请输入' }],
})(<DraftEditor placeholder={json.placeholder} />);
})(<DraftEditorCom placeholder={json.placeholder} />);
if (get === 'mobile' && json.isLabel && title) {
cm = (
<Form.Item
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论