This commit is contained in:
caishi 2023-04-13 15:04:46 +08:00
parent 6a9bda3882
commit a0391abdd9
5 changed files with 104 additions and 64 deletions

View File

@ -4,7 +4,7 @@ import { Spin } from 'antd';
class Loading extends Component {
componentDidUpdate(prevProps, prevState) {
if (!prevProps.error && this.props.error) {
console.log(this.props.error)
// console.log(this.props.error)
}
}

View File

@ -1,15 +1,16 @@
import React, { useEffect, useRef, useMemo } from 'react'
import 'katex/dist/katex.min.css'
import React, { useEffect, useRef, useMemo , useState } from 'react'
import 'katex/dist/katex.min.css';
import marked, { getTocContent, cleanToc, getMathExpressions, resetMathExpressions } from '../common/marked';
import 'code-prettify';
import dompurify from 'dompurify';
import { getEmoji } from '../forge/Main/emoji';
import axios from 'axios';
import { renderToString } from 'katex'
const preRegex = /<pre[^>]*>/g;
const strRegexSub = /:([a-zA-Z_]+):/g;
// const quoteRegex = /[#]()/g;
const quoteRegex = /\[[#][0-9]{0,}\]\(\/\w{0,}\/\w{0,}\/issues\/[0-9]{0,}\)/g;
function _unescape(str) {
let div = document.createElement('div')
div.innerHTML = str
@ -22,8 +23,29 @@ export default ({
value = '',
className,
style = {},
url
url,
owner=undefined,
projectsId=undefined
}) => {
const [ issues , setIssues ] = useState([]);
useEffect(()=>{
if(owner&&projectsId){
getIssueList();
}
},[owner,projectsId])
function getIssueList(){
axios.get(`/v1/${owner}/${projectsId}/issues`,{params:{
only_name:true,sort_direction:"desc",sort_by:"issues.created_on"
}}).then(result=>{
if(result){
let data = result.data.issues;
setIssues(data);
}
})
}
let str = String(value);
const html = useMemo(() => {
let rs = marked(str);
@ -39,6 +61,26 @@ export default ({
rs = rs.replace(matchStr[i],getEmoji(matchStr[i]));
}
}
if(owner && projectsId && issues && issues.length>0){
let matchQuote = str.match(quoteRegex);
if(matchQuote && matchQuote.length>0){
let getIndexReg = /(?<=#)(.+?)(?=\])/g;
for(var x=0;x<matchQuote.length;x++){
let getIndex = matchQuote[x].match(getIndexReg);
if(getIndex && getIndex.length>0 && getIndex[0]){
let index = getIndex[0];
let filter = issues.filter(f=>f.project_issues_index.toString() === index);
if(filter && filter.length === 1){
let content = `#${index}:${filter[0].subject}`;
rs = rs.replace(`#${index}`,content);
}else{
let content = `<span>#${index}(已删除)</span>`;
rs = rs.replace(`<a href="`+`/${owner}/${projectsId}/issues/${index}`+`">#${index}</a>`,content);
}
}
}
}
}
rs = rs.replace(/(__special_katext_id_\d+__)/g, (_match, capture) => {
const { type, expression } = math_expressions[capture];
@ -47,7 +89,7 @@ export default ({
rs = rs.replace(/▁/g, "▁▁▁")
resetMathExpressions()
return dompurify.sanitize(rs)
}, [str]);
}, [str,issues]);
// #id
useEffect(()=>{

View File

@ -6,7 +6,7 @@ import Attachments from "../../Upload/attachment";
import UploadImg from '../Img/UploadImg.png';
function NewPanel(props,ref){
const [ description , setDescription ] = useState("");
const [ description , setDescription ] = useState(undefined);
const [ fileList , setFileList] = useState(undefined);
const [ attachments , setAttachments ] = useState([]);
const [ save , setSave ] = useState([]);
@ -15,12 +15,11 @@ function NewPanel(props,ref){
const { createFunc , title , desc , files , onCancel , owner , projectsId } = props;
const { form: { getFieldDecorator, validateFields , setFieldsValue } } = props;
useState(()=>{
title && setTimeout(()=>{
setFieldsValue({subject:title});
desc && onContentChange(desc);
},100)
desc && setDescription(desc);
files && setAttachments(files);
files && setSave(files);
},[title , desc , files])
@ -84,7 +83,7 @@ function NewPanel(props,ref){
<MDEditor
placeholder={"请输入描述信息"}
height={392}
mdID={"order-new-description"}
mdID={"issue-edit-description"}
initValue={description}
onChange={onContentChange}
className="mt20"

View File

@ -32,6 +32,7 @@ function Details(props){
const [ tag , setTag ] = useState(undefined);
const [ branchList , setBranchList ] = useState(undefined);
const [ branch , setBranch ] = useState(undefined);
const [ desc , setDesc ] = useState(undefined);
const [ orderId , setOrderId ] = useState(undefined);
@ -91,6 +92,8 @@ function Details(props){
let per = data && !data.user_permission;
setEditFlag(per);
setDesc(data && data.description);
const aut = current_user && data.author && (data.author.login === current_user.login);
const con = data.pull_fixed === false && aut;
setAmountEditFlag(con);
@ -277,10 +280,10 @@ function Details(props){
if(result){
window.scrollTo(0,0);
props.showNotification("疑修更新成功!");
//
setCommentReload(Math.random());
Init();
setEdit(false);
//
setCommentReload(Math.random());
}
}).catch(error=>{})
}else{
@ -318,6 +321,7 @@ function Details(props){
props.history.push(`/${owner}/${projectsId}/issues/${index}`);
}else{
setEdit(false);
window.scrollTo(0,0);
}
}
@ -367,7 +371,7 @@ function Details(props){
{...props}
onCancel={onCancel}
title={details.subject}
desc={details.description}
desc={edit ? desc : undefined}
files={copy ? undefined : details.attachments}
createFunc={createFunc}
owner = {owner} projectsId = {projectsId}
@ -405,8 +409,8 @@ function Details(props){
}
</div>
<div class="descPanel">
{details.description ?
<RenderHtml className="break_word_comments imageLayerParent" value={details.description} url={props.history.location} />
{desc ?
<RenderHtml owner={owner} projectsId={projectsId} className="break_word_comments imageLayerParent" value={desc} url={props.history.location} />
:
<span className="color-grey-9 ml3 mr3">暂无描述</span>
}

View File

@ -74,7 +74,7 @@ function md_elocalStorage(editor, mdu, id) {
return tid
}
export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, className = '', noStorage = false, imageExpand = true, placeholder = '', width = '100%', height = 400, initValue = '', emoji, watch, showNullButton = false, showResizeBar = false, startInit = true , forMember = true , isCanAtme = false , isQuoteIssue = false , changeAtWhoLoginList, owner, projectsId , isFocus = true}) => {
export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, className = '', noStorage = false, imageExpand = true, placeholder = '', width = '100%', height = 400, initValue = '', emoji, watch=true, showNullButton = false, showResizeBar = false, startInit = true , forMember = true , isCanAtme = false , isQuoteIssue = false , changeAtWhoLoginList, owner, projectsId , isFocus = true}) => {
const editorEl = useRef();
const resizeBarEl = useRef();
@ -130,11 +130,6 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
})
}
useEffect(()=>{
if(initValue){
console.log(initValue);
}
},[initValue])
// # 引用的弹框div
const QuoteDiv = (
@ -176,42 +171,44 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
}
useEffect(()=>{
if(quoteVisibleRef.current){
const atWhoListDiv = document.getElementById("quoteDiv");
const atWhoDivs = document.getElementsByClassName("quote");
cmEl.addKeyMap({
'Up':()=>{
let index;
for(let i = 0; i<atWhoDivs.length;i++){
atWhoDivs[i].className === "quote active" && (index = i);
if(cmEl){
if(quoteVisibleRef.current){
const atWhoListDiv = document.getElementById("quoteDiv");
const atWhoDivs = document.getElementsByClassName("quote");
cmEl.addKeyMap({
'Up':()=>{
let index;
for(let i = 0; i<atWhoDivs.length;i++){
atWhoDivs[i].className === "quote active" && (index = i);
}
if(index>0){
index <=atWhoDivs.length-4 && (atWhoListDiv.scrollTop -=40)
atWhoDivs[index].className = "quote";
atWhoDivs[index-1].className = "quote active";
}
},
'Down':()=>{
let index;
for(let i = 0; i<atWhoDivs.length;i++){
atWhoDivs[i].className === "quote active" && (index = i);
}
if(index<atWhoDivs.length-1){
index >=3 && (atWhoListDiv.scrollTop +=40)
atWhoDivs[index].className = "quote";
atWhoDivs[index+1].className = "quote active";
}
},
'Enter':()=>{
//找到classname为quote active的div执行click事件
if(document.getElementsByClassName("quote active")[0]){
document.getElementsByClassName("quote active")[0].click();
}
}
if(index>0){
index <=atWhoDivs.length-4 && (atWhoListDiv.scrollTop -=40)
atWhoDivs[index].className = "quote";
atWhoDivs[index-1].className = "quote active";
}
},
'Down':()=>{
let index;
for(let i = 0; i<atWhoDivs.length;i++){
atWhoDivs[i].className === "quote active" && (index = i);
}
if(index<atWhoDivs.length-1){
index >=3 && (atWhoListDiv.scrollTop +=40)
atWhoDivs[index].className = "quote";
atWhoDivs[index+1].className = "quote active";
}
},
'Enter':()=>{
//找到classname为quote active的div执行click事件
if(document.getElementsByClassName("quote active")[0]){
document.getElementsByClassName("quote active")[0].click();
}
}
})
} else {
//移除上下、enter键监听
cmEl && cmEl.removeKeyMap();
})
} else {
//移除上下、enter键监听
cmEl.removeKeyMap();
}
}
},[quoteVisible])
@ -302,7 +299,7 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
}
})
}
if(e.shiftKey && e.code === "Digit3"){
if(e.shiftKey && e.code === "Digit3" && isQuoteIssue){
// 输入#键后在对应的位置显示可选的项目issue
quoteVisibleRef.current = true;
setQuoteVisible(true);
@ -348,8 +345,7 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
htmlDecode: "style,script,iframe",
sequenceDiagram: true,
autoFocus: false,
watch: watch === undefined ? true : watch,
watch: watch,
saveHTMLToTextarea: true,
dialogMaskOpacity: 0.6,
placeholder: placeholder,
@ -471,10 +467,11 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
}
},[users])
useEffect(() => {
if (cmEl) {
let tid = null
let ro
let ro;
if (onCMBlur) {
editorInstance.cm.on('blur', () => { onCMBlur(editorInstance.getValue()) })
}
@ -750,15 +747,13 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
document.removeEventListener('mouseup', onMouseUp)
}
}
}, [
editorInstance, resizeBarEl
])
}, [ editorInstance, resizeBarEl ])
return (
<Fragment>
{atWhoVisible && atWhoList}
{quoteVisible && QuoteDiv }
<div ref={editorEl} className={`df editormd-editing ${className} ${imageExpand && 'editormd-image-click-expand'} `}>
{quoteVisible && QuoteDiv }
<div className={`edu-back-greyf5 radius4 editormd ${error ? 'error' : ''}`} id={containerId} >
<textarea style={{ display: 'none' }} id={editorBodyId} name="content"></textarea>
<div className="CodeMirror cm-s-defualt"></div>