forked from Gitlink/forgeplus-react
工单部分相关的都改成quill编辑器
This commit is contained in:
parent
4875f2c944
commit
637ce0fc9a
|
@ -126,21 +126,10 @@ export function initAxiosInterceptors(props) {
|
|||
// https://github.com/axios/axios/issues/1497
|
||||
|
||||
// TODO 读取到package.json中的配置?
|
||||
var proxy = "http://localhost:3000"
|
||||
// proxy = "http://testbdweb.trustie.net"
|
||||
// proxy = "http://testbdweb.educoder.net"
|
||||
// proxy = "https://testeduplus2.educoder.net"
|
||||
//proxy="http://47.96.87.25:48080"
|
||||
// proxy="https://pre-newweb.educoder.net"
|
||||
// proxy="https://test-newweb.educoder.net"
|
||||
// proxy="https://test-jupyterweb.educoder.net"
|
||||
// proxy="https://test-newweb.educoder.net"
|
||||
// proxy="https://test-jupyterweb.educoder.net"
|
||||
//proxy="http://192.168.2.63:3001"
|
||||
|
||||
|
||||
var //proxy = "http://localhost:3000"
|
||||
// proxy="http://123.59.135.93:56666"
|
||||
proxy="http://localhost:3000"
|
||||
proxy="http://123.59.135.93:56666"
|
||||
// proxy="http://localhost:3000"
|
||||
|
||||
// 在这里使用requestMap控制,避免用户通过双击等操作发出重复的请求;
|
||||
// 如果需要支持重复的请求,考虑config里面自定义一个allowRepeat参考来控制
|
||||
|
@ -236,7 +225,7 @@ export function initAxiosInterceptors(props) {
|
|||
// let timestamp=railsgettimes(proxy);
|
||||
// console.log(timestamp)
|
||||
// `https://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp`
|
||||
railsgettimes( `${proxy}/api/main/first_stamp.json`);
|
||||
// railsgettimes( `${proxy}/api/main/first_stamp.json`);
|
||||
let newopens=md5(opens+timestamp)
|
||||
config.url = `${proxy}${url}`;
|
||||
if (config.url.indexOf('?') == -1) {
|
||||
|
@ -248,7 +237,7 @@ export function initAxiosInterceptors(props) {
|
|||
// 加api前缀
|
||||
// railsgettimes(`http://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp`);
|
||||
|
||||
railsgettimes( `/api/main/first_stamp.json`);
|
||||
// railsgettimes( `/api/main/first_stamp.json`);
|
||||
let newopens=md5(opens+timestamp)
|
||||
config.url = url;
|
||||
if (config.url.indexOf('?') == -1) {
|
||||
|
|
|
@ -106,31 +106,31 @@ export function getmyUrl(geturl) {
|
|||
}
|
||||
|
||||
export function getUploadActionUrl(path, goTest) {
|
||||
Railsgettimes()
|
||||
// Railsgettimes()
|
||||
let anewopens=md5(newopens+newtimestamp);
|
||||
return `${getUrl()}/api/attachments.json${isDev ? `?debug=${window._debugType || 'admin'}&randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`}`;
|
||||
}
|
||||
|
||||
export function getUploadActionUrltwo(id) {
|
||||
Railsgettimes()
|
||||
// Railsgettimes()
|
||||
let anewopens=md5(newopens+newtimestamp);
|
||||
return `${getUrlmys()}/api/shixuns/${id}/upload_data_sets.json${isDev ? `?debug=${window._debugType || 'admin'}&randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`}`
|
||||
}
|
||||
|
||||
export function getUploadActionUrlthree() {
|
||||
Railsgettimes()
|
||||
// Railsgettimes()
|
||||
let anewopens=md5(newopens+newtimestamp);
|
||||
return `${getUrlmys()}/api/jupyters/import_with_tpm.json${isDev ? `?debug=${window._debugType || 'admin'}&randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`}`
|
||||
}
|
||||
|
||||
export function getUploadActionUrlOfAuth(id) {
|
||||
Railsgettimes()
|
||||
// Railsgettimes()
|
||||
let anewopens=md5(newopens+newtimestamp);
|
||||
return `${getUrl()}/api/users/accounts/${id}/auth_attachment.json${isDev ? `?debug=${window._debugType || 'admin'}&randomcode=${newtimestamp}&client_key=${anewopens}` : `?randomcode=${newtimestamp}&client_key=${anewopens}`}`
|
||||
}
|
||||
|
||||
export function getRandomNumber(type) {
|
||||
Railsgettimes()
|
||||
// Railsgettimes()
|
||||
let anewopens=md5(newopens+newtimestamp);
|
||||
return type===true?`randomcode=${newtimestamp}&client_key=${anewopens}`:`?randomcode=${newtimestamp}&client_key=${anewopens}`
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ export function getTaskUrlById(id) {
|
|||
}
|
||||
|
||||
export function getRandomcode(url) {
|
||||
Railsgettimes()
|
||||
// Railsgettimes()
|
||||
let anewopens=md5(newopens+newtimestamp);
|
||||
|
||||
if (url.indexOf('?') == -1) {
|
||||
|
|
|
@ -5,13 +5,20 @@ import axios from 'axios';
|
|||
import Nav from './Nav';
|
||||
import UploadComponent from '../Upload/Index';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import {Modal, Col, Form, Input, Tooltip, Popconfirm, Pagination , Spin} from 'antd'
|
||||
import NoneData from '../../modules/courses/coursesPublic/NoneData';
|
||||
import Attachments from '../Upload/attachment'
|
||||
import {Modal , Form, Input, Tooltip, Popconfirm, Pagination , Spin} from 'antd'
|
||||
import Attachments from '../Upload/attachment';
|
||||
import QuillForEditor from '../quillForEditor';
|
||||
import { QuillDeltaToHtmlConverter } from 'quill-delta-to-html'
|
||||
|
||||
|
||||
const TextArea = Input.TextArea;
|
||||
|
||||
const options = [
|
||||
['bold', 'italic', 'underline'],
|
||||
[{header: [1,2,3,false]}],
|
||||
['blockquote', 'code-block'],
|
||||
['link', 'image'],
|
||||
['formula']
|
||||
];
|
||||
|
||||
class Detail extends Component{
|
||||
constructor(props){
|
||||
|
@ -32,7 +39,9 @@ class Detail extends Component{
|
|||
page:1,
|
||||
search_count:undefined,
|
||||
isSpin:false,
|
||||
showFiles: true
|
||||
showFiles: true,
|
||||
quillValue:'',
|
||||
quillFlag:false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,12 +83,26 @@ class Detail extends Component{
|
|||
|
||||
//添加评论
|
||||
addjournals=()=>{
|
||||
const { quillValue } = this.state;
|
||||
if(!quillValue){
|
||||
this.setState({
|
||||
quillFlag:true
|
||||
})
|
||||
return;
|
||||
}
|
||||
let _html = '';
|
||||
try {
|
||||
_html = new QuillDeltaToHtmlConverter(quillValue.ops, {}).convert();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
this.props.form.validateFieldsAndScroll((err, values) => {
|
||||
if(!err){
|
||||
const { data, page, limit, fileList } = this.state;
|
||||
const url = `/issues/${data.id}/journals.json`;
|
||||
axios.post(url,{
|
||||
...values,
|
||||
content:_html,
|
||||
issue_id:data.id,
|
||||
attachment_ids:fileList
|
||||
}).then(result=>{
|
||||
|
@ -88,11 +111,12 @@ class Detail extends Component{
|
|||
content: ""
|
||||
});
|
||||
this.setState({
|
||||
showFiles: false
|
||||
showFiles: false,
|
||||
quillValue:'',
|
||||
quillFlag:false
|
||||
})
|
||||
this.getjournalslist(page, limit);
|
||||
this.props.showNotification("评论成功!");
|
||||
// this.UploadFunc(undefined)
|
||||
}
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
|
@ -215,7 +239,7 @@ class Detail extends Component{
|
|||
}
|
||||
|
||||
renderJournalList=(list)=>{
|
||||
console.log(list);
|
||||
// console.log(list);
|
||||
if(list && list.length >0){
|
||||
return(
|
||||
list.map((item,key)=>{
|
||||
|
@ -280,10 +304,18 @@ class Detail extends Component{
|
|||
showFiles:flag
|
||||
})
|
||||
}
|
||||
onContentChange=(value)=>{
|
||||
if(value){
|
||||
this.setState({
|
||||
quillValue:value,
|
||||
quillFlag:false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
const { projectsId,orderId} = this.props.match.params;
|
||||
const { data,journalsdata, page, limit, search_count, isSpin, isedit, showFiles } = this.state;
|
||||
const { data,journalsdata, page, limit, search_count, isSpin, isedit, showFiles , quillValue , quillFlag } = this.state;
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
const { current_user } = this.props;
|
||||
const Paginations = (
|
||||
|
@ -325,7 +357,10 @@ class Detail extends Component{
|
|||
<div style={{display: (isedit && isedit === item.id) ? "none" : "block"}} >
|
||||
{
|
||||
item.content ?
|
||||
<div>{item.content}</div>
|
||||
<QuillForEditor
|
||||
readOnly={true}
|
||||
value={item.content}
|
||||
/>
|
||||
:
|
||||
<div>
|
||||
{this.renderJournalList(item.journal_details)}
|
||||
|
@ -370,6 +405,8 @@ class Detail extends Component{
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return(
|
||||
<div className="main">
|
||||
<div className="topWrapper">
|
||||
|
@ -388,7 +425,7 @@ class Detail extends Component{
|
|||
<span className="font-20" > { data && data.subject }</span>
|
||||
|
||||
</p>
|
||||
<p className="mt10 color-grey-c">
|
||||
<p className="mt15 color-grey-c">
|
||||
<span className={data&&data.issue_status==="关闭"?"closedetail":"opendetail"}>{data&&data.issue_status==="关闭"?"关闭中":"开启中"} </span>
|
||||
<span className="ml10 lineH32">
|
||||
由 { data && data.author_name} 于 { data && data.created_at }创建{ data && data.journals_count && data.journals_count > 0 ?` · ${data.journals_count} 条评论`:""}
|
||||
|
@ -411,7 +448,10 @@ class Detail extends Component{
|
|||
<Link to={``}><img className="user_img" src={getImageUrl(`images/${data && data.author_picture}`)} alt=""/></Link>
|
||||
<div className="detail_context">
|
||||
<div className="detail_p">
|
||||
{ data && data.description }
|
||||
<QuillForEditor
|
||||
readOnly={true}
|
||||
value={ data && data.description}
|
||||
/>
|
||||
</div>
|
||||
{
|
||||
data && data.attachments && data.attachments.length > 0 ?
|
||||
|
@ -435,15 +475,26 @@ class Detail extends Component{
|
|||
<div className="df">
|
||||
<Link to={``}><img className="user_img" src={getImageUrl(`images/${current_user && current_user.image_url}`)} alt=""/></Link>
|
||||
<div className="new_context">
|
||||
<Form.Item>
|
||||
{getFieldDecorator('content', {
|
||||
rules: [{
|
||||
required: true, message: '请输入内容'
|
||||
}],
|
||||
})(
|
||||
<TextArea placeholder="添加评论..." style={{height: "200px"}}/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<div className="quillContent">
|
||||
<QuillForEditor
|
||||
imgAttrs={{ width: '60px', height: '30px' }}
|
||||
wrapStyle={{
|
||||
height: '220px',
|
||||
opacity:1,
|
||||
}}
|
||||
autoFocus={true}
|
||||
style={{ height: '150px' }}
|
||||
placeholder="添加评论..."
|
||||
options={options}
|
||||
value={quillValue}
|
||||
onContentChange={this.onContentChange}
|
||||
// showUploadImage={handleShowImage}
|
||||
// onContentChange={handleContentChange}
|
||||
/>
|
||||
<p className="quillFlag">
|
||||
{ quillFlag && <span className="">请输入评论内容</span>}
|
||||
</p>
|
||||
</div>
|
||||
<UploadComponent load={this.UploadFunc} isComplete={showFiles} changeIsComplete={this.changeIsComplete}></UploadComponent>
|
||||
<p className="clearfix mt15">
|
||||
<a className="topWrapper_btn fr" type="submit" onClick={this.addjournals}>评论</a>
|
||||
|
@ -458,7 +509,7 @@ class Detail extends Component{
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="list-left DetailRight mt10">
|
||||
<div className="list-left DetailRight mt10" style={{backgroundColor:"#fff"}}>
|
||||
<p>
|
||||
<span className="span_title">分支</span>
|
||||
<span>{
|
||||
|
|
|
@ -1,17 +1,25 @@
|
|||
import React , { Component } from "react";
|
||||
import { Form , Input , Select } from 'antd';
|
||||
import {Link} from 'react-router-dom';
|
||||
|
||||
import { getImageUrl } from 'educoder';
|
||||
|
||||
import Nav from './Nav';
|
||||
import UploadComponent from '../Upload/Index';
|
||||
import QuillForEditor from '../quillForEditor';
|
||||
import { QuillDeltaToHtmlConverter } from 'quill-delta-to-html'
|
||||
|
||||
import './order.css';
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
const Option = Select.Option;
|
||||
const TextArea = Input.TextArea;
|
||||
const options = [
|
||||
['bold', 'italic', 'underline'],
|
||||
[{header: [1,2,3,false]}],
|
||||
['blockquote', 'code-block'],
|
||||
['link', 'image'],
|
||||
['formula']
|
||||
];
|
||||
class New extends Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
@ -27,7 +35,8 @@ class New extends Component{
|
|||
done_ratio:"0%",
|
||||
issue_chosen:undefined,
|
||||
branches:undefined,
|
||||
fileList:undefined
|
||||
fileList:undefined,
|
||||
description:undefined
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,9 +103,16 @@ class New extends Component{
|
|||
if(values.issue_tag_ids.length > 0){
|
||||
values.issue_tag_ids = [values.issue_tag_ids]
|
||||
}
|
||||
|
||||
const { description } = this.state;
|
||||
let _html = '';
|
||||
try {
|
||||
_html = new QuillDeltaToHtmlConverter(description.ops, {}).convert();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
axios.post(url,{
|
||||
...values,
|
||||
description:_html,
|
||||
attachment_ids:fileList
|
||||
}).then(result=>{
|
||||
if(result){
|
||||
|
@ -118,10 +134,16 @@ class New extends Component{
|
|||
})
|
||||
}
|
||||
|
||||
onContentChange=(value)=>{
|
||||
this.setState({
|
||||
description:value
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
const { current_user } = this.props;
|
||||
const { issue_tag_ids , fixed_version_id , branch_name , status_id , tracker_id , issue_type ,assigned_to_id , priority_id , done_ratio,
|
||||
const { issue_tag_ids , fixed_version_id , branch_name , status_id , tracker_id , description ,assigned_to_id , priority_id , done_ratio,
|
||||
issue_chosen , branches } = this.state;
|
||||
|
||||
return(
|
||||
|
@ -132,7 +154,7 @@ class New extends Component{
|
|||
<Form>
|
||||
<div className="f-wrap-between mt20" style={{alignItems:"flex-start"}}>
|
||||
<div className="list-right df">
|
||||
<Link to={``}><img class="user_img" src={getImageUrl(`images/${current_user && current_user.image_url}`)} alt=""/></Link>
|
||||
<img class="user_img" src={getImageUrl(`images/${current_user && current_user.image_url}`)} alt=""/>
|
||||
<div className="new_context">
|
||||
<Form.Item>
|
||||
{getFieldDecorator('subject', {
|
||||
|
@ -143,20 +165,35 @@ class New extends Component{
|
|||
<Input placeholder="标题"/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<div className="quillContent" style={{marginBottom:"20px"}}>
|
||||
<QuillForEditor
|
||||
value = {description}
|
||||
imgAttrs={{ width: '60px', height: '30px' }}
|
||||
wrapStyle={{
|
||||
height: '220px',
|
||||
opacity:1,
|
||||
}}
|
||||
// autoFocus={true}
|
||||
style={{ height: '170px' }}
|
||||
placeholder="请输入工单的描述..."
|
||||
options={options}
|
||||
onContentChange={this.onContentChange}
|
||||
/>
|
||||
</div>
|
||||
{/* <Form.Item>
|
||||
{getFieldDecorator('description', {
|
||||
rules: [],
|
||||
})(
|
||||
<TextArea placeholder="请输入工单的描述..." style={{height:"300px"}}/>
|
||||
)}
|
||||
</Form.Item>
|
||||
</Form.Item> */}
|
||||
<UploadComponent load={this.UploadFunc} showNotification={this.props.showNotification} isComplete={true}></UploadComponent>
|
||||
<p className="clearfix mt15">
|
||||
<a className="topWrapper_btn fr" type="submit" onClick={this.handleSubmit}>创建Issue</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="list-left" style={{paddingRight:"0px",paddingLeft:"15px",paddingTop:"10px"}}>
|
||||
<div className="list-left" style={{paddingRight:"0px",paddingLeft:"0px",width:"25%",backgroundColor:"#fff"}}>
|
||||
<div className="list-l-panel">
|
||||
<Form.Item>
|
||||
{getFieldDecorator('branch_name', {
|
||||
|
|
|
@ -5,15 +5,22 @@ import axios from 'axios';
|
|||
import Nav from './Nav';
|
||||
import UploadComponent from '../Upload/Index';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import{ Modal,Col,Form,Input,Tooltip,Select } from 'antd'
|
||||
import NoneData from '../../modules/courses/coursesPublic/NoneData';
|
||||
import{ Modal , Form , Input , Select } from 'antd'
|
||||
|
||||
import Attachments from '../Upload/attachment'
|
||||
import Attachments from '../Upload/attachment';
|
||||
import QuillForEditor from '../quillForEditor';
|
||||
import { QuillDeltaToHtmlConverter } from 'quill-delta-to-html'
|
||||
|
||||
const TextArea = Input.TextArea;
|
||||
const Option = Select.Option;
|
||||
|
||||
|
||||
const options = [
|
||||
['bold', 'italic', 'underline'],
|
||||
[{header: [1,2,3,false]}],
|
||||
['blockquote', 'code-block'],
|
||||
['link', 'image'],
|
||||
['formula']
|
||||
];
|
||||
class UpdateDetail extends Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
@ -100,6 +107,12 @@ class UpdateDetail extends Component{
|
|||
});
|
||||
};
|
||||
|
||||
onContentChange=(value)=>{
|
||||
this.setState({
|
||||
textcount:value
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
changmodelname=(e)=>{
|
||||
this.setState({
|
||||
|
@ -145,11 +158,18 @@ class UpdateDetail extends Component{
|
|||
if(values.assigned_to_id===0){
|
||||
values.assigned_to_id = ""
|
||||
}
|
||||
const { textcount } = this.state;
|
||||
let _html = '';
|
||||
try {
|
||||
_html = new QuillDeltaToHtmlConverter(textcount.ops, {}).convert();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
axios.put(url,{
|
||||
project_id:projectsId,
|
||||
subject:subject,
|
||||
id: orderId,
|
||||
description:this.state.textcount,
|
||||
description:_html,
|
||||
attachment_ids:fileList,
|
||||
...values
|
||||
}).then(result=>{
|
||||
|
@ -180,7 +200,7 @@ class UpdateDetail extends Component{
|
|||
<Form>
|
||||
<div className="f-wrap-between mt20" style={{alignItems:"flex-start"}}>
|
||||
<div className="list-right df" >
|
||||
<Link to={``}><img class="user_img" src={getImageUrl(`images/${current_user && current_user.image_url}`)} alt=""/></Link>
|
||||
<img class="user_img" src={getImageUrl(`images/${current_user && current_user.image_url}`)} alt=""/>
|
||||
<div className="new_context">
|
||||
<Form.Item>
|
||||
{getFieldDecorator('subject', {
|
||||
|
@ -192,14 +212,21 @@ class UpdateDetail extends Component{
|
|||
<Input placeholder="标题" onChange={this.changmodelname}/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
{getFieldDecorator('description', {
|
||||
rules: [],
|
||||
initialValue: textcount
|
||||
})(
|
||||
<TextArea placeholder="请输入工单的描述..." style={{height:"300px"}} onChange={this.changmodelcount}/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<div className="quillContent" style={{marginBottom:"20px"}}>
|
||||
<QuillForEditor
|
||||
value = {textcount}
|
||||
imgAttrs={{ width: '60px', height: '30px' }}
|
||||
wrapStyle={{
|
||||
height: '220px',
|
||||
opacity:1,
|
||||
}}
|
||||
// autoFocus={true}
|
||||
style={{ height: '170px' }}
|
||||
placeholder="请输入工单的描述..."
|
||||
options={options}
|
||||
onContentChange={this.onContentChange}
|
||||
/>
|
||||
</div>
|
||||
<UploadComponent load={this.UploadFunc} showNotification={this.props.showNotification} isComplete={true}></UploadComponent>
|
||||
{
|
||||
get_attachments ?
|
||||
|
@ -213,7 +240,7 @@ class UpdateDetail extends Component{
|
|||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="list-left" style={{paddingRight:"0px",paddingLeft:"15px",paddingTop:"10px"}}>
|
||||
<div className="list-left" style={{paddingRight:"0px",paddingLeft:"0px",width:"25%",backgroundColor:"#fff"}}>
|
||||
<div className="list-l-panel">
|
||||
<Form.Item
|
||||
label="分支"
|
||||
|
|
|
@ -6,6 +6,18 @@
|
|||
border-bottom: 1px solid #EEEEEE;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.quillContent{
|
||||
position: relative;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.quillFlag{
|
||||
position: absolute;
|
||||
bottom:0px;
|
||||
left:6px;
|
||||
height: 20px;
|
||||
line-height: 18px;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.topmilepost{
|
||||
padding: 20px 0;
|
||||
|
@ -354,9 +366,6 @@
|
|||
width: 80%;
|
||||
padding-left: 80px;
|
||||
}
|
||||
.detail_ptitlecount{
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.tagList > div:last-child{
|
||||
border-bottom: none;
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
|
||||
.newMain{
|
||||
background-color: #fff;
|
||||
}
|
||||
.main{
|
||||
width: 1200px;
|
||||
margin:20px auto;
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* @Description: 填空
|
||||
* @Author: tangjiang
|
||||
* @Github:
|
||||
* @Date: 2020-01-06 09:02:29
|
||||
* @LastEditors : tangjiang
|
||||
* @LastEditTime : 2020-02-05 10:44:01
|
||||
*/
|
||||
import Quill from 'quill';
|
||||
let Inline = Quill.import('blots/inline');
|
||||
// const BlockEmbed = Quill.import('blots/embed');
|
||||
class FillBlot extends Inline {
|
||||
static create (value) {
|
||||
const node = super.cerate(value);
|
||||
// node.classList.add('icon icon-bianji2');
|
||||
// node.setAttribute('data-fill', 'fill');
|
||||
console.log('编辑器值===》》》》》', value);
|
||||
node.setAttribute('data_index', value.data_index);
|
||||
node.nodeValue = value.text;
|
||||
return node;
|
||||
}
|
||||
|
||||
static value (node) {
|
||||
return {
|
||||
// dataSet: node.getAttribute('data-fill'),
|
||||
data_index: node.getAttribute('data_index')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FillBlot.blotName = "fill";
|
||||
FillBlot.tagName = "span";
|
||||
|
||||
export default FillBlot;
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* @Description: 重写图片
|
||||
* @Author: tangjiang
|
||||
* @Github:
|
||||
* @Date: 2019-12-16 15:50:45
|
||||
* @LastEditors : tangjiang
|
||||
* @LastEditTime : 2019-12-31 13:59:02
|
||||
*/
|
||||
import Quill from "quill";
|
||||
|
||||
const BlockEmbed = Quill.import('blots/block/embed');
|
||||
|
||||
export default class ImageBlot extends BlockEmbed {
|
||||
|
||||
static create(value) {
|
||||
|
||||
const node = super.create();
|
||||
node.setAttribute('alt', value.alt);
|
||||
node.setAttribute('src', value.url);
|
||||
// console.log('~~~~~~~~~~~', node, value);
|
||||
node.addEventListener('click', function () {
|
||||
value.onclick(value.url);
|
||||
}, false);
|
||||
if (value.width) {
|
||||
node.setAttribute('width', value.width);
|
||||
}
|
||||
if (value.height) {
|
||||
node.setAttribute('height', value.height);
|
||||
}
|
||||
|
||||
if (value.id) {
|
||||
node.setAttribute('id', value.id);
|
||||
}
|
||||
// 宽度和高度都不存在时,
|
||||
if (!value.width && !value.height) {
|
||||
// node.setAttribute('display', 'block');
|
||||
node.setAttribute('width', '100%');
|
||||
}
|
||||
|
||||
// node.setAttribute('style', { cursor: 'pointer' });
|
||||
|
||||
// if (node.onclick) {
|
||||
// console.log('image 有图片点击事件======》》》》》》');
|
||||
// // node.setAttribute('onclick', node.onCLick);
|
||||
// }
|
||||
// 给图片添加点击事件
|
||||
// node.onclick = () => {
|
||||
// value.onClick && value.onClick(value.url);
|
||||
// }
|
||||
return node;
|
||||
}
|
||||
|
||||
// 获取节点值
|
||||
static value (node) {
|
||||
|
||||
return {
|
||||
alt: node.getAttribute('alt'),
|
||||
url: node.getAttribute('src'),
|
||||
onclick: node.onclick,
|
||||
width: node.width,
|
||||
height: node.height,
|
||||
display: node.getAttribute('display'),
|
||||
id: node.id,
|
||||
// style: node.style
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
ImageBlot.blotName = 'image';
|
||||
ImageBlot.tagName = 'img';
|
|
@ -0,0 +1,95 @@
|
|||
<!--
|
||||
* @Description:
|
||||
* @Author: tangjiang
|
||||
* @Github:
|
||||
* @Date: 2020-01-06 16:20:03
|
||||
* @LastEditors : tangjiang
|
||||
* @LastEditTime : 2020-01-09 09:45:29
|
||||
-->
|
||||
## QuillForEditor 使用 [https://quilljs.com/]
|
||||
|
||||
### 导入
|
||||
|
||||
- 目录 src/common/quillForEditor (默认加载当前文件夹下的 index.js 文件)
|
||||
|
||||
### 参数
|
||||
|
||||
| 字段 | 描述 |
|
||||
| ----- | ----- |
|
||||
| placeholder | 提示信息 |
|
||||
| readOnly | 只读(只读取模式时,没有 工具栏且内容不可编辑,通常用于展示quill内容) |
|
||||
| autoFocus | 自动获得焦点 |
|
||||
| options | 配置参数, 指定工具栏内容 |
|
||||
| value | 文本编辑器内容 |
|
||||
| imgAttrs | 指定上传图片的尺寸 { width: 'xxpx}, height: 'xxpx'|
|
||||
| style | 指定quill容器样式 |
|
||||
| wrapStyle | 指定包裹quill容器的样式|
|
||||
| onContentChange | 当编辑器内容变化时调用此回调函数(注: 此时返回的内容为对象,提交到后台时需要格式成 JSON 字符串: JSON.stringify(xx)) |
|
||||
| showUploadImage | 点击放大上传成功后的图片, 返回上传成功后的图片 url, (评论时点击图片这么大)|
|
||||
|
||||
|
||||
|
||||
### 添加工具栏
|
||||
|
||||
- 默认所有的
|
||||
|
||||
```
|
||||
const options = [
|
||||
'bold', // 加粗
|
||||
'italic', // 斜体
|
||||
'underline', // 下划线
|
||||
{size: ['12px', '14px', '16px', '18px', '20px']}, // 字体大小
|
||||
{align: []}, // 对齐方式
|
||||
{list: 'ordered'}, // 有序列表
|
||||
{list: 'bullet'}, // 无序列表
|
||||
{script: 'sub'}, // 下标 x2
|
||||
{script: 'super'}, // 上标 平方 (x2)
|
||||
{ 'color': [] }, // 字体颜色
|
||||
{ 'background': [] }, // 背景色
|
||||
{header: [1,2,3,4,5,false]}, // H1,H2 ...
|
||||
'blockquote', // 文件左边加一个边框样式
|
||||
'code-block', // 块内容
|
||||
'link', // 链接
|
||||
'image', // 图片
|
||||
'video', // 视频
|
||||
'formula', // 数学公式
|
||||
'clean' // 清除
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
### 使用
|
||||
|
||||
````
|
||||
编辑模式是放不大图片的
|
||||
import QuillForEditor from 'xxx';
|
||||
|
||||
// 指定需要显示的工具栏信息, 不指定加载全部
|
||||
const options = [
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
* @description 获取编辑器返回的内容
|
||||
* @params [Object] value 编辑器内容
|
||||
*/
|
||||
const handleCtxChange = (value) => {
|
||||
// 编辑器内容非空判断
|
||||
const _text = quill.getText();
|
||||
const reg = /^[\s\S]*.*[^\s][\s\S]*$/;
|
||||
if (!reg.test(_text)) {
|
||||
// 处理编辑器内容为空
|
||||
} else {
|
||||
// 提交到后台的内容需要处理一下;
|
||||
value = JSON.stringify(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
<QuillForEditor
|
||||
options={options}
|
||||
onContentChange={handleCtxChange}
|
||||
>
|
||||
</QuillForEditor>
|
||||
````
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
function deepEqual (prev, current) {
|
||||
if (prev === current) { // 基本类型比较,值,类型都相同 或者同为 null or undefined
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((!prev && current)
|
||||
|| (prev && !current)
|
||||
|| (!prev && !current)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Array.isArray(prev)) {
|
||||
if (!Array.isArray(current)) return false;
|
||||
if (prev.length !== current.length) return false;
|
||||
|
||||
for (let i = 0; i < prev.length; i++) {
|
||||
if (!deepEqual(current[i], prev[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeof current === 'object') {
|
||||
if (typeof prev !== 'object') return false;
|
||||
const prevKeys = Object.keys(prev);
|
||||
const curKeys = Object.keys(current);
|
||||
|
||||
if (prevKeys.length !== curKeys.length) return false;
|
||||
|
||||
prevKeys.sort();
|
||||
curKeys.sort();
|
||||
|
||||
for (let i = 0; i < prevKeys.length; i++) {
|
||||
if (prevKeys[i] !== curKeys[i]) return false;
|
||||
const key = prevKeys[i];
|
||||
if (!deepEqual(prev[key], current[key])) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export default deepEqual;
|
|
@ -0,0 +1,280 @@
|
|||
/*
|
||||
* @Description: quill 编辑器
|
||||
* @Author: tangjiang
|
||||
* @Github:
|
||||
* @Date: 2019-12-18 08:49:30
|
||||
* @LastEditors : tangjiang
|
||||
* @LastEditTime : 2020-02-05 11:23:03
|
||||
*/
|
||||
import './index.scss';
|
||||
import 'quill/dist/quill.core.css'; // 核心样式
|
||||
import 'quill/dist/quill.snow.css'; // 有工具栏
|
||||
import 'quill/dist/quill.bubble.css'; // 无工具栏
|
||||
import 'katex/dist/katex.min.css'; // katex 表达式样式
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import Quill from 'quill';
|
||||
import katex from 'katex';
|
||||
import deepEqual from './deepEqual.js'
|
||||
import { fetchUploadImage } from '../../services/ojService.js';
|
||||
import { getImageUrl } from 'educoder'
|
||||
import ImageBlot from './ImageBlot';
|
||||
import FillBlot from './FillBlot';
|
||||
const Size = Quill.import('attributors/style/size');
|
||||
const Font = Quill.import('formats/font');
|
||||
// const Color = Quill.import('attributes/style/color');
|
||||
Size.whitelist = ['12px', '14px', '16px', '18px', '20px', false];
|
||||
Font.whitelist = ['SimSun', 'SimHei','Microsoft-YaHei','KaiTi','FangSong','Arial','Times-New-Roman','sans-serif'];
|
||||
|
||||
window.Quill = Quill;
|
||||
window.katex = katex;
|
||||
Quill.register(ImageBlot);
|
||||
Quill.register(Size);
|
||||
Quill.register(Font, true);
|
||||
// Quill.register({'modules/toolbar': Toolbar});
|
||||
Quill.register({
|
||||
'formats/fill': FillBlot
|
||||
});
|
||||
// Quill.register(Color);
|
||||
|
||||
|
||||
function QuillForEditor ({
|
||||
placeholder,
|
||||
readOnly,
|
||||
autoFocus = false,
|
||||
options,
|
||||
value,
|
||||
imgAttrs = {}, // 指定图片的宽高
|
||||
style = {},
|
||||
wrapStyle = {},
|
||||
showUploadImage,
|
||||
onContentChange,
|
||||
addFill, // 点击填空成功的回调
|
||||
deleteFill // 删除填空,返回删除的下标
|
||||
// getQuillContent
|
||||
}) {
|
||||
// toolbar 默认值
|
||||
const defaultConfig = [
|
||||
'bold', 'italic', 'underline',
|
||||
{size: ['12px', '14px', '16px', '18px', '20px']},
|
||||
{align: []}, {list: 'ordered'}, {list: 'bullet'}, // 列表
|
||||
{script: 'sub'}, {script: 'super'},
|
||||
{ 'color': [] }, { 'background': [] },
|
||||
{header: [1,2,3,4,5,false]},
|
||||
'blockquote', 'code-block',
|
||||
'link', 'image', 'video',
|
||||
'formula',
|
||||
'clean'
|
||||
];
|
||||
|
||||
const editorRef = useRef(null);
|
||||
// quill 实例
|
||||
const [quill, setQuill] = useState(null);
|
||||
const [selection, setSelection] = useState(null);
|
||||
const [fillCount, setFillCount] = useState(0);
|
||||
const [quillCtx, setQuillCtx] = useState({});
|
||||
|
||||
// 文本内容变化时
|
||||
const handleOnChange = content => {
|
||||
// getQuillContent && getQuillContent(quill);
|
||||
onContentChange && onContentChange(content, quill);
|
||||
};
|
||||
|
||||
const renderOptions = options || defaultConfig;
|
||||
|
||||
const bindings = {
|
||||
tab: {
|
||||
key: 9,
|
||||
handler: function () {
|
||||
console.log('调用了tab=====>>>>');
|
||||
}
|
||||
},
|
||||
backspace: {
|
||||
key: 'Backspace',
|
||||
/**
|
||||
* @param {*} range
|
||||
* { index, // 删除元素的位置
|
||||
* length // 删除元素的个数, 当删除一个时, length=0, 其它等于删除的元素的个数
|
||||
* }
|
||||
* @param {*} context 上下文
|
||||
*/
|
||||
handler: function (range, context) {
|
||||
/**
|
||||
* index: 删除元素的位置
|
||||
* length: 删除元素的个数
|
||||
*/
|
||||
const {index, length} = range;
|
||||
const _start = length === 0 ? index - 1 : index;
|
||||
const _length = length || 1;
|
||||
let delCtx = this.quill.getText(_start, _length); // 删除的元素
|
||||
// aa
|
||||
const reg = /▁/g;
|
||||
const delArrs = delCtx.match(reg);
|
||||
if (delArrs) {
|
||||
const r = window.confirm('确定要删除吗?');
|
||||
if (r) {
|
||||
let leaveCtx; // 获取删除元素之前的内容
|
||||
if (length === 0) {
|
||||
leaveCtx = this.quill.getText(0, index - 1);
|
||||
} else {
|
||||
leaveCtx = this.quill.getText(0, index);
|
||||
}
|
||||
const leaveArrs = leaveCtx.match(reg);
|
||||
const leaveLen = (leaveArrs || []).length;
|
||||
let delIndexs = [];
|
||||
// 获取删除元素的下标
|
||||
delArrs.forEach((item, i) => {
|
||||
leaveLen === 0 ? delIndexs.push(i) : delIndexs.push(leaveLen + i);
|
||||
});
|
||||
deleteFill && deleteFill(delIndexs); // 调用删除回调, 返回删除的元素下标[]
|
||||
return true
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
// quill 配置信息
|
||||
const quillOption = {
|
||||
modules: {
|
||||
toolbar: renderOptions,
|
||||
keyboard: {
|
||||
bindings: bindings
|
||||
}
|
||||
// toolbar: {
|
||||
// container: renderOptions
|
||||
// }
|
||||
},
|
||||
readOnly,
|
||||
placeholder,
|
||||
theme: readOnly ? 'bubble' : 'snow',
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
const quillNode = document.createElement('div');
|
||||
editorRef.current.appendChild(quillNode);
|
||||
const _quill = new Quill(editorRef.current, quillOption);
|
||||
|
||||
setQuill(_quill);
|
||||
// 处理图片上传功能
|
||||
_quill.getModule('toolbar').addHandler('image', (e) => {
|
||||
const input = document.createElement('input');
|
||||
input.setAttribute('type', 'file');
|
||||
input.setAttribute('accept', 'image/*');
|
||||
input.click();
|
||||
|
||||
input.onchange = async (e) => {
|
||||
const file = input.files[0]; // 获取文件信息
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
const range = _quill.getSelection(true);
|
||||
let fileUrl = ''; // 保存上传成功后图片的url
|
||||
// 上传文件
|
||||
const result = await fetchUploadImage(formData);
|
||||
// 获取上传图片的url
|
||||
if (result.data && result.data.id) {
|
||||
fileUrl = getImageUrl(`api/attachments/${result.data.id}`);
|
||||
}
|
||||
// 根据id获取文件路径
|
||||
const { width, height } = imgAttrs;
|
||||
// console.log('上传图片的url:', fileUrl);
|
||||
if (fileUrl) {
|
||||
_quill.insertEmbed(range.index, 'image', {
|
||||
url: fileUrl,
|
||||
alt: '图片信息',
|
||||
onClick: showUploadImage,
|
||||
width,
|
||||
height
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
// 处理填空
|
||||
_quill.getModule('toolbar').addHandler('fill', (e) => {
|
||||
// alert(1111);
|
||||
setFillCount(fillCount + 1);
|
||||
const range = _quill.getSelection(true);
|
||||
_quill.insertText(range.index, '▁');
|
||||
addFill && addFill(); // 调用添加回调
|
||||
});
|
||||
}, []);
|
||||
|
||||
// 设置值
|
||||
useEffect(() => {
|
||||
if (!quill) return
|
||||
|
||||
const previous = quill.getContents()
|
||||
|
||||
if (value && value.hasOwnProperty('ops')) {
|
||||
// console.log(value.ops);
|
||||
const ops = value.ops || [];
|
||||
ops.forEach((item, i) => {
|
||||
if (item.insert['image']) {
|
||||
item.insert['image'] = Object.assign({}, item.insert['image'], {style: { cursor: 'pointer' }, onclick: (url) => showUploadImage(url)});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const current = value
|
||||
if (!deepEqual(previous, current)) {
|
||||
setSelection(quill.getSelection())
|
||||
if (typeof value === 'string' && value) {
|
||||
// debugger
|
||||
quill.clipboard.dangerouslyPasteHTML(value, 'api');
|
||||
if (autoFocus) {
|
||||
quill.focus();
|
||||
} else {
|
||||
quill.blur();
|
||||
}
|
||||
} else {
|
||||
quill.setContents(value)
|
||||
if (autoFocus) quill.focus();
|
||||
}
|
||||
}
|
||||
}, [quill, value, setQuill, autoFocus]);
|
||||
|
||||
// 清除选择区域
|
||||
useEffect(() => {
|
||||
if (quill && selection) {
|
||||
quill.setSelection(selection)
|
||||
setSelection(null)
|
||||
}
|
||||
}, [quill, selection, setSelection]);
|
||||
|
||||
// 设置placeholder值
|
||||
useEffect(() => {
|
||||
if (!quill || !quill.root) return;
|
||||
quill.root.dataset.placeholder = placeholder;
|
||||
}, [quill, placeholder]);
|
||||
|
||||
// 处理内容变化
|
||||
useEffect(() => {
|
||||
if (!quill) return;
|
||||
if (typeof handleOnChange !== 'function') return;
|
||||
let handler;
|
||||
quill.on(
|
||||
'text-change',
|
||||
(handler = (delta, oldDelta, source) => {
|
||||
const _ctx = quill.getContents();
|
||||
setQuillCtx(_ctx);
|
||||
handleOnChange(quill.getContents()); // getContents: 检索编辑器内容
|
||||
})
|
||||
);
|
||||
return () => {
|
||||
quill.off('text-change', handler);
|
||||
}
|
||||
}, [quill, handleOnChange]);
|
||||
|
||||
// 返回结果
|
||||
return (
|
||||
<div className='quill_editor_for_react_area' style={wrapStyle}>
|
||||
<div ref={editorRef} style={style}></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default QuillForEditor;
|
|
@ -0,0 +1,132 @@
|
|||
.quill_editor_for_react_area{
|
||||
// background: #fff;
|
||||
// margin: 0 15px;
|
||||
.ql-editing{
|
||||
left: 0 !important;
|
||||
}
|
||||
.ql-editor{
|
||||
img{
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="12px"]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="12px"]::before {
|
||||
content: '12px';
|
||||
font-size: 12px;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="14px"]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="14px"]::before {
|
||||
content: '14px';
|
||||
font-size: 14px;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="16px"]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="16px"]::before {
|
||||
content: '16px';
|
||||
font-size: 16px;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="18px"]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="18px"]::before {
|
||||
content: '18px';
|
||||
font-size: 18px;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="20px"]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="20px"]::before {
|
||||
content: '20px';
|
||||
font-size: 20px;
|
||||
}
|
||||
//默认的样式
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
|
||||
content: '14px';
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=SimSun]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=SimSun]::before {
|
||||
content: "宋体";
|
||||
font-family: "SimSun";
|
||||
}
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=SimHei]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=SimHei]::before {
|
||||
content: "黑体";
|
||||
font-family: "SimHei";
|
||||
}
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Microsoft-YaHei]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Microsoft-YaHei]::before {
|
||||
content: "微软雅黑";
|
||||
font-family: "Microsoft YaHei";
|
||||
}
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=KaiTi]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=KaiTi]::before {
|
||||
content: "楷体";
|
||||
font-family: "KaiTi";
|
||||
}
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=FangSong]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=FangSong]::before {
|
||||
content: "仿宋";
|
||||
font-family: "FangSong";
|
||||
}
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Arial]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Arial]::before {
|
||||
content: "Arial";
|
||||
font-family: "Arial";
|
||||
}
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=Times-New-Roman]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Times-New-Roman]::before {
|
||||
content: "Times New Roman";
|
||||
font-family: "Times New Roman";
|
||||
}
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=sans-serif]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=sans-serif]::before {
|
||||
content: "sans-serif";
|
||||
font-family: "sans-serif";
|
||||
}
|
||||
|
||||
.ql-font-SimSun {
|
||||
font-family: "SimSun";
|
||||
}
|
||||
.ql-font-SimHei {
|
||||
font-family: "SimHei";
|
||||
}
|
||||
.ql-font-Microsoft-YaHei {
|
||||
font-family: "Microsoft YaHei";
|
||||
}
|
||||
.ql-font-KaiTi {
|
||||
font-family: "KaiTi";
|
||||
}
|
||||
.ql-font-FangSong {
|
||||
font-family: "FangSong";
|
||||
}
|
||||
.ql-font-Arial {
|
||||
font-family: "Arial";
|
||||
}
|
||||
.ql-font-Times-New-Roman {
|
||||
font-family: "Times New Roman";
|
||||
}
|
||||
.ql-font-sans-serif {
|
||||
font-family: "sans-serif";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
|
||||
content: "微软雅黑";
|
||||
font-family: "Microsoft YaHei";
|
||||
}
|
||||
|
||||
// 填空图标
|
||||
.ql-snow .ql-fill{
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
color: #05101A;
|
||||
// font-size: 18px;
|
||||
vertical-align: top;
|
||||
&::before{
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: -1px;
|
||||
content: '\e709';
|
||||
font-family: 'iconfont';
|
||||
margin-left: -7px;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue