【后台管理系统】—— Ant Design Pro结合插件(一)
一、富文本braft-editor
- 安装并引用
npm install braft-editor --save import BraftEditor from 'braft-editor'
import 'braft-editor/dist/index.css' state中初始内容
editorState: BraftEditor.createEditorState(),
表单中使用<BraftEditor/>
<FormItem label="教程正文" {...formLayout}>
{getFieldDecorator('content', {
validateTrigger: 'onBlur',
rules: [{
required: true,
validator: (_, value, callback) => {
if (value.isEmpty()) {
callback('请输入正文内容')
} else {
callback()
}
}
}],
// 内容必须通过BraftEditor.createEditorState()转化为可读的格式
initialValue: current && detail ? BraftEditor.createEditorState(defaultContent(detail.content)) : ''
})(
<BraftEditor
className="my-editor"
controls={controls} // 按需添加控件按钮
extendControls={extendControls} // 自定义控件按钮
placeholder="请输入正文内容"
media={{ // 媒体对象
uploadFn: handleUploadFn, // 上传七牛云服务器获取url
validateFn: handleValidateFn, // 上传文件的限制
accepts: { // 可上传格式
image: 'image/png, image/jpeg, image/jpg, image/gif, image/webp, image/apng, image/svg',
video: 'video/mp4',
audio: 'audio/mp3, audio/mp4, audio/ogg, audio/mpeg'
}
}}
onChange={this.handleContentChange} // 内容更改方法
/>
)}
</FormItem>
- 打开弹框时处理获取到的HTML格式的content,转化为插件可读格式,同时字符串切割替换转换后台传来的七牛云前缀与安卓ios视频图片需要的标签处理
showEditModal = item => {
const { dispatch } = this.props; let content = '';
if(item.content){
content = item.content;
let contentObj = JSON.parse(BraftEditor.createEditorState(content).toRAW());
let urlArr;
Object.keys(contentObj.entityMap).forEach((key) => {
if(contentObj.entityMap[key].data.url){
urlArr = contentObj.entityMap[key].data.url.split('/')
console.log('编辑时', urlArr)
if(urlArr.length == 2){ //ios视频前缀yihezo
urlArr.splice(0,1);
contentObj.entityMap[key].data.url = `${setFileHost()}`+ 'yihezo/' + urlArr.join('/');
} if(urlArr.length == 3){ //其它媒体文件前缀sys/tutorial
urlArr.splice(0,1);
contentObj.entityMap[key].data.url = `${setFileHost()}`+ 'sys/' + urlArr.join('/');
}
}
});
let contentRaw = JSON.stringify(contentObj);
item.content = contentRaw;
}; dispatch({
type: 'course/fetchDetail',
payload: {
id: item.id
},
callback: (res) => {
if(res){
let detail = res.data;
let HTML = detail.content;
HTML = HTML.substring(24).substring(0, HTML.length-6);
HTML = HTML.replace(/style='max-width:100%' /g, "").replace(/poster=['|"].*?['|"]/g, "").replace(/alt='picvision' /g, "");
detail.content = HTML; this.setState({
detail,
current: item,
addSubmit: false
}, () => {
this.setState({
visible: true
})
});
}
}
})
}; - 组件需要的参数和方法
// 自带的可按需选择的控件按钮
const controls = [ 'undo', 'redo', 'separator',
'font-size', 'line-height', 'letter-spacing', 'separator',
'text-color', 'bold', 'italic', 'underline', 'strike-through', 'separator',
'superscript', 'subscript', 'remove-styles', 'emoji', 'separator', 'text-indent', 'text-align', 'separator',
'headings', 'list-ul', 'list-ol', 'separator',
'link', 'separator', 'hr', 'separator',
'media', 'separator',
'clear'
]; // 上传七牛云服务器获取url
const handleUploadFn = (param) => {
const { file } = param; const fileTypeArr = file.type.split('/');
const fileType = fileTypeArr[0]; if(fileType == 'video'){
handleImageUpload(file, 'tutorialVideo').then(res => {
param.success({
url: `${setFileHost()+res}`,
meta: {
id: new Date().getTime(),
loop: false,
autoPlay: false,
controls: true
}
})
})
}else{
handleImageUpload(file, 'tutorial').then(res => {
param.success({
url: `${setFileHost()+res}`,
meta: {
id: new Date().getTime(),
loop: false,
autoPlay: false,
controls: true
}
})
})
}
} // 可上传文件的大小范围
const handleValidateFn = (file) => {
return file.size < 1024 * 1024 * 100
} // content内容存在时,处理为可编辑数据
const defaultContent = (content) => {
let contentObj = JSON.parse(BraftEditor.createEditorState(content).toRAW());
let urlArr;
Object.keys(contentObj.entityMap).forEach((key) => {
if(contentObj.entityMap[key].data.url){
urlArr = contentObj.entityMap[key].data.url.split('/')
console.log('默认内容', urlArr);
if(urlArr.length == 2){ //ios视频前缀yihezo
urlArr.splice(0,1);
contentObj.entityMap[key].data.url = `${setFileHost()}`+ 'yihezo/' + urlArr.join('/');
} if(urlArr.length == 3){ //其它媒体文件前缀sys/tutorail
urlArr.splice(0,1);
contentObj.entityMap[key].data.url = `${setFileHost()}`+ 'sys/' + urlArr.join('/');
}
}
});
let contentRaw = JSON.stringify(contentObj);
return contentRaw;
} // 自定义控件按钮
const extendControls = [
{
key: 'custom-button',
type: 'button',
text: '预览',
onClick: this.handleEditPreview
}
]; - react页面渲染HTML
<div dangerouslySetInnerHTML = {{__html:返回的html代码片段}} ></div>
原理:
1.dangerouslySetInnerHTMl 是React标签的一个属性,类似于angular的ng-bind;
2.有2个{{}},第一{}代表jsx语法开始,第二个是代表dangerouslySetInnerHTML接收的是一个对象键值对;
3.既可以插入DOM,又可以插入字符串;
二、图片裁剪
- 安装并引用
npm install react-cropper --save import Cropper from 'react-cropper'
import "cropperjs/dist/cropper.css" Modal弹框包裹<Cropper />组件
<Modal
title="上传轮播图"
visible={this.state.editImageModalVisible}
width={500}
bodyStyle={{height: 350, textAlign: 'center' }}
maskClosable={false}
onCancel={this.handleCancelImg}
okText="确认上传"
cancelText="取消"
onOk={this.handleSaveImg}
onCancel={this.handleCancelImg}
>
<Cropper
src={this.state.srcCropper} //图片路径,即是base64的值,在Upload上传的时候获取到的
ref="cropper"
viewMode={1} //定义cropper的视图模式
aspectRatio={1/1}
zoomable={false} //是否允许放大图像
movable={false}
guides={true} //显示在裁剪框上方的虚线
background={false} //是否显示背景的马赛克
rotatable={false} //是否旋转
style={{ maxWidth:500, maxHeight: 300 }}
cropBoxResizable={true} //是否可以拖拽
cropBoxMovable={true} //是否可以移动裁剪框
dragMode="move"
center={true}
/>
</Modal>beforeUpload方法中在获得file之后,判断this.refs.cropper,设置组件所需参数
beforeUpload = (file) => {
let type = file.type.split('/')[0];
let name = file.name.split('.')[0];
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{
//当打开同一张图片的时候清除上一次的缓存
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;
}
}点击弹框中【确定/保存裁剪后的图片,上传七牛云获取url,在Upload组件中显示】,【取消/关闭弹框】
handleSaveImg = () => {
let imgArray = [...this.state.imgList];
let imgFile = this.dataURLtoFile(this.refs.cropper.getCroppedCanvas().toDataURL(), this.state.selectImgName)
imgArray.push(imgFile); // 上传七牛云方法 --- Upload组件使用中有js封装过程
handleImageUpload(imgFile, 'image').then(res => {
this.setState({
imgList: imgArray,
srcCropper: this.state.srcCropper, //cropper的图片路径
}, () => {
this.setState({
editImageModalVisible: false
})
})
this.handleFileThumb(res, imgFile, imgArray)
})
} handleCancelImg = () => {
this.setState({
editImageModalVisible: false,
});
}
三、统计图表
- 官网图例:https://bizcharts.net/products/bizCharts
- 安装和引用
npm install bizcharts --save import {ChartCard, Field, TimelineChart} from '@/components/Charts'; import {
G2,
Chart,
Geom,
Axis,
Tooltip,
Coord,
Label,
Legend,
View,
Guide,
Shape,
Facet,
Util
} from "bizcharts";官方折线图Mock数据示例:
class Curved extends React.Component {
render() {
const data = [
{
month: "Jan",
city: "Tokyo",
temperature: 7
},
{
month: "Jan",
city: "London",
temperature: 3.9
},
{
month: "Feb",
city: "Tokyo",
temperature: 6.9
},
{
month: "Feb",
city: "London",
temperature: 4.2
},
{
month: "Mar",
city: "Tokyo",
temperature: 9.5
},
{
month: "Mar",
city: "London",
temperature: 5.7
},
{
month: "Apr",
city: "Tokyo",
temperature: 14.5
},
{
month: "Apr",
city: "London",
temperature: 8.5
},
{
month: "May",
city: "Tokyo",
temperature: 18.4
},
{
month: "May",
city: "London",
temperature: 11.9
},
{
month: "Jun",
city: "Tokyo",
temperature: 21.5
},
{
month: "Jun",
city: "London",
temperature: 15.2
},
{
month: "Jul",
city: "Tokyo",
temperature: 25.2
},
{
month: "Jul",
city: "London",
temperature: 17
},
{
month: "Aug",
city: "Tokyo",
temperature: 26.5
},
{
month: "Aug",
city: "London",
temperature: 16.6
},
{
month: "Sep",
city: "Tokyo",
temperature: 23.3
},
{
month: "Sep",
city: "London",
temperature: 14.2
},
{
month: "Oct",
city: "Tokyo",
temperature: 18.3
},
{
month: "Oct",
city: "London",
temperature: 10.3
},
{
month: "Nov",
city: "Tokyo",
temperature: 13.9
},
{
month: "Nov",
city: "London",
temperature: 6.6
},
{
month: "Dec",
city: "Tokyo",
temperature: 9.6
},
{
month: "Dec",
city: "London",
temperature: 4.8
}
];
const cols = {
month: {
range: [0, 1]
}
};
return (
<div>
<Chart height={400} data={data} scale={cols} forceFit>
<Legend />
<Axis name="month" />
<Axis
name="temperature"
label={{
formatter: val => `${val}°C`
}}
/>
<Tooltip
crosshairs={{
type: "y"
}}
/>
<Geom
type="line"
position="month*temperature"
size={2}
color={"city"}
shape={"smooth"}
/>
<Geom
type="point"
position="month*temperature"
size={4}
shape={"circle"}
color={"city"}
style={{
stroke: "#fff",
lineWidth: 1
}}
/>
</Chart>
</div>
);
}
} ReactDOM.render(<Curved />, mountNode)
转载请注明出处
【后台管理系统】—— Ant Design Pro结合插件(一)的更多相关文章
- 【后台管理系统】—— Ant Design Pro入门学习&项目实践笔记(三)
前言:前一篇记录了[后台管理系统]目前进展开发中遇到的一些应用点,这一篇会梳理一些自己学习Ant Design Pro源码的功能点.附:Ant Design Pro 在线预览地址. Dashboard ...
- Ant Design Pro (中后台系统)教程
一.概念:https://pro.ant.design/docs/getting-started-cn(官方网站) 1.Ant Design Pro 是什么: https://www.cnblogs ...
- ant design pro(一)安装、目录结构、项目加载启动【原始、以及idea开发】
一.概述 1.1.脚手架概念 编程领域中的“脚手架(Scaffolding)”指的是能够快速搭建项目“骨架”的一类工具.例如大多数的React项目都有src,public,webpack配置文件等等, ...
- 使用ant design pro搭建项目
脚手架搭建 git clone --depth=1 https://github.com/ant-design/ant-design-pro.git my-project 然后 cd my-proje ...
- 轻松玩转Ant Design Pro一
ant design pro来源于ant design,其是一段自带样式的react组件,用于企业后台的漂亮的,可控的组件.ant design有很多组件和样式,不可能所有都记住,我们只要记住常用的, ...
- ant design pro 当中改变ant design 组件的样式和 数据管理
ant design pro 简介 官网简介 链接 https://pro.ant.design/docs/getting-started-cn 项目结构 https://github.com/ant ...
- Ant Design Pro 学习笔记:数据流向
在讲这个问题之前,有一个问题应当讲一下: Ant Design Pro / umi / dva 是什么关系? 首先是 umi / dva 的关系. umi 是一个基于路由的 react 开发框架. d ...
- 阿里开源项目之Ant Design Pro
本篇文章主要包含的内容有三个方面. 第一.Ant Design Pro简介; 第二.Ant Design Pro能做什么; 第三.初步使用; 我相信通过这三个方面的讲解能让你大概知道Ant Desig ...
- ant design pro (十一)advanced Mock 和联调
一.概述 原文地址:https://pro.ant.design/docs/mock-api-cn Mock 数据是前端开发过程中必不可少的一环,是分离前后端开发的关键链路.通过预先跟服务器端约定好的 ...
随机推荐
- qt使用QWT注意事项
当继承某个QWT类时,有是使用O_OBJECT弘会出现问题 切记在工程文件里别忘了添加这一句 DEFINES+=QWT_DLL
- Flask开发系列之Flask+redis实现IP代理池
Flask开发系列之Flask+redis实现IP代理池 代理池的要求 多站抓取,异步检测:多站抓取:指的是我们需要从各大免费的ip代理网站,把他们公开的一些免费代理抓取下来:一步检测指的是:把这些代 ...
- 初探 -2 JavaScript
JavaScript 简介 JavaScript 是互联网上最流行的脚本语言,这门语言可用于 HTML 和 web,更可广泛用于服务器.PC.笔记本电脑.平板电脑和智能手机等设备. JavaScrip ...
- MySQL安装+Navicat_Premium(安装+破解)+Navicat_Premium中MySQL的localhost不能正常连接+不能连接Docker启动容器中的MySQL
MySQL安装 安装MySQL 我这里安装的是 MySQL 8.0 Command Line Client 下载+安装 详情见 https://www.cnblogs.com/taopanfeng/p ...
- Jmeter分布式测试dubbo接口1
最近工作中接到一个需求,需要对一个Dubbo接口进行压力测试,测试其性能,之前一直使用jmeter做压力测试,在踏了好多坑之后,决定把这些记录下来,顺便也希望能帮助到大家. 开始测试之前,我们需要先知 ...
- 登陆Oracle的管理员登陆
任务栏:开始——运行,CMD 超级管理员进入系统:conn sys/oracle@prod as sysdba; 修改的代码:alter user username identified by use ...
- uwsgi_response_write_body报错的几种情况
1.uwsgi_response_write_body_do(): Broken pipe 出现这种情况一般是由于客户端无法等到服务端的回应而关闭了连接,常出现与nginx + uwsgi的情况,当u ...
- Codeforces 985 最短水桶分配 沙堆构造 贪心单调对列
A B /* Huyyt */ #include <bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) #define mkp(a, ...
- Android开发艺术探索笔记之Activity
内容来源:Android开发艺术探索第一章:Activity的生命周期与启动模式 不能在onPause中做重量级的操作,因为必须执行完成以后新Activity才能Resume.onPause和onSt ...
- pushd&popd&dirs命令
dirs 显示当前目录栈中的所有记录 -p 一个目录一行显示 -l 以完整格式显示 -c 删除目录栈中的所有记录 -v 每行一个目录来显示,每个目录前加上编号 +N 从左到右的第n个 ...