|
@@ -1,18 +1,20 @@
|
|
|
/* eslint-disable camelcase */
|
|
|
import React from 'react'
|
|
|
-import { Button, Form, Input, Select, Slider, Switch, InputNumber, Icon, Popover, Modal, message } from 'antd'
|
|
|
+import { Button, Form, Input, Select, Slider, Switch,Row,Col, InputNumber, Icon, Popover, Modal, message } from 'antd'
|
|
|
import { Rnd } from 'react-rnd'
|
|
|
-import { ImagePreview } from 'wptpc-design'
|
|
|
+import { ImagePreview, JsonPage } from 'wptpc-design'
|
|
|
|
|
|
import isEmpty from 'lodash/isEmpty'
|
|
|
// import { connect } from 'dva'
|
|
|
|
|
|
import RcColorPicker from 'rc-color-picker'
|
|
|
import 'rc-color-picker/assets/index.css'
|
|
|
-import { create, fetchDetail, update } from './service'
|
|
|
+import { create, fetchDetail, update,fontList } from './service'
|
|
|
|
|
|
import styles from './index.less'
|
|
|
-
|
|
|
+const IconFont = Icon.createFromIconfontCN({
|
|
|
+ scriptUrl: '//at.alicdn.com/t/font_2018233_fl4w8ponsnu.js',
|
|
|
+});
|
|
|
const { Option } = Select
|
|
|
const { confirm } = Modal
|
|
|
|
|
@@ -32,12 +34,91 @@ export default class Edit extends React.PureComponent {
|
|
|
},
|
|
|
element: [],
|
|
|
activeObjectIndex: 0,
|
|
|
+ canvasArea:false,// 鼠标是否在画布区域
|
|
|
editName: '',
|
|
|
imgs: [], // 预览图片的url
|
|
|
- previwVisible: false // 预览框是否展示
|
|
|
+ previwVisible: false, // 预览框是否展示
|
|
|
+ fontList:[],//字体列表
|
|
|
}
|
|
|
+ keyPress = event => {
|
|
|
+ const { activeObjectIndex,canvasArea } = this.state
|
|
|
+ const activeObject=this.state.element[activeObjectIndex] || {}
|
|
|
+ const e = event || window.event;
|
|
|
+ const { keyCode } = e;
|
|
|
+ var ctrlKey = e.ctrlKey || e.metaKey;
|
|
|
+ // console.log("🚀 ~ file: $id$.js ~ line 45 ~ Edit ~ ctrlKey", ctrlKey)
|
|
|
+ // console.log("🚀 ~ file: $id$.js ~ line 44 ~ Edit ~ keyCode", keyCode)
|
|
|
|
|
|
- componentDidMount () {
|
|
|
+ if (ctrlKey && keyCode === 90) {
|
|
|
+ e.preventDefault();
|
|
|
+ this.reback = true;
|
|
|
+ // 撤销
|
|
|
+ let list = [];
|
|
|
+ if (localStorage.getItem('posterElement') && JSON.parse(localStorage.getItem('posterElement'))?.length > 0) {
|
|
|
+ list = JSON.parse(localStorage.getItem('posterElement'));
|
|
|
+ if (this.state.id&&list.length===1) {
|
|
|
+ this.reback = false;
|
|
|
+ return
|
|
|
+ }
|
|
|
+ list = list.slice(0, -1);
|
|
|
+ let obj = list.slice(-1)[0];
|
|
|
+ if (!obj) {
|
|
|
+ this.setState({
|
|
|
+ name: '',
|
|
|
+ description: '',
|
|
|
+ bg: {
|
|
|
+ type: 'bg',
|
|
|
+ w: 750,
|
|
|
+ h: 1000,
|
|
|
+ c: '#eaeaea'
|
|
|
+ },
|
|
|
+ element: [],
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ this.setState(obj)
|
|
|
+ }
|
|
|
+ localStorage.setItem('posterElement', JSON.stringify(list));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!canvasArea) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // e.preventDefault(); 不能提取到最外面,有位只有按下方向键才需要阻止默认事件
|
|
|
+ if (keyCode === 37) {
|
|
|
+ e.preventDefault();
|
|
|
+ //左
|
|
|
+ this.updateElement(activeObjectIndex, { dx: activeObject.dx-1 })
|
|
|
+ }
|
|
|
+ if (keyCode === 38) {
|
|
|
+ e.preventDefault();
|
|
|
+ //上
|
|
|
+ this.updateElement(activeObjectIndex, { dy: activeObject.dy-1 })
|
|
|
+ }
|
|
|
+ if (keyCode === 39) {
|
|
|
+ e.preventDefault();
|
|
|
+ // 右
|
|
|
+ this.updateElement(activeObjectIndex, { dx: activeObject.dx+1 })
|
|
|
+
|
|
|
+ }
|
|
|
+ if (keyCode === 40) {
|
|
|
+ e.preventDefault();
|
|
|
+ //下
|
|
|
+ this.updateElement(activeObjectIndex, { dy: activeObject.dy+1 })
|
|
|
+
|
|
|
+ }
|
|
|
+ };
|
|
|
+ // 添加监听键盘事件 防止长按多次发送用keyup
|
|
|
+ addKeyUpEvent = () => {
|
|
|
+ window.addEventListener('keydown', this.keyPress);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 移除监听键盘事件
|
|
|
+ removeKeyUpEvent = () => {
|
|
|
+ window.removeEventListener('keydowm', this.keyPress);
|
|
|
+ };
|
|
|
+ componentDidMount() {
|
|
|
+ this.addKeyUpEvent();
|
|
|
+ localStorage.setItem("posterElement",'')
|
|
|
this.setState({ posterHeight: document.body.clientHeight - document.getElementById('poster').offsetTop - 35 })
|
|
|
if (this.props.match.params.id) {
|
|
|
fetchDetail({ id: this.props.match.params.id }).then(res => {
|
|
@@ -46,9 +127,48 @@ export default class Edit extends React.PureComponent {
|
|
|
this.setState({ name: name, description: description, element: element, id: id, bg: bg, imgs: [preview] })
|
|
|
}
|
|
|
})
|
|
|
+ fontList().then(res => {
|
|
|
+ if (res.code === 0) {
|
|
|
+ this.setState({fontList:res.data})
|
|
|
+ }
|
|
|
+ })
|
|
|
}
|
|
|
}
|
|
|
+ componentDidUpdate(prevProps, prevState) {
|
|
|
+ const { name, description, bg, element } = this.state;
|
|
|
+ const { name: nameprev, description: descriptionprev, bg: bgprev, element: elementprev } = prevState;
|
|
|
+ console.log(name,nameprev,111);
|
|
|
+ if (name === nameprev && description === descriptionprev && JSON.stringify(bg) === JSON.stringify(bgprev) && JSON.stringify(element) === JSON.stringify(elementprev)) {
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
+ const temListStr = localStorage.getItem('posterElement');
|
|
|
+ let obj={}
|
|
|
+ let list = [];
|
|
|
+ if (temListStr) {
|
|
|
+ list = JSON.parse(temListStr);
|
|
|
+ }
|
|
|
+ // 撤销的时候就不再去储存值了
|
|
|
+ if (this.reback) {
|
|
|
+ this.reback = false;
|
|
|
+ return
|
|
|
+ }
|
|
|
+ list.push({
|
|
|
+ element: element,
|
|
|
+ name: name,
|
|
|
+ description: description,
|
|
|
+ bg:bg,
|
|
|
+ })
|
|
|
+ // 最多储存 30 步的操作
|
|
|
+ if (list.length >30) {
|
|
|
+ list=list.slice(-30)
|
|
|
+ }
|
|
|
+ localStorage.setItem('posterElement',JSON.stringify(list))
|
|
|
+ }
|
|
|
+ componentWillUnmount() {
|
|
|
+ this.removeKeyUpEvent();
|
|
|
+ localStorage.setItem('posterElement','')
|
|
|
+ }
|
|
|
updateBgState = (value) => {
|
|
|
this.setState({ bg: { ...this.state.bg, ...value } })
|
|
|
}
|
|
@@ -112,6 +232,19 @@ export default class Edit extends React.PureComponent {
|
|
|
// align: 'both-align'
|
|
|
})
|
|
|
break
|
|
|
+ case 'mat':
|
|
|
+ _ele.push({
|
|
|
+ type: 'mat',
|
|
|
+ path: '#mat_' + (this.state.element.filter(item => item.type === 'mat').length + 1) + '#',
|
|
|
+ content: 'https://cdn01t.weipaitang.com/img/20200407u1hmwwai-75so-tvze-5z15-oynukyk8esad-W1125H1500/w/640',
|
|
|
+ w: '100',
|
|
|
+ h: '100',
|
|
|
+ dx: dx + 15,
|
|
|
+ dy: dy + 15,
|
|
|
+ round: 'false'
|
|
|
+ // align: 'both-align'
|
|
|
+ })
|
|
|
+ break
|
|
|
case 'qr':
|
|
|
_ele.push({
|
|
|
content: '我是预览二维码',
|
|
@@ -162,7 +295,16 @@ export default class Edit extends React.PureComponent {
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
-
|
|
|
+ // 动态的加载字体
|
|
|
+ // loadFonts= async ()=> {
|
|
|
+ // const font = new FontFace(
|
|
|
+ // "font84",
|
|
|
+ // "url(https://cdn.weipaitang.com/static/public/202012016ac3fed2-0fe8-fed20fe8-56d0-cdacb08d7de0.ttf)"
|
|
|
+ // );
|
|
|
+ // await font.load();
|
|
|
+ // document.fonts.add(font);
|
|
|
+ // document.body.classList.add("fonts-loaded");
|
|
|
+ // }
|
|
|
render () {
|
|
|
const { bg: { w: bgWidth, h: bgHeight, c: bgColor }, activeObjectIndex, element, name, description, imgs, previwVisible } = this.state
|
|
|
const activeObject = element[activeObjectIndex] || {}
|
|
@@ -208,17 +350,26 @@ export default class Edit extends React.PureComponent {
|
|
|
</div>
|
|
|
<div className={styles.box}>
|
|
|
<h2>元素</h2>
|
|
|
- <ul className={styles.elem}>
|
|
|
+ <div style={{ fontSize: 18,cursor:"pointer" }} >
|
|
|
+ <Row >
|
|
|
+ <Col span={12} onClick={() => this.addShape('text')}><IconFont type='iconwenben'/><span style={{display:'inline-block', margin:5}}>文本</span></Col>
|
|
|
+ <Col span={12} onClick={() => this.addShape('pic')}><Icon type="picture" /><span style={{display:'inline-block', margin:5}}>图片</span></Col>
|
|
|
+ <Col span={12} onClick={() => this.addShape('qr')}><Icon type="qrcode" /><span style={{display:'inline-block', margin:5}}>二维码</span></Col>
|
|
|
+ <Col span={12} onClick={() => this.addShape('mat')}><IconFont type='iconsucai'/><span style={{display:'inline-block', margin:5}}>素材</span></Col>
|
|
|
+ </Row>
|
|
|
+ </div>
|
|
|
+ {/* <ul className={styles.elem}>
|
|
|
<li onClick={() => this.addShape('text')}><img src="https://cdn.weipaitang.com/static/20200416b0b57798-76f7-779876f7-9088-1d2665151e70-W200H200" />文字</li>
|
|
|
<li className={styles.pic} onClick={() => this.addShape('pic')}><img src="https://cdn.weipaitang.com/static/20200416a625b5f0-c5a1-b5f0c5a1-7472-58fbb8d4fb83-W200H200"/>图片</li>
|
|
|
<li className={styles.qr} onClick={() => this.addShape('qr')}><img src="https://cdn.weipaitang.com/static/20200416360ff7ff-c855-f7ffc855-0070-1542fd7ea01e-W200H200"/>二维码</li>
|
|
|
- </ul>
|
|
|
+ </ul> */}
|
|
|
</div>
|
|
|
<div className={styles.box}>
|
|
|
<h2>图层列表</h2>
|
|
|
<ul className={styles.layer}>
|
|
|
{
|
|
|
unique(group).map((_item) => {
|
|
|
+ console.log(_element,'_element');
|
|
|
return <React.Fragment>
|
|
|
<div>分组:{_item || '未分组'}</div>
|
|
|
{
|
|
@@ -226,7 +377,14 @@ export default class Edit extends React.PureComponent {
|
|
|
<li
|
|
|
className={`${activeObjectIndex === item.index ? styles.selected : ''} ${styles[item.type]}`}
|
|
|
onClick={() => this.setState({ activeObjectIndex: item.index })}>
|
|
|
- {(item.type === 'pic' ? item.path : item.t || '').toString().replace(/#/g, '')}
|
|
|
+ <div className={styles.tem} style={{ display: 'inline-block', verticalAlign: -2, backgroundColor: '#1890ff05' }} >
|
|
|
+ {item.type === 'pic'&&<Icon type="picture" />}
|
|
|
+ {item.type === 'mat'&&<IconFont type="iconsucai" />}
|
|
|
+ {item.type === 'text'&&<IconFont type="iconwenben" />}
|
|
|
+ {item.type === 'qr' && <Icon type="qrcode" />}
|
|
|
+ {item.isTemplate ? <IconFont type="iconmu" />:<IconFont type="iconkongbai" />}
|
|
|
+ </div>
|
|
|
+ {((item.type === 'pic'||item.type === 'mat') ? item.path : item.t || '').toString().replace(/#/g, '')}
|
|
|
<Popover placement="right" content={<div><p onClick={() => this.setState({ visible: true, editIndex: item.index, editType: item.type, editName: item.type === 'pic' ? item.path : item.t || '' })}>重命名</p><p onClick={() => this.delElement(item.index, item.type === 'pic' ? item.path : item.t)}>删除</p></div>}>
|
|
|
<Icon type="setting" theme="filled" />
|
|
|
</Popover>
|
|
@@ -240,7 +398,7 @@ export default class Edit extends React.PureComponent {
|
|
|
</ul>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div className={styles.middle}>
|
|
|
+ <div className={styles.middle} onMouseEnter={()=>{this.setState({canvasArea:true})}} onMouseLeave={()=>{this.setState({canvasArea:false})}}>
|
|
|
<div id="canvas" style={{
|
|
|
position: 'relative',
|
|
|
width: Number(bgWidth),
|
|
@@ -366,33 +524,22 @@ export default class Edit extends React.PureComponent {
|
|
|
{
|
|
|
activeObject.type === 'text' && (
|
|
|
<div className={styles.box}>
|
|
|
- <h2>文字</h2>
|
|
|
+ <h2>
|
|
|
+ <span>文字</span>
|
|
|
+ <span style={{float:'right',fontSize:14}}>
|
|
|
+ <span style={{marginRight:5}}>设置为母版</span>
|
|
|
+ <Switch checked={activeObject.isTemplate||false} onChange={(checked) => this.updateElement(activeObjectIndex, { isTemplate: checked })}/>
|
|
|
+ </span>
|
|
|
+ </h2>
|
|
|
<Form layout="vertical">
|
|
|
<Form.Item label="内容">
|
|
|
<Input.TextArea rows={3} value={activeObject.content} onChange={(e) => this.updateElement(activeObjectIndex, { content: e.target.value })}/>
|
|
|
</Form.Item>
|
|
|
<Form.Item label="字体">
|
|
|
<Select value={activeObject.font} onChange={(value) => this.updateElement(activeObjectIndex, { font: value })}>
|
|
|
- <Option value="msyh">msyh</Option>
|
|
|
- <Option value="msyhbd">msyhbd</Option>
|
|
|
- <Option value="NotoSerifCJK.ttc">NotoSerifCJK</Option>
|
|
|
- <Option value="PingFang.ttc">PingFang</Option>
|
|
|
- <Option value="pingfang-sc-semibold">pingfang-sc-semibold</Option>
|
|
|
- <Option value="pingfang_jiancu">pingfang_jiancu</Option>
|
|
|
- <Option value="pingfang_jianxi">pingfang_jianxi</Option>
|
|
|
- <Option value="pingfang_regular">pingfang_regular</Option>
|
|
|
- <Option value="PingFang_SC">PingFang_SC</Option>
|
|
|
- <Option value="pingfang_sc_medium">pingfang_sc_medium</Option>
|
|
|
- <Option value="pingfang_sc_semibold">pingfang_sc_semibold</Option>
|
|
|
- <Option value="simhei">simhei</Option>
|
|
|
- <Option value="SourceHanSansCN-Normal">SourceHanSansCN-Normal</Option>
|
|
|
- <Option value="喜鹊招牌体">喜鹊招牌体</Option>
|
|
|
- <Option value="喜鹊燕书体(简繁体)">喜鹊燕书体(简繁体)</Option>
|
|
|
- <Option value="Songti.ttc">Songti</Option>
|
|
|
- <Option value="SourceHanSansCN-Regular.otf">SourceHanSansCN-Regular</Option>
|
|
|
- <Option value="喜鹊聚珍体regular">喜鹊聚珍体regular</Option>
|
|
|
- <Option value="思源宋体.otf">思源宋体</Option>
|
|
|
- <Option value="方正正粗黑简体">方正正粗黑简体</Option>
|
|
|
+ {(this.state.fontList || []).map(item => {
|
|
|
+ return <Option value={item.value}>{ item.option}</Option>
|
|
|
+ })}
|
|
|
</Select>
|
|
|
</Form.Item>
|
|
|
<div style={{ display: 'flex' }}>
|
|
@@ -488,7 +635,13 @@ export default class Edit extends React.PureComponent {
|
|
|
{
|
|
|
activeObject.type === 'qr' && (
|
|
|
<div className={styles.box}>
|
|
|
- <h2>二维码</h2>
|
|
|
+ <h2>
|
|
|
+ <span>二维码</span>
|
|
|
+ <span style={{float:'right',fontSize:14}}>
|
|
|
+ <span style={{marginRight:5}}>设置为母版</span>
|
|
|
+ <Switch checked={activeObject.isTemplate||false} onChange={(checked) => this.updateElement(activeObjectIndex, { isTemplate: checked })}/>
|
|
|
+ </span>
|
|
|
+ </h2>
|
|
|
<Form layout="vertical">
|
|
|
<Form.Item label="内容">
|
|
|
<Input value={activeObject.content} onChange={(e) => this.updateElement(activeObjectIndex, { content: e.target.value })}/>
|
|
@@ -529,7 +682,7 @@ export default class Edit extends React.PureComponent {
|
|
|
unCheckedChildren="关"
|
|
|
/>
|
|
|
</Form.Item>
|
|
|
- <Form.Item label="相对位置" style={{ flex: 1 }}>
|
|
|
+ <Form.Item label="浮动位置" style={{ flex: 1 }}>
|
|
|
<Switch
|
|
|
checked={activeObject.relative}
|
|
|
onChange={(checked) => this.updateElement(activeObjectIndex, { relative: checked })}
|
|
@@ -551,9 +704,15 @@ export default class Edit extends React.PureComponent {
|
|
|
}
|
|
|
|
|
|
{
|
|
|
- activeObject.type === 'pic' && (
|
|
|
+ (activeObject.type === 'pic'||activeObject.type === 'mat') && (
|
|
|
<div className={styles.box}>
|
|
|
- <h2>图片</h2>
|
|
|
+ <h2>
|
|
|
+ <span>{activeObject.type === 'pic' ? "图片" : "素材"}</span>
|
|
|
+ <span style={{float:'right',fontSize:14}}>
|
|
|
+ <span style={{marginRight:5}}>设置为母版</span>
|
|
|
+ <Switch checked={activeObject.isTemplate||false} onChange={(checked) => this.updateElement(activeObjectIndex, { isTemplate: checked })}/>
|
|
|
+ </span>
|
|
|
+ </h2>
|
|
|
<Form layout="vertical">
|
|
|
<Form.Item label="路径">
|
|
|
<Input value={activeObject.content} onChange={(e) => this.updateElement(activeObjectIndex, { content: e.target.value })}/>
|