Merge pull request '修改头像的bug,提取copyUrl组件,优化函数式模态框组件' (#20) from tongChong/forgeplus-react:feature_wikis into pre_develop_dev

This commit is contained in:
baladiwei 2021-08-23 11:47:44 +08:00
commit 39fef1ce3c
8 changed files with 104 additions and 171 deletions

View File

@ -0,0 +1,44 @@
import React, { useState, useCallback, memo } from 'react';
import { Tooltip } from 'antd';
CopyTool.defaultProps = {
beforeText: '复制', //
afterText: '复制成功', //
className: '', //svgclass
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);

View File

@ -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 { Button, Dropdown, Icon, Input, Menu, Tooltip, Select, Upload, message, Spin } from 'antd';
import { getImageUrl, timeAgo } from 'educoder'; import { getImageUrl, timeAgo } from 'educoder';
import cookie from 'react-cookies'; import cookie from 'react-cookies';
// import Loading from "../../Loading"; import CopyTool from '../Component/CopyTool';
import DelModal from './components/ModalFun'; import DelModal from './components/ModalFun';
import Welcome from './Welcome'; import Welcome from './Welcome';
import { wikiPages, getWiki, deleteWiki } from './api'; import { wikiPages, getWiki, deleteWiki } from './api';
@ -14,15 +14,12 @@ const InputGroup = Input.Group;
const { Option } = Select; const { Option } = Select;
export default (props) => { export default (props) => {
const { match, current_user, history, showNotification, project, projectDetail } = props; const { match, history, showNotification, project, projectDetail } = props;
// const permission = projectDetail && projectDetail.permission !== "Reporter";
const permission = projectDetail && projectDetail.permission && projectDetail.permission !== "Reporter"; const permission = projectDetail && projectDetail.permission && projectDetail.permission !== "Reporter";
let projectsId = match.params.projectsId; let projectsId = match.params.projectsId;
let owner = match.params.owner; let owner = match.params.owner;
console.log(project);
const [fileArrInit, setFileArrInit] = useState(null); const [fileArrInit, setFileArrInit] = useState(null);
const [checkItem, setCheckItem] = useState({}); const [checkItem, setCheckItem] = useState({});
const [itemDetail, setItemDetail] = useState({}); const [itemDetail, setItemDetail] = useState({});
@ -85,7 +82,7 @@ export default (props) => {
DelModal({ DelModal({
title: '删除页面', title: '删除页面',
contentTitle: `您确定要删除“${item.name}”此页面吗?`, contentTitle: `您确定要删除“${item.name}”此页面吗?`,
content: '此操作将删除该页面,请进行确认以防文件的丢失', content: '此操作将删除该页面,请进行确认以防文件的丢失',
onOk: () => { onOk: () => {
deleteWiki({ deleteWiki({
owner: owner, owner: owner,
@ -109,17 +106,6 @@ export default (props) => {
window.location.href = `/users/${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() { function addFile() {
history.push(`/projects/${owner}/${projectsId}/wiki/add`); history.push(`/projects/${owner}/${projectsId}/wiki/add`);
} }
@ -231,6 +217,7 @@ export default (props) => {
<Button type="default" className="ml10">导出<Icon type="caret-down" /></Button> <Button type="default" className="ml10">导出<Icon type="caret-down" /></Button>
</Dropdown> </Dropdown>
<Button type="default" className="ml10" onClick={preview}>预览</Button> <Button type="default" className="ml10" onClick={preview}>预览</Button>
</div> </div>
</div> </div>
@ -246,8 +233,8 @@ export default (props) => {
{ {
fileArr.map(item => { fileArr.map(item => {
return <div className="wiki-nav-title-parent"> return <div className="wiki-nav-title-parent" key={item.name}>
<div className={`wiki-nav-title ${item.name === checkItem.name ? 'active' : ''}`} key={item.name} onClick={() => { setCheckItem(item) }}> <div className={`wiki-nav-title ${item.name === checkItem.name ? 'active' : ''}`} onClick={() => { setCheckItem(item) }}>
<div className="nav-title-left"> <div className="nav-title-left">
<i className="iconfont icon-wenjianjia2 mr3"></i> <i className="iconfont icon-wenjianjia2 mr3"></i>
<span className="nav-title-left-text">{item.name}</span> <span className="nav-title-left-text">{item.name}</span>
@ -266,9 +253,7 @@ export default (props) => {
<Option value="SSH">SSH</Option> <Option value="SSH">SSH</Option>
</Select> </Select>
<Input id="wikiUrl" value={urlType === 'HTTPS' ? checkItem.wiki_clone_link.https : checkItem.wiki_clone_link.ssh} /> <Input id="wikiUrl" value={urlType === 'HTTPS' ? checkItem.wiki_clone_link.https : checkItem.wiki_clone_link.ssh} />
<Tooltip placement="bottom" title={'复制'}> <CopyTool className="copy-wiki" inputId="wikiUrl" />
<i className="iconfont icon-fuzhiicon copy-svg" onClick={copyUrl}></i>
</Tooltip>
</InputGroup>} </InputGroup>}
</div> </div>
@ -277,9 +262,9 @@ export default (props) => {
<div className="wiki-content-head"> <div className="wiki-content-head">
<div className="wiki-content-head-left"> <div className="wiki-content-head-left">
<h3 className="wiki-detail-title">{checkItem.name}</h3> <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}`)} />} {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>
<span className="time-ago">上次修改于{checkItem.commit && timeAgo(checkItem.commit.author.when)}</span> <span className="time-ago">上次修改于{checkItem.commit && timeAgo(checkItem.commit.author.when)}</span>
</div> </div>

View File

@ -199,7 +199,7 @@ body {
word-break: break-all; word-break: break-all;
} }
.copy-svg { .copy-wiki {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;

View File

@ -1,5 +1,6 @@
import React, { useEffect, useCallback, useState } from 'react'; 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 { wikiPages, getWiki, } from './api';
import { httpUrl } from './fetch'; import { httpUrl } from './fetch';
import './Index.scss'; import './Index.scss';
@ -59,16 +60,6 @@ export default (props) => {
}); });
}, [project, checkItem]); }, [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() { function goEdit() {
history.push(`/projects/${owner}/${projectsId}/wiki/edit/${checkItem.name}`); history.push(`/projects/${owner}/${projectsId}/wiki/edit/${checkItem.name}`);
} }
@ -113,9 +104,7 @@ export default (props) => {
<Option value="SSH">SSH</Option> <Option value="SSH">SSH</Option>
</Select> </Select>
<Input id="wikiUrl" value={urlType === 'HTTPS' ? checkItem.wiki_clone_link.https : checkItem.wiki_clone_link.ssh} /> <Input id="wikiUrl" value={urlType === 'HTTPS' ? checkItem.wiki_clone_link.https : checkItem.wiki_clone_link.ssh} />
<Tooltip placement="bottom" title={'复制'}> <CopyTool className="copy-wiki" inputId="wikiUrl"/>
<i className="iconfont icon-fuzhiicon copy-svg" onClick={copyUrl}></i>
</Tooltip>
</InputGroup> </InputGroup>
} }

View File

@ -1,10 +1,9 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import * as ReactDOM from 'react-dom'; import * as ReactDOM from 'react-dom';
import LoginDialog from '../../../../modules/login/LoginDialog'; import LoginDialog from '../../../../modules/login/LoginDialog';
import './index.scss';
// 使 // 使
export default function DelModal(props) { export default function Login(props) {
const div = document.createElement('div'); const div = document.createElement('div');
document.body.appendChild(div); document.body.appendChild(div);
@ -16,9 +15,6 @@ export default function DelModal(props) {
} }
function render() { function render() {
/**
* Sync render blocks React event. Let's make this async.
*/
setTimeout(() => { setTimeout(() => {
ReactDOM.render( ReactDOM.render(
<MyLoginDialog afterClose={destroy} /> <MyLoginDialog afterClose={destroy} />

View File

@ -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;
}
}
}

View File

@ -1,23 +1,33 @@
/* eslint-disable react/jsx-no-duplicate-props */
import React, { useState } from 'react'; import React, { useState } from 'react';
import * as ReactDOM from 'react-dom'; import * as ReactDOM from 'react-dom';
import { Modal, Button } from 'antd'; import { Modal, Button } from 'antd';
import './index.scss'; import './index.scss';
InitModal.defaultProps = {
okText: '确认', //
cancelText: '取消', //
className: '', //
inputId: 'copyText', //ID
};
// 使 // 使
export default function DelModal(props) { export default function DelModal(props) {
renderModal({ ...props, type: 'delete' }) renderModal({ ...props, type: 'delete' })
} }
export function confirmModal(props) { // 使
export function Confirm(props) {
renderModal({ ...props, type: 'confirm' }) renderModal({ ...props, type: 'confirm' })
} }
function renderModal(props) { function renderModal(props) {
const type = props.type; const { type, afterClose } = props;
const div = document.createElement('div'); const div = document.createElement('div');
document.body.appendChild(div); document.body.appendChild(div);
function destroy() { function destroy() {
afterClose && afterClose();
const unmountResult = ReactDOM.unmountComponentAtNode(div); const unmountResult = ReactDOM.unmountComponentAtNode(div);
if (unmountResult && div.parentNode) { if (unmountResult && div.parentNode) {
div.parentNode.removeChild(div); div.parentNode.removeChild(div);
@ -26,18 +36,26 @@ function renderModal(props) {
function modalType(type) { function modalType(type) {
if (type === 'delete') { 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') { } else if (type === 'confirm') {
return <ConfirmModal title="选择" afterClose={destroy} {...props} /> return <InitModal title="选择" afterClose={destroy} {...props} />
} else { } else {
return <ConfirmModal title="选择" afterClose={destroy} {...props} /> return <InitModal title="选择" afterClose={destroy} {...props} />
} }
} }
function render() { function render() {
/**
* Sync render blocks React event. Let's make this async.
*/
setTimeout(() => { setTimeout(() => {
ReactDOM.render( ReactDOM.render(
modalType(type), modalType(type),
@ -48,16 +66,17 @@ function renderModal(props) {
render(); render();
} }
// //
function DeleteModal({ function InitModal({
onCancel, onCancel,
onOk, onOk,
title, title,
contentTitle, contentTitle,
content, content,
afterClose,
okText, okText,
cancelText, cancelText,
afterClose,
className,
}) { }) {
const [visible, setVisible] = useState(true); const [visible, setVisible] = useState(true);
@ -78,71 +97,20 @@ function DeleteModal({
onCancel={onCancelModal} onCancel={onCancelModal}
afterClose={afterClose} afterClose={afterClose}
title={title} title={title}
className="myself-modal" className={`myself-modal ${className}`}
centered centered
footer={[ footer={[
<Button key="back" onClick={onCancelModal}> <Button type="default" key="back" onClick={onCancelModal}>
{cancelText||'取消'} {cancelText}
</Button>, </Button>,
<Button className="foot-submit" key="submit" onClick={onSuccess}> <Button className="foot-submit" key="submit" onClick={onSuccess}>
{okText||'确认删除'} {okText}
</Button>, </Button>,
]} ]}
> >
<div> <div>
<p className="delete-title"> {contentTitle && <p className="content-title">{contentTitle}</p>}
<i className="red-circle iconfont icon-shanchu_tc_icon mr3"></i> <p className="content-descibe">{content}</p>
{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>
</div> </div>
</Modal> </Modal>
) )

View File

@ -16,7 +16,7 @@
.ant-modal-body { .ant-modal-body {
text-align: center; text-align: center;
} }
.delete-title { .content-title {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
@ -32,7 +32,7 @@
color: #ca0002; color: #ca0002;
font-size: 1.5rem !important; font-size: 1.5rem !important;
} }
.delete-descibe { .content-descibe {
font-size: 14px; font-size: 14px;
color: #666; color: #666;
line-height: 33px; line-height: 33px;
@ -53,4 +53,11 @@
border-color: #df0002; border-color: #df0002;
} }
} }
.ant-btn-default:hover,
.ant-btn-default:active,
.ant-btn-default:focus {
background: #f3f4f6;
color: #333;
border-color: #d0d0d0;
}
} }