forgeplus-react/src/forge/Information/Pages/help.jsx

255 lines
9.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useEffect, useState } from 'react';
import { Box, LongWidth, FlexAJ } from '../../Component/layout';
import { Affix, Button, Input, message, Spin, Tree } from 'antd';
import Nodata from '../../Nodata';
import nodata from '../img/nodata.png';
import { tempEnum } from '../tempInfo';
import { findFirstWiki, generateList, getParentKey, getWiki, parseSidebar, wikiPages } from '../../Wiki/api';
import RenderHtml from '../../../components/render-html';
import { Base64 } from 'js-base64';
import { getTocContent } from '../../../common/marked';
import { splitAndCombine } from '../../Wiki/utils';
const { Search } = Input;
const { DirectoryTree, TreeNode } = Tree;
function ProjectSource(props) {
const [loading, setLoading] = useState(false);
const [wikiList, setWikiList] = useState(undefined);
const [flattenedMenuList, setFlattenedMenuList] = useState([]);
const [initMenuList, setInitMenuList] = useState([]);
const [expandedKeys, setExpandedKeys] = useState(undefined);
const [wiki, setWiki] = useState(undefined);
const [wikiDetail, setWikiDetail] = useState(undefined);
const [autoExpandParent, setAutoExpandParent] = useState(false);
const [searchValue, setSearchValue] = useState("");
const [wikiContMenu, setWikiContMenu] = useState(undefined);
const { temp, history, data, adminUrl } = props;
let scroller = undefined;
const { owner, identifier, projectId } = (data && data.gitlinkProject) || {};
const wikiParams = {
owner,
repo: identifier,
projectId
};
const reg = /[.,/#!$%^&*;:{}=\-_`~():,。¥;「」|?》《~·【】‘、!]/g;
useEffect(() => {
if(!owner) return
// 获取wiki 列表
wikiPages(wikiParams).then(async res => {
if (res && res.message === "200") {
setWikiList(res.data);
// 解析sidebar获取目录list
const info = await parseSidebar(res.data, wikiParams);
if (!info) return
const { menuList } = info;
// 默认打开第一个wiki
const firstWiki = findFirstWiki(menuList);
if(firstWiki){
setExpandedKeys(splitAndCombine(firstWiki.key+""));
setWiki(firstWiki);
}
setFlattenedMenuList(generateList(menuList));
setInitMenuList(menuList);
} else {
setWikiList([]);
}
})
}, [owner])
useEffect(() =>{
if(!wiki){
return
}
// 获取wiki内容
setLoading(true);
getWiki({
pageName: wiki.title_sub,
...wikiParams
}).then(res=>{
setLoading(false);
if (res && res.message === "200") {
setWikiDetail(res.data);
const tocContent = getTocContent();
setWikiContMenu(tocContent);
} else {
message.error("加载失败")
}
})
}, [wiki && wiki.title_sub])
useEffect(() => {
if (scroller) {
scroller.destroy();
}
if (!document.querySelector('.wikiContentHC .markdown_anchors')) {
return;
}
require('intersection-observer');
// 默认第一个高亮
setTimeout(() => {
const linkNode = document.querySelectorAll(`.wikiContMenuBox li a`)[0];
linkNode && (linkNode.className = 'current');
}, 100);
const scrollama = require('scrollama');
scroller = scrollama();
scroller
.setup({
step: '.wikiContentHC .markdown_anchors',
offset: 0.2,
})
.onStepEnter(({ element }) => {
[].forEach.call(document.querySelectorAll('.wikiContMenuBox li a'), node => {
node.className = '';
});
const currentNode = document.querySelectorAll(`.wikiContMenuBox li a[href="#${element.textContent.toLocaleLowerCase()}"]`)[0];
if (currentNode) {
currentNode.className = 'current';
}
})
}, [wikiDetail])
useEffect(() =>{
// 点击事件
const handleClick = (event) => {
let target = event.target;
if (target.tagName.toUpperCase() === 'A') {
let ancher = target.getAttribute('href');
if (ancher && ancher.startsWith('#')) {
event.preventDefault()
let viewEl = document.getElementById(ancher.replace(reg,""))
if (viewEl) {
viewEl.scrollIntoView(true);
// 滚动结束后向下偏移170像素
window.scrollBy(0,-170);
}
}
}
};
// 滚动
const scroll = () =>{
var element = document.getElementById('wikiContMenuBox');
var scrollTop = document.documentElement.scrollTop||document.body.scrollTop;
var windowHeight = document.documentElement.clientHeight || document.body.clientHeight;
var scrollHeight = document.documentElement.scrollHeight||document.body.scrollHeight;
if(scrollHeight-scrollTop <= windowHeight*1.2){
const maxElementHeight = (scrollHeight-scrollTop)/2-200;
element && (element.style.maxHeight = maxElementHeight + 'px');
}else if(scrollHeight-scrollTop <= windowHeight*1.5){
const maxElementHeight = (scrollHeight-scrollTop)/2-100;
element && (element.style.maxHeight = maxElementHeight + 'px');
}else{
element && (element.style.maxHeight = '80vh');
}
}
document.addEventListener("click", handleClick);
document.addEventListener("scroll", scroll);
return () => {
document.removeEventListener("click", handleClick);
document.removeEventListener("scroll", scroll);
};
}, [])
function changeSearchValue(value) {
if (value) {
const va = value.trim();
// 找到命中搜索的item的父元素
const expandedKeys = flattenedMenuList.map(item => {
if (item.title.match(new RegExp(va, 'i'))) {
return getParentKey(item.key, initMenuList);
}
return null;
}).filter((item, i, self) => item && self.indexOf(item) === i);
setSearchValue(va);
setExpandedKeys(splitAndCombine(expandedKeys[0]));
} else {
setSearchValue("");
}
}
// 收起展开
function onExpand(expandedKeys) {
setAutoExpandParent(false);
setExpandedKeys(expandedKeys);
}
// 选中节点
function selectTree(keys,event){
let {isFile} = event.node.props.dataRef;
if(isFile){
setWiki(event.node.props.dataRef);
}
}
function renderTreeNodes(data) {
return data && data.length > 0 && data.map((item) => {
const matchResult = item.titleStr.match(new RegExp(searchValue, 'i'));
const title = matchResult ? (
<span>
{item.titleStr.substr(0, matchResult.index)}
<span style={{ color: '#f50' }}>{item.titleStr.substring(matchResult.index, matchResult.index+searchValue.length)}</span>
{item.titleStr.substr(matchResult.index+searchValue.length)}
</span>
) : (
<span>{item.titleStr}</span>
);
return (
<TreeNode title={title} key={item.key + ""} isLeaf={item.isFile} dataRef={item} className='menuHcNode font-15'>
{renderTreeNodes(item.children)}
</TreeNode>
);
});
}
const noDataText = adminUrl ? <a href={`${data && data.gitlinkProject.wiki_url}`} target="_blank" style={{color: '#466aff'}}>前往配置</a> : ""
return (
<div className="in_pro">
<div className="boxmain" style={{ paddingTop: "56px" }}>
<p className="in_title mb30">{data && data.sectionHelperTitle}</p>
<Spin spinning={loading}>
{
wikiList && (wikiList.length > 0 ? <Box className='zoneHelpBox'>
{/* wiki目录导航 */}
<div className='leftMenuBox mr20'>
<div className='leftMenuHC'>
<Search
allowClear
placeholder="输入关键字搜索文件"
className="searchHC mb10"
onSearch={changeSearchValue}
/>
<DirectoryTree onSelect={selectTree} expandedKeys={expandedKeys} onExpand={onExpand} autoExpandParent={autoExpandParent} showIcon={false}>
{renderTreeNodes(initMenuList)}
</DirectoryTree>
</div>
</div>
{/* 内容区 */}
{wikiDetail && <LongWidth className='wikiContentBox'>
<Box>
<LongWidth>
<FlexAJ style={{alignItems: 'stretch'}}>
<div>
<div className='wikiTitleHC font-20 mb5'>{wikiDetail.name}</div>
{wikiDetail.commit && <div className='wikiUpdateTimeHC font-15'>更新时间{wikiDetail.commit.author.date || '刚刚'}</div>}
</div>
{adminUrl && <Button onClick={()=>{wiki && window.open(`${data && data.gitlinkProject.wiki_url}/${wiki.title_sub}/${wiki.key}`)}} className='zone_apply_button' style={{width: '90px', height: '34px'}}>配置内容</Button>}
</FlexAJ>
{wikiDetail.md_content && <RenderHtml className="wikiContentHC editor-content-panel mt20 imageLayerParent" value={ Base64.decode(wikiDetail.md_content) } url={history.location}/>}
</LongWidth>
{wikiContMenu && wikiContMenu !== "<ul></ul>" && <Affix offsetTop={80}>
<div id="wikiContMenuBox" className='wikiContMenuBox font-15' dangerouslySetInnerHTML={{ __html: wikiContMenu }}></div>
</Affix>}
</Box>
</LongWidth>}
</Box> : (temp === tempEnum.zone1 ? <Nodata _html={noDataText} img={nodata} /> : <Nodata _html={noDataText} />))}
</Spin>
</div>
</div>
)
}
export default ProjectSource;