forgeplus-react/src/forge/Wiki/Index.jsx

299 lines
10 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, 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 Loading from "../../Loading";
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';
const Search = Input.Search;
const InputGroup = Input.Group;
const { Option } = Select;
export default (props) => {
const { match, current_user, history, showNotification, project, projectDetail } = props;
// const permission = projectDetail && projectDetail.permission !== "Reporter";
const permission = projectDetail && projectDetail.permission && projectDetail.permission !== "Reporter";
let projectsId = match.params.projectsId;
let owner = match.params.owner;
console.log(project);
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) {
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 = `/users/${login}`;
}
// 复制链接
const copyUrl = useCallback(() => {
let wikiUrl = document.getElementById("wikiUrl");
wikiUrl.select();
if (document.execCommand('copy')) {
document.execCommand('copy');
}
message.success('复制成功');
wikiUrl.blur();
}, [])
function addFile() {
history.push(`/projects/${owner}/${projectsId}/wiki/add`);
}
function goEdit() {
history.push(`/projects/${owner}/${projectsId}/wiki/edit/${encodeURI(checkItem.name)}`);
}
function preview() {
window.open(`/projects/${owner}/${projectsId}/wiki/preview/${encodeURI(project.name)}/${project.id}`);
}
// 支持 MarkdownHtmlPdf格式文件
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}`, //?token=${sessionStorage.taskToken}
showUploadList: false,
headers: {
Authorization: cookie.load(TokenKey) || sessionStorage.taskToken,
},
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} 上传失败`);
}
},
};
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">
<div className={`wiki-nav-title ${item.name === checkItem.name ? 'active' : ''}`} key={item.name} onClick={() => { setCheckItem(item) }}>
<div className="nav-title-left">
<i className="iconfont icon-wenjianjia2 mr3"></i>
<span className="nav-title-left-text">{item.name}</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} />
<Tooltip placement="bottom" title={'复制'}>
<i className="iconfont icon-fuzhiicon copy-svg" onClick={copyUrl}></i>
</Tooltip>
</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={() => { goUser(current_user.login) }}>
{itemDetail.image_url && <img alt="头像" className="head-log-small" src={getImageUrl(`/${itemDetail.image_url}`)} />}
<span >{checkItem.commit ? checkItem.commit.author.name : ''}</span>
</span>
<span className="time-ago">上次修改于{checkItem.commit && timeAgo(checkItem.commit.author.when)}</span>
</div>
{permission && <Button type="primary" onClick={goEdit}>编辑</Button>}
</div>
<div className="wiki-content-detail editor-content-panel markdown-body" dangerouslySetInnerHTML={{ __html: itemDetail && itemDetail.simple_content }} ></div>
</div>
</div>
</div >
:
<Welcome {...props} reloadList={setReload} />
}
</Spin>
)
}