295 lines
10 KiB
JavaScript
295 lines
10 KiB
JavaScript
import React, { useEffect, useCallback, useState } from 'react';
|
||
import { Button, Dropdown, Icon, Input, Menu, Tooltip, Select, Upload, message, Spin } from 'antd';
|
||
import { getImageUrl, timeAgo } from 'educoder';
|
||
import cookie from 'react-cookies';
|
||
import CopyTool from '../Component/CopyTool';
|
||
import DelModal from './components/ModalFun';
|
||
import Welcome from './Welcome';
|
||
import { wikiPages, getWiki, deleteWiki } from './api';
|
||
import { httpUrl, TokenKey } from './fetch';
|
||
import './Index.scss';
|
||
import { isArray } from 'lodash';
|
||
import RenderHtml from '../../components/render-html';
|
||
const Search = Input.Search;
|
||
const InputGroup = Input.Group;
|
||
const { Option } = Select;
|
||
|
||
export default (props) => {
|
||
const { match, history, showNotification, project, projectDetail } = props;
|
||
const permission = projectDetail && projectDetail.permission && projectDetail.permission !== "Reporter";
|
||
|
||
let projectsId = match.params.projectsId;
|
||
let owner = match.params.owner;
|
||
let wikiName = match.params.wikiName;
|
||
const [fileArrInit, setFileArrInit] = useState(null);
|
||
const [checkItem, setCheckItem] = useState({});
|
||
const [itemDetail, setItemDetail] = useState({});
|
||
|
||
const [fileArr, setFileArr] = useState([]);
|
||
const [reload, setReload] = useState();
|
||
|
||
const [urlType, setUrlType] = useState('HTTPS');
|
||
|
||
// 加载wiki列表
|
||
useEffect(() => {
|
||
project && wikiPages({
|
||
owner: owner,
|
||
repo: projectsId,
|
||
projectId: project.id
|
||
}).then(res => {
|
||
if (res && res.message === "200" && isArray(res.data)) {
|
||
setFileArr(res.data);
|
||
setFileArrInit(res.data);
|
||
if (res.data.length) {
|
||
if (wikiName) {
|
||
let activeItem = res.data.filter(item => { return item.name == wikiName })[0] || res.data[0];
|
||
setCheckItem(activeItem)
|
||
} else {
|
||
setCheckItem(res.data[0]);
|
||
}
|
||
};
|
||
} else {
|
||
setFileArr([]);
|
||
setFileArrInit([]);
|
||
}
|
||
});
|
||
}, [project, reload])
|
||
|
||
// 加载单个wiki详情,参数尽量用驼峰,此处由于后端太麻烦所以不标准
|
||
useEffect(() => {
|
||
project && checkItem.name && getWiki({
|
||
owner: owner,
|
||
repo: projectsId,
|
||
pagename: checkItem.name,
|
||
projectId: project.id
|
||
}).then(res => {
|
||
if (res && res.message === "200") {
|
||
setItemDetail(res.data);
|
||
} else {
|
||
showNotification("加载失败")
|
||
}
|
||
});
|
||
}, [project, checkItem]);
|
||
|
||
function changeSearchValue(e) {
|
||
let value = e.target.value;
|
||
let newFileArr = [];
|
||
for (const item of fileArrInit) {
|
||
if (item.name.indexOf(value) > -1) {
|
||
newFileArr.push(item);
|
||
}
|
||
}
|
||
setFileArr(newFileArr);
|
||
}
|
||
|
||
// 删除wiki模态框
|
||
function deleteFileModal(e, item) {
|
||
e.stopPropagation();
|
||
DelModal({
|
||
title: '删除页面',
|
||
contentTitle: `您确定要删除“${item.name}”此页面吗?`,
|
||
content: '此操作将删除该页面,请进行确认以防文件的丢失',
|
||
onOk: () => {
|
||
deleteWiki({
|
||
owner: owner,
|
||
repo: projectsId,
|
||
pagename: item.name,
|
||
projectId: project.id
|
||
}).then(res => {
|
||
if (res && res.message === "200") {
|
||
message.success('删除成功');
|
||
setReload(Math.random());
|
||
} else {
|
||
message.error('删除失败');
|
||
}
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
|
||
function goUser(login) {
|
||
window.location.href = `/${login}`;
|
||
}
|
||
|
||
function addFile() {
|
||
history.push(`/${owner}/${projectsId}/wiki/add`);
|
||
}
|
||
|
||
function goEdit() {
|
||
history.push(`/${owner}/${projectsId}/wiki/edit/${encodeURI(checkItem.name)}`);
|
||
}
|
||
|
||
function preview() {
|
||
window.open(`/${owner}/${projectsId}/wiki/preview/${encodeURI(project.name)}/${project.id}`);
|
||
}
|
||
|
||
// 支持 Markdown,Html,Pdf格式文件
|
||
const menu = (
|
||
<Menu >
|
||
<Menu.Item key="1" onClick={() => { downloadWiki('markdown') }}>
|
||
Markdown
|
||
</Menu.Item>
|
||
<Menu.Item key="2" onClick={() => { downloadWiki('html') }}>
|
||
HTML
|
||
</Menu.Item>
|
||
<Menu.Item key="3" onClick={() => { downloadWiki('pdf') }}>
|
||
PDF
|
||
</Menu.Item>
|
||
</Menu>
|
||
);
|
||
|
||
function downloadWiki(type) {
|
||
window.open(`${httpUrl}/api/wikiExport/wikiExport-wrapper?repoName=${projectsId}&owner=${owner}&type=${type}&projectName=${project.name}&projectId=${project.id}`);
|
||
}
|
||
|
||
function beforeUpload(file) {
|
||
if (!['md', 'txt'].includes(file.name.split('.').pop())) {
|
||
message.error('只能上传md、txt文件');
|
||
return false;
|
||
}
|
||
|
||
let regEn = /[\[\]`\/:*?''<>|%-+_]/g;
|
||
if (regEn.test(file.name)) {
|
||
message.error('文件名不能有特殊字符');
|
||
return;
|
||
}
|
||
|
||
for (const item of fileArrInit) {
|
||
if (item.name === file.name) {
|
||
message.error('不能上传与已有文件相同文件名的文件');
|
||
return false;
|
||
}
|
||
}
|
||
const isLt100M = file.size / 1024 / 1024 < 100;
|
||
if (!isLt100M) {
|
||
showNotification(`文件大小必须小于${100}MB!`);
|
||
}
|
||
return isLt100M;
|
||
}
|
||
|
||
const uploadProps = {
|
||
name: 'multipartFile',
|
||
withCredentials: true,
|
||
action: `${httpUrl}/api/wikiExport/uploadWiki/${owner}/${projectsId}/${project && project.id}`,
|
||
showUploadList: false,
|
||
headers: {
|
||
Authorization: cookie.load(TokenKey),
|
||
},
|
||
beforeUpload: beforeUpload,
|
||
onChange(info) {
|
||
if (info.file.status === 'uploading') {
|
||
console.log(info.file, info.fileList);
|
||
}
|
||
if (info.file.status === 'done') {
|
||
if (info.file.response.message === '200') {
|
||
message.success(`${info.file.name} 上传成功`);
|
||
setReload(Math.random());
|
||
} else if (info.file.response.message === '500') {
|
||
let data = JSON.parse(info.file.response.data);
|
||
message.error(data && data.message ? data.message : '文件上传失败');
|
||
} else {
|
||
message.error('文件上传失败');
|
||
}
|
||
} else if (info.file.status === 'error') {
|
||
message.error(`${info.file.name} 上传失败`);
|
||
}
|
||
},
|
||
};
|
||
|
||
function changeItem(item){
|
||
history.push(`/${owner}/${projectsId}/wiki/${item.name}`)
|
||
setCheckItem(item);
|
||
}
|
||
|
||
return (
|
||
< Spin spinning={!fileArrInit} className="opacitySpin">
|
||
{fileArrInit && fileArrInit.length ?
|
||
<div className="wiki-main">
|
||
<div className="wiki-head">
|
||
|
||
<span className="head-title">
|
||
{
|
||
permission ?
|
||
<Button type="default" onClick={addFile}><Icon type="plus" />新增页面</Button>
|
||
: "Wiki文档"
|
||
}
|
||
</span>
|
||
<div>
|
||
{
|
||
permission &&
|
||
<Upload {...uploadProps}>
|
||
<Tooltip placement="top" title={'支持导入txt、markdown格式文件'}>
|
||
<Button type="default" className="ml10"><Icon type="plus" />导入模板</Button>
|
||
</Tooltip>
|
||
</Upload>
|
||
}
|
||
<Dropdown overlay={menu}>
|
||
<Button type="default" className="ml10">导出<Icon type="caret-down" /></Button>
|
||
</Dropdown>
|
||
<Button type="default" className="ml10" onClick={preview}>预览</Button>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<div className="wiki-body">
|
||
<div className="wiki-nav-parent">
|
||
<div className="wiki-nav">
|
||
<Search
|
||
// allowClear
|
||
placeholder="输入关键字搜索文件"
|
||
className="wiki-search"
|
||
onChange={changeSearchValue}
|
||
/>
|
||
|
||
{
|
||
fileArr.map(item => {
|
||
return <div className="wiki-nav-title-parent" key={item.name}>
|
||
<div className={`wiki-nav-title ${item.name === checkItem.name ? 'active' : ''}`} onClick={() => { changeItem(item) }}>
|
||
<div className="nav-title-left">
|
||
<i className="iconfont icon-wenjianjia2 mr3"></i>
|
||
<span className="nav-title-left-text">{item.name.substring(0, item.name.indexOf('.') !== -1 ? item.name.lastIndexOf('.') : item.name.length-1)}</span>
|
||
</div>
|
||
{permission && <i className="iconfont icon-shanchuicon1 delete-title-icon color-grey-6" onClick={(e) => { deleteFileModal(e, item) }}></i>}
|
||
</div>
|
||
</div>
|
||
})
|
||
}
|
||
</div>
|
||
|
||
|
||
{checkItem.wiki_clone_link && <InputGroup className="copy-url" compact>
|
||
<Select dropdownClassName="wiki-url-type" defaultValue="HTTPS" onChange={(v) => { setUrlType(v) }}>
|
||
<Option value="HTTPS">HTTPS</Option>
|
||
<Option value="SSH">SSH</Option>
|
||
</Select>
|
||
<Input id="wikiUrl" value={urlType === 'HTTPS' ? checkItem.wiki_clone_link.https : checkItem.wiki_clone_link.ssh} />
|
||
<CopyTool className="copy-wiki" inputId="wikiUrl" />
|
||
</InputGroup>}
|
||
|
||
</div>
|
||
|
||
<div className="wiki-content">
|
||
<div className="wiki-content-head">
|
||
<div className="wiki-content-head-left">
|
||
<h3 className="wiki-detail-title">{checkItem.name}</h3>
|
||
<span className="user-box mr10" onClick={() => { checkItem.commit && goUser(checkItem.commit.author.name) }}>
|
||
{itemDetail.image_url && <img alt="头像" className="head-log-small" src={getImageUrl(`/${itemDetail.image_url}`)} />}
|
||
<span >{itemDetail.userName}</span>
|
||
</span>
|
||
<span className="time-ago">上次修改于{checkItem.commit ? timeAgo(checkItem.commit.author.when):'刚刚'}</span>
|
||
</div>
|
||
{permission && <Button type="primary" onClick={goEdit}>编辑</Button>}
|
||
</div>
|
||
|
||
{itemDetail && itemDetail.md_content && <RenderHtml className="wiki-content-detail editor-content-panel" value={ itemDetail.md_content } url={history.location}/>}
|
||
</div>
|
||
</div>
|
||
</div >
|
||
:
|
||
<Welcome {...props} reloadList={setReload} />
|
||
}
|
||
</Spin>
|
||
)
|
||
}
|