Merge pull request '修改头像的bug,提取copyUrl组件,优化函数式模态框组件' (#20) from tongChong/forgeplus-react:feature_wikis into pre_develop_dev
This commit is contained in:
commit
39fef1ce3c
|
@ -0,0 +1,44 @@
|
|||
import React, { useState, useCallback, memo } from 'react';
|
||||
import { Tooltip } from 'antd';
|
||||
|
||||
CopyTool.defaultProps = {
|
||||
beforeText: '复制', //浮动过去显示的文字
|
||||
afterText: '复制成功', //点击后显示的文字
|
||||
className: '', //传给svg的class
|
||||
inputId: 'copyText', //要复制的文本的ID
|
||||
};
|
||||
|
||||
|
||||
function CopyTool({ beforeText, afterText, className,inputId }) {
|
||||
const [title, setTitle] = useState(() => {
|
||||
return beforeText;
|
||||
});
|
||||
|
||||
// 复制链接
|
||||
const copyUrl = useCallback(() => {
|
||||
let inputDom = document.getElementById(inputId);
|
||||
if (!inputDom) {
|
||||
console.error("您的CopyTool未设置正确的inputId");
|
||||
return;
|
||||
}
|
||||
inputDom.select();
|
||||
if (document.execCommand('copy')) {
|
||||
document.execCommand('copy');
|
||||
}
|
||||
setTitle(afterText);
|
||||
inputDom.blur();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
placement="top"
|
||||
title={title}
|
||||
onVisibleChange={() => { setTitle(beforeText) }}
|
||||
>
|
||||
<i className={`iconfont icon-fuzhiicon ${className}`} style={{ color: '#466aff' }} onClick={copyUrl}></i>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default memo(CopyTool);
|
|
@ -2,7 +2,7 @@ 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 CopyTool from '../Component/CopyTool';
|
||||
import DelModal from './components/ModalFun';
|
||||
import Welcome from './Welcome';
|
||||
import { wikiPages, getWiki, deleteWiki } from './api';
|
||||
|
@ -14,15 +14,12 @@ 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 { match, history, showNotification, project, projectDetail } = props;
|
||||
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({});
|
||||
|
@ -85,7 +82,7 @@ export default (props) => {
|
|||
DelModal({
|
||||
title: '删除页面',
|
||||
contentTitle: `您确定要删除“${item.name}”此页面吗?`,
|
||||
content: '此操作将删除该页面,请进行确认以防文件的丢失。',
|
||||
content: '此操作将删除该页面,请进行确认以防文件的丢失',
|
||||
onOk: () => {
|
||||
deleteWiki({
|
||||
owner: owner,
|
||||
|
@ -109,17 +106,6 @@ export default (props) => {
|
|||
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`);
|
||||
}
|
||||
|
@ -231,6 +217,7 @@ export default (props) => {
|
|||
<Button type="default" className="ml10">导出<Icon type="caret-down" /></Button>
|
||||
</Dropdown>
|
||||
<Button type="default" className="ml10" onClick={preview}>预览</Button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -246,8 +233,8 @@ export default (props) => {
|
|||
|
||||
{
|
||||
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) }}>
|
||||
return <div className="wiki-nav-title-parent" key={item.name}>
|
||||
<div className={`wiki-nav-title ${item.name === checkItem.name ? 'active' : ''}`} onClick={() => { setCheckItem(item) }}>
|
||||
<div className="nav-title-left">
|
||||
<i className="iconfont icon-wenjianjia2 mr3"></i>
|
||||
<span className="nav-title-left-text">{item.name}</span>
|
||||
|
@ -266,9 +253,7 @@ export default (props) => {
|
|||
<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>
|
||||
<CopyTool className="copy-wiki" inputId="wikiUrl" />
|
||||
</InputGroup>}
|
||||
|
||||
</div>
|
||||
|
@ -277,9 +262,9 @@ export default (props) => {
|
|||
<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) }}>
|
||||
<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 >{checkItem.commit ? checkItem.commit.author.name : ''}</span>
|
||||
<span >{itemDetail.userName}</span>
|
||||
</span>
|
||||
<span className="time-ago">上次修改于{checkItem.commit && timeAgo(checkItem.commit.author.when)}</span>
|
||||
</div>
|
||||
|
|
|
@ -199,7 +199,7 @@ body {
|
|||
word-break: break-all;
|
||||
}
|
||||
|
||||
.copy-svg {
|
||||
.copy-wiki {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React, { useEffect, useCallback, useState } from 'react';
|
||||
import { Input, Button, Tooltip, Select, Dropdown, Icon, Menu, message } from 'antd';
|
||||
import { Input, Button, Select, Dropdown, Icon, Menu, message } from 'antd';
|
||||
import CopyTool from '../Component/CopyTool';
|
||||
import { wikiPages, getWiki, } from './api';
|
||||
import { httpUrl } from './fetch';
|
||||
import './Index.scss';
|
||||
|
@ -59,16 +60,6 @@ export default (props) => {
|
|||
});
|
||||
}, [project, checkItem]);
|
||||
|
||||
const copyUrl = useCallback(() => {
|
||||
let wikiUrl = document.getElementById("wikiUrl");
|
||||
wikiUrl.select();
|
||||
if (document.execCommand('copy')) {
|
||||
document.execCommand('copy');
|
||||
}
|
||||
message.success('复制成功');
|
||||
wikiUrl.blur();
|
||||
}, []);
|
||||
|
||||
function goEdit() {
|
||||
history.push(`/projects/${owner}/${projectsId}/wiki/edit/${checkItem.name}`);
|
||||
}
|
||||
|
@ -113,9 +104,7 @@ export default (props) => {
|
|||
<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>
|
||||
<CopyTool className="copy-wiki" inputId="wikiUrl"/>
|
||||
</InputGroup>
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import React, { useState } from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import LoginDialog from '../../../../modules/login/LoginDialog';
|
||||
import './index.scss';
|
||||
|
||||
// 使用函数调用删除组件
|
||||
export default function DelModal(props) {
|
||||
// 使用函数调用登录组件
|
||||
export default function Login(props) {
|
||||
const div = document.createElement('div');
|
||||
document.body.appendChild(div);
|
||||
|
||||
|
@ -16,9 +15,6 @@ export default function DelModal(props) {
|
|||
}
|
||||
|
||||
function render() {
|
||||
/**
|
||||
* Sync render blocks React event. Let's make this async.
|
||||
*/
|
||||
setTimeout(() => {
|
||||
ReactDOM.render(
|
||||
<MyLoginDialog afterClose={destroy} />
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
.delete-modal {
|
||||
.ant-modal-header {
|
||||
padding: 9px 24px;
|
||||
background: #f8f8f8;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.ant-modal-title {
|
||||
text-align: left;
|
||||
}
|
||||
.ant-modal-close {
|
||||
top: 0px !important;
|
||||
}
|
||||
.ant-modal-close-x {
|
||||
font-size: 24px;
|
||||
}
|
||||
.ant-modal-body {
|
||||
text-align: center;
|
||||
}
|
||||
.delete-title {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 2rem 0 1rem !important;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
letter-spacing: 0;
|
||||
line-height: 29px;
|
||||
font-weight: 400;
|
||||
}
|
||||
.red-circle {
|
||||
align-self: flex-start;
|
||||
color: #ca0002;
|
||||
font-size: 1.5rem !important;
|
||||
}
|
||||
.delete-descibe {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
line-height: 33px;
|
||||
font-weight: 400;
|
||||
}
|
||||
.ant-modal-footer {
|
||||
padding: 2rem 0;
|
||||
text-align: center;
|
||||
border: 0;
|
||||
.ant-btn {
|
||||
width: 6rem;
|
||||
}
|
||||
}
|
||||
.foot-submit {
|
||||
margin-left: 3rem;
|
||||
color: #df0002;
|
||||
&:hover {
|
||||
border-color: #df0002;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +1,33 @@
|
|||
/* eslint-disable react/jsx-no-duplicate-props */
|
||||
import React, { useState } from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { Modal, Button } from 'antd';
|
||||
import './index.scss';
|
||||
|
||||
InitModal.defaultProps = {
|
||||
okText: '确认', //确定按钮的文字
|
||||
cancelText: '取消', //取消按钮的文字
|
||||
className: '', //
|
||||
inputId: 'copyText', //要复制的文本的ID
|
||||
};
|
||||
|
||||
// 使用函数调用删除组件
|
||||
export default function DelModal(props) {
|
||||
renderModal({ ...props, type: 'delete' })
|
||||
}
|
||||
|
||||
export function confirmModal(props) {
|
||||
// 使用函数调用选择模态框组件
|
||||
export function Confirm(props) {
|
||||
renderModal({ ...props, type: 'confirm' })
|
||||
}
|
||||
|
||||
function renderModal(props) {
|
||||
const type = props.type;
|
||||
const { type, afterClose } = props;
|
||||
const div = document.createElement('div');
|
||||
document.body.appendChild(div);
|
||||
|
||||
function destroy() {
|
||||
afterClose && afterClose();
|
||||
const unmountResult = ReactDOM.unmountComponentAtNode(div);
|
||||
if (unmountResult && div.parentNode) {
|
||||
div.parentNode.removeChild(div);
|
||||
|
@ -26,18 +36,26 @@ function renderModal(props) {
|
|||
|
||||
function modalType(type) {
|
||||
if (type === 'delete') {
|
||||
return <DeleteModal title="删除页面" contentTitle="确定要删除吗?" afterClose={destroy} {...props} />
|
||||
return <InitModal
|
||||
title="删除"
|
||||
contentTitle="确定要删除吗?"
|
||||
okText="确认删除"
|
||||
{...props}
|
||||
|
||||
afterClose={destroy}
|
||||
contentTitle={<React.Fragment>
|
||||
<i className="red-circle iconfont icon-shanchu_tc_icon mr3"></i>
|
||||
{props.contentTitle}
|
||||
</React.Fragment>}
|
||||
/>
|
||||
} else if (type === 'confirm') {
|
||||
return <ConfirmModal title="选择" afterClose={destroy} {...props} />
|
||||
return <InitModal title="选择" afterClose={destroy} {...props} />
|
||||
} else {
|
||||
return <ConfirmModal title="选择" afterClose={destroy} {...props} />
|
||||
return <InitModal title="选择" afterClose={destroy} {...props} />
|
||||
}
|
||||
}
|
||||
|
||||
function render() {
|
||||
/**
|
||||
* Sync render blocks React event. Let's make this async.
|
||||
*/
|
||||
setTimeout(() => {
|
||||
ReactDOM.render(
|
||||
modalType(type),
|
||||
|
@ -48,16 +66,17 @@ function renderModal(props) {
|
|||
render();
|
||||
}
|
||||
|
||||
// 真正的删除组件
|
||||
function DeleteModal({
|
||||
// 选择模态框组件
|
||||
function InitModal({
|
||||
onCancel,
|
||||
onOk,
|
||||
title,
|
||||
contentTitle,
|
||||
content,
|
||||
afterClose,
|
||||
okText,
|
||||
cancelText,
|
||||
afterClose,
|
||||
className,
|
||||
}) {
|
||||
|
||||
const [visible, setVisible] = useState(true);
|
||||
|
@ -78,71 +97,20 @@ function DeleteModal({
|
|||
onCancel={onCancelModal}
|
||||
afterClose={afterClose}
|
||||
title={title}
|
||||
className="myself-modal"
|
||||
className={`myself-modal ${className}`}
|
||||
centered
|
||||
footer={[
|
||||
<Button key="back" onClick={onCancelModal}>
|
||||
{cancelText||'取消'}
|
||||
<Button type="default" key="back" onClick={onCancelModal}>
|
||||
{cancelText}
|
||||
</Button>,
|
||||
<Button className="foot-submit" key="submit" onClick={onSuccess}>
|
||||
{okText||'确认删除'}
|
||||
{okText}
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<div>
|
||||
<p className="delete-title">
|
||||
<i className="red-circle iconfont icon-shanchu_tc_icon mr3"></i>
|
||||
{contentTitle}</p>
|
||||
<p className="delete-descibe">{content}</p>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
// 选择组件
|
||||
function ConfirmModal({
|
||||
onCancel,
|
||||
onOk,
|
||||
title,
|
||||
contentTitle,
|
||||
content,
|
||||
okText,
|
||||
cancelText,
|
||||
afterClose,
|
||||
}) {
|
||||
|
||||
const [visible, setVisible] = useState(true);
|
||||
|
||||
function onCancelModal() {
|
||||
setVisible(false);
|
||||
onCancel && onCancel()
|
||||
}
|
||||
|
||||
function onSuccess() {
|
||||
setVisible(false);
|
||||
onOk && onOk();
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
onCancel={onCancelModal}
|
||||
afterClose={afterClose}
|
||||
title={title}
|
||||
className="myself-modal"
|
||||
centered
|
||||
footer={[
|
||||
<Button key="back" onClick={onCancelModal}>
|
||||
{cancelText||'取消'}
|
||||
</Button>,
|
||||
<Button className="foot-submit" key="submit" onClick={onSuccess}>
|
||||
{okText||'确认'}
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<div>
|
||||
{contentTitle && <p className="delete-title">{contentTitle}</p>}
|
||||
<p className="delete-descibe">{content}</p>
|
||||
{contentTitle && <p className="content-title">{contentTitle}</p>}
|
||||
<p className="content-descibe">{content}</p>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
.ant-modal-body {
|
||||
text-align: center;
|
||||
}
|
||||
.delete-title {
|
||||
.content-title {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
@ -32,7 +32,7 @@
|
|||
color: #ca0002;
|
||||
font-size: 1.5rem !important;
|
||||
}
|
||||
.delete-descibe {
|
||||
.content-descibe {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
line-height: 33px;
|
||||
|
@ -53,4 +53,11 @@
|
|||
border-color: #df0002;
|
||||
}
|
||||
}
|
||||
.ant-btn-default:hover,
|
||||
.ant-btn-default:active,
|
||||
.ant-btn-default:focus {
|
||||
background: #f3f4f6;
|
||||
color: #333;
|
||||
border-color: #d0d0d0;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue