forked from Gitlink/forgeplus-react
pull upstream pre_develop_dev
This commit is contained in:
commit
1750544c0d
|
@ -7286,8 +7286,7 @@
|
|||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
||||
"optional": true
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
|
@ -7704,8 +7703,7 @@
|
|||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"optional": true
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
|
@ -7761,7 +7759,6 @@
|
|||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
|
@ -7805,14 +7802,12 @@
|
|||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"optional": true
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
||||
"optional": true
|
||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -125,7 +125,11 @@
|
|||
"scripts": {
|
||||
"start": "node --max_old_space_size=15360 scripts/start.js",
|
||||
"build": "cross-env NODE_ENV=production node --max_old_space_size=15360 scripts/build.js",
|
||||
<<<<<<< HEAD
|
||||
"test-build": "cross-env NODE_ENV=testBuild node --max_old_space_size=15360 scripts/build.js",
|
||||
=======
|
||||
"test-build": "NODE_ENV=testBuild node --max_old_space_size=15360 scripts/build.js",
|
||||
>>>>>>> 9be808e37f9c52698b7861d74cd537e356aafb6d
|
||||
"pre-build": "NODE_ENV=preBuild node --max_old_space_size=15360 scripts/build.js",
|
||||
"gen_stats": "NODE_ENV=production webpack --profile --config=./config/webpack.config.prod.js --json > stats.json",
|
||||
"ana": "webpack-bundle-analyzer ./stats.json",
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2340181 */
|
||||
<<<<<<< HEAD
|
||||
src: url('iconfont.woff2?t=1632881251448') format('woff2'),
|
||||
url('iconfont.woff?t=1632881251448') format('woff'),
|
||||
url('iconfont.ttf?t=1632881251448') format('truetype');
|
||||
=======
|
||||
src: url('iconfont.woff2?t=1631773579834') format('woff2'),
|
||||
url('iconfont.woff?t=1631773579834') format('woff'),
|
||||
url('iconfont.ttf?t=1631773579834') format('truetype');
|
||||
>>>>>>> 9be808e37f9c52698b7861d74cd537e356aafb6d
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
|
@ -13,6 +19,7 @@
|
|||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
.icon-wenjian7:before {
|
||||
content: "\e8e0";
|
||||
}
|
||||
|
@ -37,6 +44,8 @@
|
|||
content: "\e8db";
|
||||
}
|
||||
|
||||
=======
|
||||
>>>>>>> 9be808e37f9c52698b7861d74cd537e356aafb6d
|
||||
.icon-xiangmubiaoqian:before {
|
||||
content: "\e8da";
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -6,6 +6,7 @@
|
|||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
"icon_id": "24656750",
|
||||
"name": "文件",
|
||||
"font_class": "wenjian7",
|
||||
|
@ -48,6 +49,8 @@
|
|||
"unicode_decimal": 59611
|
||||
},
|
||||
{
|
||||
=======
|
||||
>>>>>>> 9be808e37f9c52698b7861d74cd537e356aafb6d
|
||||
"icon_id": "24378423",
|
||||
"name": "项目标签",
|
||||
"font_class": "xiangmubiaoqian",
|
||||
|
|
|
@ -3319,9 +3319,9 @@
|
|||
text = text.replace(emailReg, function ($1, $2, $3, $4) {
|
||||
return $1.replace(/@/g, "_#_@_#_");
|
||||
});
|
||||
|
||||
// " + editormd.urls.atLinkBase + "" + $2 + "
|
||||
text = text.replace(atLinkReg, function ($1, $2) {
|
||||
return "<a href=\"" + editormd.urls.atLinkBase + "" + $2 + "\" title=\"@" + $2 + "\" class=\"at-link\">" + $1 + "</a>";
|
||||
return "<span title=\"@" + $2 + "\" class=\"at-link\"> " + $1 + " </span>";
|
||||
}).replace(/_#_@_#_/g, "@");
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/* 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
|
||||
onCancel:()=>{}, //取消的回调
|
||||
onOk:()=>{}, //确认的回调
|
||||
title:'提示', //模态框名字
|
||||
contentTitle:'', //内容标题
|
||||
content:'', //详细内容
|
||||
afterClose:()=>{}, //关闭模态框以后的回调
|
||||
};
|
||||
|
||||
// 使用函数调用删除组件
|
||||
export default function DelModal(props) {
|
||||
renderModal({ ...props, type: 'delete' })
|
||||
}
|
||||
|
||||
// 使用函数调用选择模态框组件
|
||||
export function Confirm(props) {
|
||||
renderModal({ ...props, type: 'confirm' })
|
||||
}
|
||||
|
||||
function renderModal(props) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
function modalType(type) {
|
||||
if (type === 'delete') {
|
||||
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 <InitModal title="选择" afterClose={destroy} {...props} />
|
||||
} else {
|
||||
return <InitModal title="选择" afterClose={destroy} {...props} />
|
||||
}
|
||||
}
|
||||
|
||||
function render() {
|
||||
setTimeout(() => {
|
||||
ReactDOM.render(
|
||||
modalType(type),
|
||||
div,
|
||||
);
|
||||
});
|
||||
}
|
||||
render();
|
||||
}
|
||||
|
||||
// 选择模态框组件
|
||||
function InitModal({
|
||||
onCancel,
|
||||
onOk,
|
||||
title,
|
||||
contentTitle,
|
||||
content,
|
||||
okText,
|
||||
cancelText,
|
||||
afterClose,
|
||||
className,
|
||||
}) {
|
||||
|
||||
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 ${className}`}
|
||||
centered
|
||||
footer={[
|
||||
<Button type="default" key="back" onClick={onCancelModal}>
|
||||
{cancelText}
|
||||
</Button>,
|
||||
<Button className="foot-submit" key="submit" onClick={onSuccess}>
|
||||
{okText}
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<div>
|
||||
{contentTitle && <p className="content-title">{contentTitle}</p>}
|
||||
<p className="content-descibe">{content}</p>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
.myself-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;
|
||||
}
|
||||
.content-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;
|
||||
}
|
||||
.content-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;
|
||||
}
|
||||
}
|
||||
.ant-btn-default:hover,
|
||||
.ant-btn-default:active,
|
||||
.ant-btn-default:focus {
|
||||
background: #f3f4f6;
|
||||
color: #333;
|
||||
border-color: #d0d0d0;
|
||||
}
|
||||
}
|
|
@ -27,7 +27,11 @@ function Releases({owner,projectsId,releaseVersions , baseOperate , projectType}
|
|||
})
|
||||
:
|
||||
<div className="mt8">
|
||||
<<<<<<< HEAD
|
||||
您暂未发布任何版本{baseOperate && projectType !==2 && <Link className="color-blue ml20" to={{pathname:`/${owner}/${projectsId}/releases/new`,state:{stable:true}}}>创建新版本</Link>}
|
||||
=======
|
||||
您暂未发布任何版本{baseOperate && projectType !==2 && <Link className="color-blue ml20" to={`/${owner}/${projectsId}/releases/new`}>创建新版本</Link>}
|
||||
>>>>>>> 9be808e37f9c52698b7861d74cd537e356aafb6d
|
||||
</div>
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Icon } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import Nodata from '../Nodata';
|
||||
|
||||
|
||||
class PullRefresh extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
}
|
||||
this.pullRef = {};
|
||||
// 节流
|
||||
this.onScrollList = _.throttle(this.handleScroll, 200, {
|
||||
leading: false,
|
||||
trailing: true,
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
let dom = document.querySelector('.pull-refresh-wrap');
|
||||
dom && dom.addEventListener('scroll', this.onScrollList);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
let dom = document.querySelector('.pull-refresh-wrap');
|
||||
dom && dom.removeEventListener('scroll', this.onScrollList)
|
||||
}
|
||||
|
||||
|
||||
handleScroll = () => {
|
||||
if (this.props.count < this.props.pageSize) return;
|
||||
if (this.props.type === 1 || this.props.type === 2) return;
|
||||
const wrap = this.pullRef;
|
||||
const currentScroll = wrap.scrollTop + wrap.clientHeight
|
||||
|
||||
// 触底
|
||||
if (currentScroll >= (wrap.scrollHeight - 200)) {
|
||||
this.loadData()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
handleLoadClick = () => {
|
||||
this.loadData();
|
||||
}
|
||||
|
||||
loadData = () => {
|
||||
this.props.onPullRefresh()
|
||||
}
|
||||
|
||||
|
||||
renderLoading() {
|
||||
switch (this.props.type) {
|
||||
case 0: // 加载更多
|
||||
return <div className='text-center' onClick={this.handleLoadClick}>显示更多</div>
|
||||
case 1: // 加载中
|
||||
return (
|
||||
<div className='text-center'>
|
||||
<Icon type="loading" />
|
||||
<span className='text-center'>加载中...</span>
|
||||
</div>
|
||||
)
|
||||
case 2: // 无样式
|
||||
return <div className='text-center'>没有更多了</div>
|
||||
default:
|
||||
return <div className='text-center'>没有更多了</div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const { className, count, children } = this.props;
|
||||
return (
|
||||
<div
|
||||
className={`pull-refresh-wrap ${className}`}
|
||||
ref={dom => { this.pullRef = dom }}
|
||||
>
|
||||
|
||||
{children}
|
||||
|
||||
{
|
||||
count < 1 && <Nodata _html="暂无未读消息"/>
|
||||
}
|
||||
|
||||
{/* 大于分页数据才显示loading */}
|
||||
{/* {this.props.count >= this.props.pageSize ? this.renderLoading() : null} */}
|
||||
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
PullRefresh.propTypes = {
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.any,
|
||||
onPullRefresh: PropTypes.func.isRequired,
|
||||
type: PropTypes.oneOf([0, 1, 2]),
|
||||
count: PropTypes.number.isRequired,
|
||||
pageSize: PropTypes.number.isRequired,
|
||||
}
|
||||
|
||||
|
||||
export default PullRefresh
|
|
@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
|||
import AccountProfile from "../../modules/user/AccountProfile";
|
||||
import { getImageUrl } from 'educoder'
|
||||
import axios from 'axios';
|
||||
import { Input , notification , Dropdown , Menu } from 'antd';
|
||||
import { Input , notification , Dropdown ,Popover, Menu,Badge, Button } from 'antd';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import LoginDialog from '../../modules/login/LoginDialog';
|
||||
|
@ -13,6 +13,7 @@ import '../../modules/tpm/TPMIndex.css';
|
|||
import CheckProfile from '../Component/ProfileModal/Profile';
|
||||
|
||||
import './header.scss';
|
||||
import NoticeContent from './NoticeContent';
|
||||
const $ = window.$
|
||||
// TODO 这部分脚本从公共脚本中直接调用
|
||||
const { Search } = Input;
|
||||
|
@ -47,6 +48,7 @@ class NewHeader extends Component {
|
|||
settings: null,
|
||||
visiblemyss: false,
|
||||
openSearch:false,
|
||||
visible:false, //浮动消息框展示控制
|
||||
}
|
||||
}
|
||||
componentDidMount() {
|
||||
|
@ -92,9 +94,6 @@ class NewHeader extends Component {
|
|||
this.setState({
|
||||
user: newProps.user
|
||||
})
|
||||
if (newProps.Headertop !== undefined) {
|
||||
old_url = newProps.Headertop.old_url
|
||||
}
|
||||
}
|
||||
|
||||
educoderlogin = () => {
|
||||
|
@ -255,6 +254,7 @@ class NewHeader extends Component {
|
|||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderMenu=(personal)=>{
|
||||
const { current_user } = this.props;
|
||||
return(
|
||||
|
@ -275,8 +275,12 @@ class NewHeader extends Component {
|
|||
)
|
||||
}
|
||||
|
||||
handleVisibleChange = visible => {
|
||||
this.setState({ visible });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { match} = this.props;
|
||||
const { match ,resetUserInfo ,showNotification} = this.props;
|
||||
let current_user = this.props.user;
|
||||
let {
|
||||
AccountProfiletype,
|
||||
|
@ -285,6 +289,7 @@ class NewHeader extends Component {
|
|||
headtypesonClickbool,
|
||||
headtypess,
|
||||
settings,
|
||||
visible,
|
||||
} = this.state;
|
||||
/*用户名称 用户头像url*/
|
||||
let activeIndex = false;
|
||||
|
@ -395,7 +400,7 @@ class NewHeader extends Component {
|
|||
{
|
||||
settings.navbar && settings.navbar.map((item, key) => {
|
||||
var new_link = item.link;
|
||||
var user_login = this.props.user && this.props.user.login;
|
||||
var user_login = current_user && current_user.login;
|
||||
var is_hidden = item.hidden
|
||||
if (new_link && (new_link.indexOf("courses") > -1 || new_link.indexOf("contests") > -1)) {
|
||||
if (user_login) {
|
||||
|
@ -426,25 +431,30 @@ class NewHeader extends Component {
|
|||
}
|
||||
</div>
|
||||
<div className="head-right">
|
||||
{/* {search_url ? this.SearchInput(openSearch,search_url):""} */}
|
||||
{ search_url && <HeadSearch {...this.props}/>}
|
||||
{
|
||||
current_user && (current_user.main_site || current_user.login) && (settings && settings.add && settings.add.length>0)?
|
||||
<Dropdown overlay={this.addMenu(settings && settings.add)} placement="bottomRight">
|
||||
<i className="iconfont icon-tianjiafangda color-grey-6 ml30"></i>
|
||||
<i className="iconfont icon-tianjiafangda color-grey-6 ml30 mr15"></i>
|
||||
</Dropdown>:""
|
||||
}
|
||||
|
||||
{this.props.user && this.props.user.login && notice_url ?
|
||||
<div className="ml30 edu-menu-panel">
|
||||
{user && user.login &&
|
||||
<a href={`${notice_url}`} style={{ position: 'relative' }}>
|
||||
<i className="iconfont icon-xiaoxilingdang color-grey-6"></i>
|
||||
<span className="newslight" style={{ display: this.props.Headertop === undefined ? "none" : this.props.Headertop.new_message === true ? "block" : "none" }}>
|
||||
</span>
|
||||
</a>
|
||||
}
|
||||
</div>:""
|
||||
{current_user && current_user.login ?
|
||||
<Popover
|
||||
overlayClassName="notice-popover"
|
||||
placement={`bottomRight`}
|
||||
content={<NoticeContent visible={visible} current_user={current_user} showNotification={showNotification} resetUserInfo={resetUserInfo}/>}
|
||||
visible={visible}
|
||||
onVisibleChange={this.handleVisibleChange}
|
||||
destroyTooltipOnHide
|
||||
>
|
||||
<Link to={"/settings/notice"} className="message-icon">
|
||||
<Badge count={current_user.message_unread_total}>
|
||||
<i className="iconfont icon-xiaoxilingdang color-grey-6 ml15 mr15"></i>
|
||||
</Badge>
|
||||
</Link>
|
||||
</Popover>
|
||||
: ""
|
||||
}
|
||||
</div>
|
||||
{!user || (user && !user.login) ?
|
||||
|
|
|
@ -0,0 +1,262 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Badge, Menu } from 'antd';
|
||||
import { Link } from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
import AppPullRefresh from './AppPullRefresh';
|
||||
import { noticeSourceType } from '../common/static';
|
||||
import './header.scss';
|
||||
import '../SecuritySetting/notice/manager/Index.scss';
|
||||
import '../SecuritySetting/Index.scss';
|
||||
import '../SecuritySetting/notice/myNotice/Index.scss';
|
||||
|
||||
|
||||
function NoticeContent({ visible, showNotification, resetUserInfo, current_user: { login } }) {
|
||||
const [initialize, setInitialize] = useState(true);
|
||||
const [noticeType, setNoticeType] = useState("notification");
|
||||
const [letterUnreadCount, setLetterUnreadCount] = useState(0);//未读私信数量
|
||||
|
||||
const [noticeUnreadCount, setNoticeUnreadCount] = useState(0);//未读系统通知数量
|
||||
const [noticePage, setNoticePage] = useState(0);
|
||||
const [noticeUnreadList, setNoticeUnreadList] = useState([]);//未读系统通知列表
|
||||
|
||||
const [atUnreadCount, setAtUnreadCount] = useState();//未读@我数量
|
||||
const [atPage, setAtPage] = useState(0);
|
||||
const [atUnreadList, setAtUnreadList] = useState([]);//未读@我列表
|
||||
|
||||
useEffect(() => {
|
||||
resetUserInfo();
|
||||
}, [noticeUnreadCount,atUnreadCount]);
|
||||
|
||||
useEffect(()=>{
|
||||
setNoticePage(0);
|
||||
setAtPage(0);
|
||||
},[visible])
|
||||
|
||||
useEffect(() => {
|
||||
const params = {
|
||||
type: noticeType,
|
||||
limit: 10,
|
||||
page: noticeType === "notification" ? noticePage : noticeType === "atme" ? atPage : "",
|
||||
status: 1,
|
||||
}
|
||||
getMessageList(params);
|
||||
}, [noticePage, atPage]);
|
||||
|
||||
useEffect(() => {
|
||||
const params = {
|
||||
type: noticeType,
|
||||
limit: 10,
|
||||
page: 0,
|
||||
status: 1,
|
||||
};
|
||||
if (initialize) {
|
||||
params.type = "atme"
|
||||
}
|
||||
visible && getMessageList(params);
|
||||
}, [visible]);
|
||||
|
||||
|
||||
function getMessageList(params) {
|
||||
axios.get(`/users/${login}/messages.json`, {
|
||||
params: params,
|
||||
}).then((response) => {
|
||||
if (response && response.data) {
|
||||
setNoticeUnreadCount(response.data.unread_notification);
|
||||
setAtUnreadCount(response.data.unread_atme);
|
||||
if (params.type === "notification") {
|
||||
let list = response.data.messages;
|
||||
if (params.page !== 0) {
|
||||
list = [...noticeUnreadList, ...list];
|
||||
}
|
||||
setNoticeUnreadList(list);
|
||||
if (initialize) {
|
||||
// 如果是第一次加载,根据数据量判断是否切换tab栏
|
||||
setInitialize(false);
|
||||
if (response.data.unread_notification === 0 && response.data.unread_atme !== 0) {
|
||||
setNoticeType("atme");
|
||||
}
|
||||
}
|
||||
} else if (params.type === "atme") {
|
||||
let list = response.data.messages;
|
||||
if (params.page !== 0) {
|
||||
list = [...atUnreadList, ...list];
|
||||
}
|
||||
setAtUnreadList(list);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function readAll() {
|
||||
axios.post(`/users/${login}/messages/read.json`, {
|
||||
type: noticeType,
|
||||
ids: [-1]
|
||||
}).then((response) => {
|
||||
let data = response.data;
|
||||
if (!data) return;
|
||||
if (data.status === 0) {
|
||||
changeReadMarkAll(noticeType);
|
||||
} else {
|
||||
showNotification(data.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function changeReadMarkAll(noticeType) {
|
||||
if (noticeType === "notification") {
|
||||
let list = noticeUnreadList.slice();
|
||||
list.forEach(item => {
|
||||
item.status = 2;
|
||||
})
|
||||
setNoticeUnreadList(list);
|
||||
setNoticeUnreadCount(0);
|
||||
} else if (noticeType === "atme") {
|
||||
let list = atUnreadList.slice();
|
||||
list.forEach(item => {
|
||||
item.status = 2;
|
||||
})
|
||||
setAtUnreadList(list);
|
||||
setAtUnreadCount(0);
|
||||
}
|
||||
}
|
||||
|
||||
// const [letter_unread_list, setLetter_unread_list] = useState([
|
||||
// {
|
||||
// id: 122,
|
||||
// read: 0, //是否已读,0未读,1已读
|
||||
// send_name: "蒋宇航", //消息发送人
|
||||
// send_login: "jiangYuHang", //消息发送人的login,前端根据这个跳转到消息内页
|
||||
// content: "私信内容", //最近一条未读消息的内容
|
||||
// create_time: "2019-03-04 18:08", //发送时间
|
||||
// },
|
||||
// ]);
|
||||
|
||||
function readItem(item) {
|
||||
axios.post(`/users/${login}/messages/read.json`, {
|
||||
type: noticeType,
|
||||
ids: [item.id]
|
||||
}).then((response) => {
|
||||
let data = response.data;
|
||||
if (!data) return;
|
||||
if (data.status === 0) {
|
||||
changeReadMark(item);
|
||||
item.notification_url && window.open(item.notification_url);
|
||||
} else {
|
||||
showNotification(data.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function changeReadMark(item) {
|
||||
if (item.type === "notification") {
|
||||
let list = noticeUnreadList.slice();
|
||||
let index = noticeUnreadList.indexOf(item);
|
||||
list[index].status = 2;
|
||||
setNoticeUnreadList(list);
|
||||
if (noticeUnreadCount > 0) {
|
||||
setNoticeUnreadCount(noticeUnreadCount - 1);
|
||||
}
|
||||
} else if (item.type === "atme") {
|
||||
let list = atUnreadList.slice();
|
||||
let index = atUnreadList.indexOf(item);
|
||||
list[index].status = 2;
|
||||
setAtUnreadList(list);
|
||||
if (atUnreadCount > 0) {
|
||||
setAtUnreadCount(atUnreadCount - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="messageHoverDiv notice01">
|
||||
<div className="sshHead hoverNotice-head">
|
||||
<Menu mode="horizontal" selectedKeys={noticeType} onClick={(e) => setNoticeType(e.key)}>
|
||||
<Menu.Item key="notification"><Badge count={noticeUnreadCount}>系统通知</Badge></Menu.Item>
|
||||
{/* <Menu.Item key="1" id="item-private"><Badge count={letterUnreadCount}>私信</Badge></Menu.Item> */}
|
||||
<Menu.Item key="atme"><Badge count={atUnreadCount}>@我</Badge></Menu.Item>
|
||||
</Menu>
|
||||
</div>
|
||||
|
||||
{/* 系统通知 */}
|
||||
{noticeType === "notification" && <AppPullRefresh
|
||||
className='hoverNotice-body' // 外部添加className加以区分
|
||||
onPullRefresh={() => { setNoticePage(noticePage + 1); }} //触发加载ajax的function
|
||||
// type={2} // 传送加载组件的状态
|
||||
count={noticeUnreadList.length} // 数据当前的总数量
|
||||
pageSize={10} //
|
||||
>
|
||||
{
|
||||
noticeUnreadList.map(item => {
|
||||
return (
|
||||
<div key={item.id + Math.random()} className="noticeCont-back" onClick={() => { readItem(item) }}>
|
||||
<div className={`noticeCont ${item.notification_url?'pointer':''}`}>
|
||||
<span style={{ visibility: item.status === 1 ? 'visible' : 'hidden' }}>
|
||||
<Badge color="#FA2020" />
|
||||
</span>
|
||||
<i className={"iconfont " + noticeSourceType[item.source]}></i>
|
||||
<div className="noticeCont-text">
|
||||
<span className="content-span notice-cont-span" dangerouslySetInnerHTML={{ __html: item.content }}></span>
|
||||
<span className="timeSpan">{item.time_ago}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</AppPullRefresh>
|
||||
}
|
||||
|
||||
{/* @我 */}
|
||||
{noticeType === "atme" && <AppPullRefresh
|
||||
className='hoverNotice-body' // 外部添加className加以区分
|
||||
onPullRefresh={() => { setAtPage(atPage + 1); }} //触发加载ajax的function
|
||||
// type={1} // 传送加载组件的状态
|
||||
count={atUnreadList.length} // 数据当前的总数量
|
||||
pageSize={10} //
|
||||
>
|
||||
{atUnreadList.map(item => {
|
||||
return (
|
||||
<div key={item.id + Math.random()} className="noticeCont-back" onClick={() => { readItem(item) }}>
|
||||
<div className="noticeCont">
|
||||
<span style={{ visibility: item.status === 1 ? 'visible' : 'hidden' }}>
|
||||
<Badge color="#FA2020" />
|
||||
</span>
|
||||
<div className="noticeCont-text">
|
||||
<span className="content-span atme-cont-span" dangerouslySetInnerHTML={{ __html: "<b>" + (item.sender ? item.sender.name : '') + "</b> " + item.content + " 中@我" }}></span>
|
||||
<span className="timeSpan">{item.time_ago}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</AppPullRefresh>
|
||||
}
|
||||
|
||||
{/* 私信 */}
|
||||
{/* {noticeType === "1" ? letter_unread_list.length > 0 ? letter_unread_list.map(item => {
|
||||
return (
|
||||
<div className="noticeCont-back">
|
||||
<div className="noticeCont" style={{ height: item.content.length >= 30 && item.content.length <= 34 ? '65px' : "" }}>
|
||||
<Badge color="#FA2020" />
|
||||
<div className="noticeCont-text">
|
||||
<span>{item.send_name}:</span>
|
||||
<span className="boldSpan" dangerouslySetInnerHTML={{ __html: item.content.length >= 50 ? item.content.substr(0, 50) + "..." : item.content }}></span>
|
||||
<span className="timeSpan">{item.create_time ? timeAgo(item.create_time) : "刚刚"}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}) : "暂无数据" : ""} */}
|
||||
<div className="hoverNotice-buttom">
|
||||
<Link to={{pathname:"/settings/notice",query:{noticeType:noticeType}}}>全部消息</Link>
|
||||
{noticeUnreadCount > 0 && noticeType === "notification" && <a onClick={readAll}>所有系统消息一键已读</a>}
|
||||
{atUnreadCount > 0 && noticeType === "atme" && <a onClick={readAll}>所有@我一键已读</a>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
export default NoticeContent;
|
|
@ -24,8 +24,9 @@
|
|||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 50%;
|
||||
margin-left: 30px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.currentMenu{
|
||||
width: 120px;
|
||||
text-align: center;
|
||||
|
@ -126,4 +127,139 @@
|
|||
width: 110px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
// 右上角小铃铛单独样式
|
||||
.notice-popover{
|
||||
//popover小尖尖
|
||||
.ant-popover-arrow{
|
||||
display: none;
|
||||
}
|
||||
|
||||
//popover框
|
||||
.ant-popover-inner-content {
|
||||
width: 386px;
|
||||
height: 446px;
|
||||
box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5);
|
||||
border-radius: 4px;
|
||||
margin-top: -10px;
|
||||
padding: 12px 1px 12px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.messageHoverDiv .ant-menu-item{
|
||||
margin-right: 24px !important;
|
||||
}
|
||||
|
||||
.hoverNotice-head{
|
||||
margin-left: 18px;
|
||||
|
||||
& .ant-badge{
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
&>.ant-menu-horizontal {
|
||||
border-bottom: 1px solid #e8e8e8 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.hoverNotice-body{
|
||||
height: 342px;
|
||||
overflow-y: scroll;
|
||||
|
||||
& b{
|
||||
font-weight: 400;
|
||||
text-shadow: 0.5px 0 0 #333;
|
||||
}
|
||||
|
||||
.none_panels{
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.message-icon{
|
||||
position: relative;
|
||||
.ant-scroll-number{
|
||||
right:12px;
|
||||
padding: 0 0px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.hoverNotice-buttom{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 12px 18px;
|
||||
a{
|
||||
color: #466AFF;
|
||||
&:hover{
|
||||
opacity:0.85;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.noticeCont-back{
|
||||
.pointer{
|
||||
cursor: pointer;
|
||||
}
|
||||
&:hover{
|
||||
background: #F3F4F6;
|
||||
}
|
||||
}
|
||||
|
||||
.noticeCont{
|
||||
display: flex;
|
||||
margin: 0 16px 0 18px;
|
||||
padding: 12px 0 10px 0;
|
||||
line-height: 24px;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
cursor: default;
|
||||
i{
|
||||
font-size: 14px !important;
|
||||
margin-right: 6px;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.boldSpan{
|
||||
font-weight: 400;
|
||||
text-shadow: 0.5px 0 0 #333;
|
||||
}
|
||||
|
||||
.noticeCont-text{
|
||||
display: flex;
|
||||
color:#333333;
|
||||
flex:auto;
|
||||
justify-content: space-between;
|
||||
|
||||
& .content-span{
|
||||
word-break: break-all;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
& .atme-cont-span{
|
||||
width: 272px;
|
||||
}
|
||||
|
||||
& .notice-cont-span{
|
||||
width: 255px;
|
||||
}
|
||||
|
||||
.timeSpan{
|
||||
font-size: 12px;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.at-name{
|
||||
margin-right: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.text-center{
|
||||
text-align: center;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import axios from 'axios';
|
||||
import { Spin } from 'antd';
|
||||
import { truncateCommitId } from '../common/util';
|
||||
import Nodata from '../Nodata';
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
export default (( props, { projectDetail }) => {
|
||||
const [isSpin, setSpin] = useState(true);
|
||||
const [data, setData] = useState(undefined);
|
||||
|
||||
const { projectsId , owner } = props.match.params;
|
||||
|
||||
useEffect(() => {
|
||||
if (projectsId) {
|
||||
const url = `/${owner}/${projectsId}/tags.json`;
|
||||
axios.get(url).then((result) => {
|
||||
if (result) {
|
||||
setSpin(false);
|
||||
setData(result.data);
|
||||
}
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
}, [owner, projectsId]);
|
||||
|
||||
return (
|
||||
<div className="main" style={{padding:"0px",border:"none"}}>
|
||||
<Spin spinning={isSpin}>
|
||||
<div style={{minHeight:"400px"}}>
|
||||
{
|
||||
data && data.length > 0 &&
|
||||
<div className="div_table">
|
||||
<ul className="ul_thead">
|
||||
<li>
|
||||
<span className="flex1">标记名</span>
|
||||
<span>提交信息</span>
|
||||
<span className="ul_tbody_forth">下载</span>
|
||||
</li>
|
||||
</ul>
|
||||
<ul className="ul_tbody">
|
||||
{
|
||||
data.map((item, key) => {
|
||||
return (
|
||||
<li>
|
||||
<span className="flex1">
|
||||
<i className="iconfont icon-biaoqian3 font-16 mr5 color-grey-8"></i>
|
||||
<span className="font-16">{item.name}</span>
|
||||
</span>
|
||||
<span className="ul_tbody_third">
|
||||
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.id}`)}`} className="commitKey" style={{ "marginLeft": 0 }}>{truncateCommitId(`${item.id}`)}</Link>
|
||||
</span>
|
||||
<span className="ul_tbody_forth">
|
||||
<a href={item.tarball_url} style={{ color: "#4CC1DA" }} className="mr30"><i className="iconfont icon-TAR font-18 mr5"></i>TAR</a>
|
||||
<a href={item.zipball_url} style={{ color: "#28BD6C" }}><i className="iconfont icon-ZIP font-18 mr5"></i>ZIP</a>
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
{ data && data.length === 0 && <Nodata _html={`暂无标签!`}/> }
|
||||
</div>
|
||||
</Spin>
|
||||
</div>
|
||||
)
|
||||
})
|
|
@ -255,7 +255,11 @@ class Detail extends Component {
|
|||
open_devops: flag
|
||||
})
|
||||
}
|
||||
canvasChannel = () => {
|
||||
/**
|
||||
*
|
||||
* @param {*} deleteFlag :同步镜像需要提示成功,且未成功的情况下不需要删除项目
|
||||
*/
|
||||
canvasChannel = (deleteFlag) => {
|
||||
const name = window.location.hostname === "localhost" ? "testforgeplus.trustie.net" : window.location.hostname;
|
||||
const actioncable = require("actioncable");
|
||||
var project = this.state.project;
|
||||
|
@ -272,10 +276,15 @@ class Detail extends Component {
|
|||
console.log(`###### ---received data--- ######`);
|
||||
console.log(data);
|
||||
if (data) {
|
||||
if ( data.project && data.project.mirror_status === 2) {
|
||||
this.deleteProjectBack();
|
||||
if(deleteFlag){
|
||||
this.props.showNotification("镜像同步成功!");
|
||||
window.location.reload();
|
||||
}else{
|
||||
if (data.project && data.project.mirror_status === 2) {
|
||||
this.deleteProjectBack();
|
||||
}
|
||||
this.getDetail();
|
||||
}
|
||||
this.getDetail();
|
||||
this.setState({
|
||||
firstSync: false,
|
||||
secondSync: false
|
||||
|
@ -428,8 +437,10 @@ class Detail extends Component {
|
|||
const url = `/${owner}/${projectsId}/sync_mirror.json`;
|
||||
axios.post(url).then(result => {
|
||||
if (result && result.data && result.data.status === 0) {
|
||||
this.props.showNotification("镜像同步成功!");
|
||||
this.getProject(2);
|
||||
this.setState({
|
||||
secondSync:true
|
||||
})
|
||||
this.canvasChannel(true);
|
||||
} else {
|
||||
this.props.showNotification("镜像同步失败!");
|
||||
}
|
||||
|
@ -670,17 +681,22 @@ class Detail extends Component {
|
|||
(props) => (<OrderNew {...this.props} {...props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
{/* 修改详情 */}
|
||||
<Route path="/:owner/:projectsId/issues/:orderId/updatedetail"
|
||||
{/* 修改详情 updatedetail*/}
|
||||
<Route path="/:owner/:projectsId/issues/:orderId/:operateName"
|
||||
render={
|
||||
(props) => (<OrderupdateDetail {...this.props} {...props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
{/* 复制详情 */}
|
||||
<Route path="/:owner/:projectsId/issues/:orderId/copyetail"
|
||||
{/* 复制详情 copyetail*/}
|
||||
{/* <Route path="/:owner/:projectsId/issues/:orderId/copyetail"
|
||||
render={
|
||||
(props) => (<OrdercopyDetail {...this.props} {...props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route> */}
|
||||
<Route path="/:owner/:projectsId/issues/:orderId/:operateName"
|
||||
render={
|
||||
(props) => (<OrderupdateDetail {...this.props} {...props} {...this.state} {...common} />)
|
||||
}
|
||||
></Route>
|
||||
{/* 任务详情 */}
|
||||
<Route path="/:owner/:projectsId/issues/:orderId"
|
||||
|
|
|
@ -426,14 +426,15 @@
|
|||
border-right: none;
|
||||
}
|
||||
.gitAddressClone > input{
|
||||
border:none;
|
||||
outline: none;
|
||||
padding:0px 8px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
border-radius: 0px;
|
||||
border: 1px solid #eee;
|
||||
flex:1;
|
||||
padding: 0px 8px;
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
border: none!important;
|
||||
border-right: 1px solid #eee!important;
|
||||
border-radius: 4px 0px 0px 4px;
|
||||
flex: 1;
|
||||
max-width: 249px;
|
||||
}
|
||||
.wrap-commit-table .ant-table-small > .ant-table-content > .ant-table-body{
|
||||
margin:0px;
|
||||
|
|
|
@ -424,7 +424,7 @@ class MessageCount extends Component {
|
|||
</span>
|
||||
</span>
|
||||
<span className="ml25">
|
||||
<span className="color-grey-8">标签:</span>
|
||||
<span className="color-grey-8">标记:</span>
|
||||
<span className="color-grey-3">
|
||||
{data.issue.issue_tags &&
|
||||
data.issue.issue_tags.length > 0
|
||||
|
|
|
@ -110,6 +110,7 @@ class NewMerge extends Component {
|
|||
const { author , identifier } =oldProject;
|
||||
url += `/${mergeBranch}...${author && author.login}/${identifier}:${localBranch}.json`;
|
||||
}
|
||||
this.setState({isSpin: true});
|
||||
axios.get(url).then(result=>{
|
||||
if(result){
|
||||
if (result.data.status === 0) {
|
||||
|
@ -128,7 +129,9 @@ class NewMerge extends Component {
|
|||
comparesData:result.data
|
||||
})
|
||||
}
|
||||
}).catch(error=>{})
|
||||
}).catch(error=>{
|
||||
this.setState({isSpin: false});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ class merge extends Component {
|
|||
//设置选择高亮
|
||||
openselect: 1,
|
||||
closeselect: undefined,
|
||||
issue_tag_ids: "标签",
|
||||
issue_tag_ids: "标记",
|
||||
fixed_version_ids: "里程碑",
|
||||
assigned_to_ids: "审查人员",
|
||||
paix: "排序",
|
||||
|
@ -198,7 +198,7 @@ class merge extends Component {
|
|||
});
|
||||
this.setState({
|
||||
status_type: type,
|
||||
issue_tag_ids: "标签",
|
||||
issue_tag_ids: "标记",
|
||||
fixed_version_ids: "里程碑",
|
||||
assigned_to_ids: "审查人员",
|
||||
paix: "排序",
|
||||
|
@ -321,7 +321,7 @@ class merge extends Component {
|
|||
className="topWrapperSelect"
|
||||
overlay={this.renderMenu(
|
||||
issue_chosen && issue_chosen.issue_tag,
|
||||
"标签",
|
||||
"标记",
|
||||
"issue_tag_id"
|
||||
)}
|
||||
trigger={["click"]}
|
||||
|
|
|
@ -300,7 +300,8 @@ class MergeForm extends Component {
|
|||
{getFieldDecorator("assigned_to_id", {
|
||||
initialValue: assigned_to_id,
|
||||
})(
|
||||
<Select placeholder="审查人员" showSearch>
|
||||
<Select placeholder="未选择审查人员" showSearch>
|
||||
<Option key={0} value={""}>未选择审查人员</Option>
|
||||
{this.renderSelect(members)}
|
||||
</Select>
|
||||
)}
|
||||
|
@ -311,12 +312,11 @@ class MergeForm extends Component {
|
|||
})(
|
||||
<Select
|
||||
placeholder={
|
||||
issue_versions && issue_versions.length > 0
|
||||
? "未选择里程碑"
|
||||
: "请添加里程碑"
|
||||
issue_versions && issue_versions.length > 0? "未选择里程碑": "请添加里程碑"
|
||||
}
|
||||
showSearch
|
||||
>
|
||||
<Option key={0} value={""}>{issue_versions && issue_versions.length > 0? "未选择里程碑": "请添加里程碑"}</Option>
|
||||
{this.renderSelect(issue_versions)}
|
||||
</Select>
|
||||
)}
|
||||
|
@ -327,12 +327,11 @@ class MergeForm extends Component {
|
|||
})(
|
||||
<Select
|
||||
placeholder={
|
||||
issue_tags && issue_tags.length > 0
|
||||
? "未选择标签"
|
||||
: "请在仓库设置里添加标签"
|
||||
issue_tags && issue_tags.length > 0 ? "未选择标记" : "请在仓库设置里添加标记"
|
||||
}
|
||||
showSearch
|
||||
>
|
||||
<Option key={0} value={""}>{issue_tags && issue_tags.length > 0 ? "未选择标记" : "请在仓库设置里添加标记"}</Option>
|
||||
{this.renderSelect(issue_tags)}
|
||||
</Select>
|
||||
)}
|
||||
|
|
|
@ -219,7 +219,7 @@ class Index extends Component {
|
|||
user_id:owners_id
|
||||
}).then((result) => {
|
||||
if (result && result.data.id) {
|
||||
projectsType && projectsType !== "mirror" && this.props.showNotification(`托管项目创建成功!`);
|
||||
projectsType && projectsType !== "mirror" && this.props.showNotification(`项目创建成功!`);
|
||||
this.props.history.push(`/${result.data.login}/${result.data.identifier}`);
|
||||
}
|
||||
this.setState({
|
||||
|
@ -351,7 +351,7 @@ class Index extends Component {
|
|||
required: true, message: '请填写镜像版本库地址'
|
||||
}],
|
||||
})(
|
||||
<Input placeholder="输入需要同步到本项目的镜像版本库地址" onChange={this.ChangeAddr} />
|
||||
<Input placeholder="请输入需要导入到本项目的仓库地址" onChange={this.ChangeAddr} />
|
||||
)}
|
||||
</Form.Item>
|
||||
<p className="formTip color-orange">示例:https://github.com/facebook/reack.git</p>
|
||||
|
@ -386,7 +386,7 @@ class Index extends Component {
|
|||
{getFieldDecorator('password', {
|
||||
rules: [],
|
||||
})(
|
||||
<Input.Password placeholder="请输入对应平台的登录用户名" autocomplete='new-password' style={{width:"240px"}}/>
|
||||
<Input.Password placeholder="请输入对应平台的登录密码" autocomplete='new-password' style={{width:"240px"}}/>
|
||||
)}
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React , { Component } from 'react';
|
||||
|
||||
import nodata from './Images/nodata.png';
|
||||
|
||||
import './css/index.scss';
|
||||
class Nodata extends Component{
|
||||
render(){
|
||||
const { _html , small } = this.props;
|
||||
|
|
|
@ -10,10 +10,6 @@ const Apply = Loadable({
|
|||
loader: () => import("./Apply"),
|
||||
loading: Loading,
|
||||
});
|
||||
const Notify = Loadable({
|
||||
loader: () => import("./Notify"),
|
||||
loading: Loading,
|
||||
});
|
||||
const UndoEvent = Loadable({
|
||||
loader: () => import("./UndoEvent"),
|
||||
loading: Loading,
|
||||
|
@ -23,7 +19,7 @@ function Index(props){
|
|||
const pathname = props.history.location.pathname;
|
||||
const user = props.user;
|
||||
|
||||
const [ menu , setMenu ] = useState("notify");
|
||||
const [ menu , setMenu ] = useState("undo");
|
||||
const [ messagesCount , setMessagesCount ] = useState(0);
|
||||
const [ transferCount , setTransferCount ] = useState(0);
|
||||
const [ applyCount , setApplyCount ] = useState(0);
|
||||
|
@ -48,10 +44,6 @@ function Index(props){
|
|||
useEffect(()=>{
|
||||
if(pathname && username){
|
||||
if(pathname === `/${username}/notice`){
|
||||
setMenu("notify");
|
||||
changeNum(user.undo_messages);
|
||||
}
|
||||
if(pathname === `/${username}/notice/undo`){
|
||||
setMenu("undo");
|
||||
}
|
||||
if(pathname === `/${username}/notice/apply`){
|
||||
|
@ -83,14 +75,8 @@ function Index(props){
|
|||
return (
|
||||
<div>
|
||||
<ul className="noticeMenu">
|
||||
<li className={menu === "notify" ? "active":""}>
|
||||
<Link to={`/${username}/notice`} onClick={changeNum}>
|
||||
<span>通知</span>
|
||||
{messagesCount ? <span className="unNum">{messagesCount}</span>:""}
|
||||
</Link>
|
||||
</li>
|
||||
<li className={menu === "undo" ? "active":""}>
|
||||
<Link to={`/${username}/notice/undo`}>
|
||||
<Link to={`/${username}/notice`}>
|
||||
<span>接收仓库</span>
|
||||
{transferCount ? <span className="unNum">{transferCount}</span>:""}
|
||||
</Link>
|
||||
|
@ -109,16 +95,10 @@ function Index(props){
|
|||
return <Apply {...props} {...p} deleteEvent={deleteEvent}/>;
|
||||
}}
|
||||
></Route>
|
||||
<Route
|
||||
path="/:username/notice/undo"
|
||||
render={(p) => {
|
||||
return <UndoEvent {...props} {...p} deleteEvent={deleteEvent}/>;
|
||||
}}
|
||||
></Route>
|
||||
<Route
|
||||
path="/:username/notice"
|
||||
render={(p) => {
|
||||
return <Notify {...props} {...p} deleteEvent={deleteEvent}/>;
|
||||
return <UndoEvent {...props} {...p} deleteEvent={deleteEvent}/>;
|
||||
}}
|
||||
></Route>
|
||||
</Switch>
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
|
||||
import React, { Component } from "react";
|
||||
import React from "react";
|
||||
import OrderItem from './order_form'
|
||||
class CopyDetail extends Component {
|
||||
render() {
|
||||
return (
|
||||
<OrderItem form_type="copy" {...this.props}></OrderItem>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
function CopyDetail(props){
|
||||
const operate = props.match.params.operate;
|
||||
console.log(operate);
|
||||
return(
|
||||
<OrderItem form_type="copy" {...props}></OrderItem>
|
||||
)
|
||||
}
|
||||
export default CopyDetail;
|
||||
export default CopyDetail;
|
|
@ -315,7 +315,7 @@ class Detail extends Component {
|
|||
</span>
|
||||
</p>
|
||||
<p className="grid-item-left pb15">
|
||||
<span className="issue_detail_info">标签:</span>
|
||||
<span className="issue_detail_info">标记:</span>
|
||||
<span>
|
||||
{data && data.issue_tags ? (
|
||||
<span className="grid-item">
|
||||
|
|
|
@ -40,7 +40,7 @@ class MilepostDetail extends Component {
|
|||
issue_type: undefined,
|
||||
status_type: '1',
|
||||
//设置选择高亮
|
||||
issue_tag_ids: '标签',
|
||||
issue_tag_ids: '标记',
|
||||
tracker_ids: '类型',
|
||||
author_ids: '发布人',
|
||||
assigned_to_ids: '负责人',
|
||||
|
@ -194,7 +194,7 @@ class MilepostDetail extends Component {
|
|||
done_ratio : undefined,
|
||||
status_id: undefined,
|
||||
assigned_to_id: undefined,
|
||||
issue_tag_ids: '标签',
|
||||
issue_tag_ids: '标记',
|
||||
tracker_ids: '类型',
|
||||
author_ids: '发布人',
|
||||
assigned_to_ids: '负责人',
|
||||
|
@ -254,7 +254,7 @@ class MilepostDetail extends Component {
|
|||
</ul>
|
||||
<ul className="topWrapper_select">
|
||||
<li>
|
||||
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.issue_tag, '标签', 'issue_tag_id')} trigger={['click']} placement="bottomCenter">
|
||||
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.issue_tag, '标记', 'issue_tag_id')} trigger={['click']} placement="bottomCenter">
|
||||
<span>{this.state.issue_tag_ids}<Icon type="caret-down" className="ml5" /></span>
|
||||
</Dropdown>
|
||||
</li>
|
||||
|
|
|
@ -7,7 +7,7 @@ class Nav extends Component{
|
|||
const { projectsId , owner } = this.props.match.params;
|
||||
return(
|
||||
<p className="topWrapper_nav">
|
||||
<NavLink activeClassName="active" className="issue-type-button" to={`/${owner}/${projectsId}/issues/tags`}>标签</NavLink>
|
||||
<NavLink activeClassName="active" className="issue-type-button" to={`/${owner}/${projectsId}/issues/tags`}>标记</NavLink>
|
||||
<NavLink activeClassName="active" className="issue-type-button" to={`/${owner}/${projectsId}/milestones`}>里程碑</NavLink>
|
||||
</p>
|
||||
)
|
||||
|
|
|
@ -324,11 +324,11 @@ class Tags extends Component {
|
|||
data && data.issue_tags && data.issue_tags.length > 0 ?
|
||||
<div>
|
||||
<div className="topWrapper">
|
||||
<span>共{data && data.issue_tags_count}个标签</span>
|
||||
<span>共{data && data.issue_tags_count}个标记</span>
|
||||
<ul className="topWrapper_select">
|
||||
<li>
|
||||
<Dropdown className="topWrapperSelect" overlay={this.menu()} trigger={['click']} placement="bottomCenter">
|
||||
<span>标签<Icon type="caret-down" className="ml5" /></span>
|
||||
<span>标记<Icon type="caret-down" className="ml5" /></span>
|
||||
</Dropdown>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
|
||||
import React, { Component } from "react";
|
||||
import React from "react";
|
||||
import OrderForm from './order_form'
|
||||
class UpdateDetail extends Component {
|
||||
render() {
|
||||
return (
|
||||
<OrderForm form_type="edit" {...this.props}></OrderForm>
|
||||
)
|
||||
}
|
||||
|
||||
function CopyDetail(props){
|
||||
const operateName = props.match.params.operateName;
|
||||
return(
|
||||
<OrderForm form_type={operateName === "copyetail" ? "copy":"edit"} {...props}></OrderForm>
|
||||
)
|
||||
}
|
||||
export default UpdateDetail;
|
||||
export default CopyDetail;
|
||||
|
|
|
@ -39,7 +39,7 @@ class order extends Component {
|
|||
search_count: undefined,
|
||||
issue_type: undefined,
|
||||
status_type: "1", // 默认显示开启中的
|
||||
issue_tag_ids: "标签",
|
||||
issue_tag_ids: "标记",
|
||||
tracker_ids: "类型",
|
||||
author_ids: "发布人",
|
||||
assigned_to_ids: "负责人",
|
||||
|
@ -58,7 +58,7 @@ class order extends Component {
|
|||
select_params: {
|
||||
assigned_to_id: undefined, // 负责人
|
||||
author_id: undefined, // 发布人
|
||||
issue_tag_id: undefined, // 标签
|
||||
issue_tag_id: undefined, // 标记
|
||||
tracker_id: undefined, //类型
|
||||
done_ratio: undefined, // 完成度
|
||||
status_id: undefined, // 优先级
|
||||
|
@ -257,7 +257,7 @@ class order extends Component {
|
|||
author_id: undefined,
|
||||
assigned_to_id: undefined,
|
||||
status_type: type,
|
||||
issue_tag_ids: "标签",
|
||||
issue_tag_ids: "标记",
|
||||
tracker_ids: "类型",
|
||||
author_ids: "发布人",
|
||||
assigned_to_ids: "负责人",
|
||||
|
@ -677,7 +677,7 @@ class order extends Component {
|
|||
className="topWrapperSelect"
|
||||
overlay={this.renderMenu(
|
||||
issue_chosen && issue_chosen.issue_tag,
|
||||
"标签",
|
||||
"标记",
|
||||
"issue_tag_id"
|
||||
)}
|
||||
trigger={["click"]}
|
||||
|
|
|
@ -153,7 +153,7 @@ class order_form extends Component {
|
|||
values.issue_tag_ids = [values.issue_tag_ids];
|
||||
}
|
||||
const { description, start_date, due_date, issue_type } = this.state;
|
||||
if (form_type === "new") {
|
||||
if (form_type !== "edit") {
|
||||
const url = `/${owner}/${projectsId}/issues.json`;
|
||||
axios.post(url, {
|
||||
...values,
|
||||
|
@ -442,13 +442,13 @@ class order_form extends Component {
|
|||
</Select>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item label="标签">
|
||||
<Form.Item label="标记">
|
||||
{getFieldDecorator("issue_tag_ids", {rules: []})(
|
||||
<Select>
|
||||
<Option value={""}>
|
||||
{issue_chosen && issue_chosen.issue_tag.length > 0
|
||||
? "未选择标签"
|
||||
: "请在仓库设置里添加标签"}
|
||||
? "未选择标记"
|
||||
: "请在仓库设置里添加标记"}
|
||||
</Option>
|
||||
{this.renderSelect(issue_chosen && issue_chosen.issue_tag)}
|
||||
</Select>
|
||||
|
|
|
@ -14,6 +14,16 @@ import { Link } from 'react-router-dom';
|
|||
|
||||
import './Index.scss';
|
||||
|
||||
const MyNoticeIndex = Loadable({
|
||||
loader: () => import("./notice/myNotice/Index"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
const NoticeManager = Loadable({
|
||||
loader: () => import("./notice/manager/Index"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
const SSHNew = Loadable({
|
||||
loader: () => import("./sub/New"),
|
||||
loading: Loading,
|
||||
|
@ -26,6 +36,12 @@ const SSHIndex = Loadable({
|
|||
loader: () => import("./sub/SSH"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
const PrivateLetter = Loadable({
|
||||
loader: () => import("./notice/privateLetter/Index"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
function Index(props){
|
||||
const { current_user } = props;
|
||||
const { pathname } = props.location;
|
||||
|
@ -39,18 +55,35 @@ function Index(props){
|
|||
<img src={getImageUrl(`/${current_user && current_user.image_url}`)} alt=""/>
|
||||
<span>{current_user && current_user.username}</span>
|
||||
</div>
|
||||
<ul className="securityUl">
|
||||
<ul className="securityUl ul-border-buttom">
|
||||
<li>个人信息</li>
|
||||
<li className={pathname.indexOf("/settings/profile")>-1 ?"active":""}><Link to={`/settings/profile`}><i className="iconfont icon-gerenziliao mr5 font-14"></i>基本资料</Link></li>
|
||||
<li className={pathname.indexOf("/settings/profile")>-1 ?"active":""}><Link to={`/settings/profile`}><i className="iconfont icon-gerenziliao mr5 font-14"></i><span className="text-shodow-bold">基本资料</span></Link></li>
|
||||
</ul>
|
||||
<ul className="securityUl ul-border-buttom">
|
||||
<li>消息通知</li>
|
||||
<li className={(pathname.indexOf("/settings/notice")>-1 && pathname.indexOf("/settings/notice/config") == -1) || pathname.indexOf("/settings/notice/privateLetter")>-1 ?"active":""}><Link to={"/settings/notice"}><i className="iconfont icon-wodetongzhi"></i><span className="text-shodow-bold">我的通知</span></Link></li>
|
||||
{/* <li className={pathname.indexOf("/settings/notice/config")>-1 ?"active":""}><Link to={'/settings/notice/config'}><i className="iconfont icon-tongzhiguanli"></i><span className="text-shodow-bold">通知管理</span></Link></li> */}
|
||||
</ul>
|
||||
<ul className="securityUl">
|
||||
<li>安全设置</li>
|
||||
<li className={pathname.indexOf("/settings/SSH")>-1 ?"active":""}><Link to={`/settings/SSH`}><i className="iconfont icon-xuanzhongssh_icon mr5 font-14"></i>SSH密钥</Link></li>
|
||||
<li className={pathname.indexOf("/settings/SSH")>-1 ?"active":""}><Link to={`/settings/SSH`}><i className="iconfont icon-xuanzhongssh_icon mr5 font-14"></i><span className="text-shodow-bold">SSH密钥</span></Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
<LongWidth>
|
||||
<Gap>
|
||||
<Switch>
|
||||
<Route
|
||||
path="/settings/notice"
|
||||
render={(p) => (
|
||||
<MyNoticeIndex {...props} {...p}/>
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/settings/notice/config"
|
||||
render={(p) => (
|
||||
<NoticeManager {...props} {...p}/>
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/settings/SSH/new"
|
||||
render={(p) => (
|
||||
|
@ -69,12 +102,17 @@ function Index(props){
|
|||
<SSHIndex {...props} {...p}/>
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/settings/notice/privateLetter"
|
||||
render={(p)=>(
|
||||
<PrivateLetter{...props} {...p}/>
|
||||
)}
|
||||
></Route>
|
||||
</Switch>
|
||||
</Gap>
|
||||
</LongWidth>
|
||||
</Box>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -8,42 +8,44 @@
|
|||
width: 198px;
|
||||
border: 1px solid rgba(153, 153, 153, 0.22);
|
||||
border-radius: 4px;
|
||||
min-height: 400px;
|
||||
// min-height: 400px;
|
||||
margin-bottom: 30px;
|
||||
.userDetail{
|
||||
background: rgba(153, 153, 153, 0.05);
|
||||
border-radius: 4px 4px 0px 0px;
|
||||
padding:20px 25px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
text-align: center;
|
||||
height: 105px;
|
||||
img{
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
border-radius: 50%;
|
||||
margin-right: 12px;
|
||||
}
|
||||
span{
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
max-width: 90px;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
.securityUl{
|
||||
padding:20px 16px;
|
||||
padding-left: 17px;
|
||||
color: #333;
|
||||
margin-bottom: 0px;
|
||||
padding-bottom: 0px;
|
||||
padding-bottom: 12px;
|
||||
padding-top: 5px;
|
||||
li{
|
||||
font-size: 14px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
height: 27px;
|
||||
line-height: 27px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
cursor: default;
|
||||
|
||||
a{
|
||||
color: #666;
|
||||
&:hover{
|
||||
|
@ -52,32 +54,57 @@
|
|||
}
|
||||
&.active a{
|
||||
color: #333;
|
||||
}
|
||||
&:first-child{
|
||||
font-size: 16px;
|
||||
.text-shodow-bold{
|
||||
font-weight: 400;
|
||||
text-shadow: 0.5px 0 #333;
|
||||
}
|
||||
}
|
||||
&.active::before{
|
||||
position: absolute;
|
||||
left: -16px;
|
||||
top:0px;
|
||||
height: 100%;
|
||||
width: 2px;
|
||||
left: -18px;
|
||||
top:6px;
|
||||
height: 15px;
|
||||
width: 3px;
|
||||
border-radius: 2px;
|
||||
content: "";
|
||||
background-color: #2A61FF;
|
||||
background-color: #466AFF;
|
||||
}
|
||||
|
||||
i{
|
||||
font-size: 14px !important;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ul-border-buttom{
|
||||
border-bottom: 1px solid rgba(153, 153, 153, 0.22);
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
}
|
||||
.sshHead{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding:15px 20px;
|
||||
padding:6px 0px;
|
||||
margin-bottom: 15px;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
&>span{
|
||||
&>.text-shadow07{
|
||||
font-size: 18px;
|
||||
font-weight: 400;
|
||||
color: #333333;
|
||||
text-shadow: 0.5px 0 #333;
|
||||
}
|
||||
&>.add-SSH-title{
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
color: #333333;
|
||||
text-shadow: 0.5px 0 #333;
|
||||
}
|
||||
& .but25{
|
||||
padding:0 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-list-item{
|
||||
padding:20px;
|
||||
border-bottom: 1px solid #eee!important;
|
||||
|
@ -109,7 +136,7 @@
|
|||
.questionLink{
|
||||
padding:15px 20px;
|
||||
a{
|
||||
color: #4B7AFF;
|
||||
color: #466AFF;
|
||||
&:hover{
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
@ -147,4 +174,23 @@
|
|||
flex:1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.but25{
|
||||
margin-bottom: 5px;
|
||||
background-color: #466AFF;
|
||||
color: #fff;
|
||||
border-color: #466AFF;
|
||||
&:hover{
|
||||
opacity: 0.8;
|
||||
background-color: #466AFF;
|
||||
border-color: #466AFF;
|
||||
}
|
||||
&:active{
|
||||
opacity: 1;
|
||||
background-color: #466AFF;
|
||||
border-color: #466AFF;
|
||||
}
|
||||
}
|
||||
.blue-Purple{
|
||||
color: #466AFF !important;
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 900 B After Width: | Height: | Size: 1.0 KiB |
|
@ -0,0 +1,46 @@
|
|||
import fetch from './fetch';
|
||||
|
||||
// 获取消息列表
|
||||
export function noticePages(params) {
|
||||
return fetch({
|
||||
url: '/api/notice/noticePages',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
// 获取单个notice
|
||||
export function getNotice(params) {
|
||||
return fetch({
|
||||
url: '/api/notice/getNotice',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
//新增notice
|
||||
export function addNotice(data) {
|
||||
return fetch({
|
||||
url: '/api/notice/createNotice',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
//更新notice
|
||||
export function updateNotice(data) {
|
||||
return fetch({
|
||||
url: '/api/notice/updateNotice',
|
||||
method: 'PUT',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
//删除notice
|
||||
export function deleteNotice(data) {
|
||||
return fetch({
|
||||
url: '/api/notice/deleteNotice',
|
||||
method: 'DELETE',
|
||||
data,
|
||||
});
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
import javaFetch from '../../javaFetch';
|
||||
|
||||
const developUrl = "https://test-search.trustie.net";
|
||||
const testUrl = "https://test-search.trustie.net";
|
||||
const productUrl = "https://wiki-api.trustie.net";
|
||||
|
||||
const { service, actionUrl } = javaFetch(productUrl, testUrl, developUrl);
|
||||
export const httpUrl = actionUrl;
|
||||
export default service;
|
|
@ -0,0 +1,100 @@
|
|||
import { Button, Checkbox } from "antd";
|
||||
import React from "react";
|
||||
|
||||
import './Index.scss';
|
||||
|
||||
function NoticeManager(props){
|
||||
|
||||
return(
|
||||
<div className="notice01">
|
||||
<div className="sshHead">
|
||||
<span className="text-shadow07">通知管理</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="notice-manager-tip">您可以通过通知管理来选择接受通知的方式</span>
|
||||
<div className="manager-cont-top">
|
||||
我创建或负责的
|
||||
</div>
|
||||
<div className="manager-cont">
|
||||
<div className="manager-cont-title">易修状态变更</div>
|
||||
<Checkbox defaultChecked='true' disabled>站内信</Checkbox>
|
||||
<Checkbox >邮件</Checkbox>
|
||||
</div>
|
||||
<div className="manager-cont">
|
||||
<div className="manager-cont-title">易修截止日期到达最后一天</div>
|
||||
<Checkbox defaultChecked='true' disabled>站内信</Checkbox>
|
||||
<Checkbox >邮件</Checkbox>
|
||||
</div>
|
||||
<div className="manager-cont">
|
||||
<div className="manager-cont-title">合并请求状态变更</div>
|
||||
<Checkbox defaultChecked='true' disabled>站内信</Checkbox>
|
||||
<Checkbox >邮件</Checkbox>
|
||||
</div>
|
||||
<div className="manager-cont">
|
||||
<div className="manager-cont-title">易修有新的评论</div>
|
||||
<Checkbox defaultChecked='true'>站内信</Checkbox>
|
||||
<Checkbox >邮件</Checkbox>
|
||||
</div>
|
||||
<div className="manager-cont">
|
||||
<div className="manager-cont-title">合并请求有新的评论</div>
|
||||
<Checkbox defaultChecked='true'>站内信</Checkbox>
|
||||
<Checkbox >邮件</Checkbox>
|
||||
</div>
|
||||
|
||||
<div className="manager-cont-top">
|
||||
我管理的仓库
|
||||
</div>
|
||||
<div className="manager-cont">
|
||||
<div className="manager-cont-title">被关注</div>
|
||||
<Checkbox defaultChecked='true'>站内信</Checkbox>
|
||||
<Checkbox >邮件</Checkbox>
|
||||
</div>
|
||||
<div className="manager-cont">
|
||||
<div className="manager-cont-title">被点赞</div>
|
||||
<Checkbox defaultChecked='true'>站内信</Checkbox>
|
||||
<Checkbox >邮件</Checkbox>
|
||||
</div>
|
||||
<div className="manager-cont">
|
||||
<div className="manager-cont-title">被复刻</div>
|
||||
<Checkbox defaultChecked='true'>站内信</Checkbox>
|
||||
<Checkbox >邮件</Checkbox>
|
||||
</div>
|
||||
<div className="manager-cont">
|
||||
<div className="manager-cont-title">有新的里程碑</div>
|
||||
<Checkbox defaultChecked='true'>站内信</Checkbox>
|
||||
<Checkbox >邮件</Checkbox>
|
||||
</div>
|
||||
|
||||
<div className="manager-cont-top">
|
||||
我关注的仓库
|
||||
</div>
|
||||
<div className="manager-cont">
|
||||
<div className="manager-cont-title">被删除</div>
|
||||
<Checkbox defaultChecked='true'>站内信</Checkbox>
|
||||
<Checkbox >邮件</Checkbox>
|
||||
</div>
|
||||
<div className="manager-cont">
|
||||
<div className="manager-cont-title">被转移</div>
|
||||
<Checkbox defaultChecked='true'>站内信</Checkbox>
|
||||
<Checkbox >邮件</Checkbox>
|
||||
</div>
|
||||
<div className="manager-cont">
|
||||
<div className="manager-cont-title">有新的易修</div>
|
||||
<Checkbox defaultChecked='true'>站内信</Checkbox>
|
||||
<Checkbox >邮件</Checkbox>
|
||||
</div>
|
||||
<div className="manager-cont">
|
||||
<div className="manager-cont-title">有新的合并请求</div>
|
||||
<Checkbox defaultChecked='true'>站内信</Checkbox>
|
||||
<Checkbox >邮件</Checkbox>
|
||||
</div>
|
||||
<div className="manager-cont">
|
||||
<div className="manager-cont-title">有新的版本发布</div>
|
||||
<Checkbox defaultChecked='true'>站内信</Checkbox>
|
||||
<Checkbox >邮件</Checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default NoticeManager;
|
|
@ -0,0 +1,87 @@
|
|||
.notice-manager-tip{
|
||||
font-size:16px;
|
||||
font-weight:400;
|
||||
}
|
||||
.manager-cont-top{
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
height: 44px;
|
||||
padding-left: 20px;
|
||||
background: #FAFCFF;
|
||||
border: 1px solid #89a4f7;
|
||||
line-height: 44px;
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.manager-cont{
|
||||
padding: 8px 20px 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
|
||||
.manager-cont-title{
|
||||
width: 320px;
|
||||
}
|
||||
}
|
||||
|
||||
.notice01{
|
||||
.ant-checkbox-disabled.ant-checkbox-checked .ant-checkbox-inner::after {
|
||||
border-color: white;
|
||||
}
|
||||
.ant-checkbox-disabled .ant-checkbox-inner {
|
||||
background-color: #999999 !important;
|
||||
border-color: #999999 !important;
|
||||
}
|
||||
|
||||
.ant-checkbox-checked .ant-checkbox-inner {
|
||||
background-color: #466AFF;
|
||||
border: #466AFF;
|
||||
}
|
||||
|
||||
.ant-checkbox-checked::after{
|
||||
border: 1px solid #466AFF;
|
||||
}
|
||||
.ant-checkbox-wrapper:hover .ant-checkbox-inner, .ant-checkbox:hover .ant-checkbox-inner, .ant-checkbox-input:focus + .ant-checkbox-inner,.ant-radio-checked .ant-radio-inner,.ant-radio-wrapper:hover .ant-radio, .ant-radio:hover .ant-radio-inner, .ant-radio-input:focus + .ant-radio-inner {
|
||||
border-color: #466AFF;
|
||||
}
|
||||
|
||||
.ant-checkbox + span,.manager-cont-title {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.ant-radio-inner::after{
|
||||
background-color:#466AFF;
|
||||
}
|
||||
|
||||
.but25{
|
||||
background-color: #466AFF;
|
||||
color: #fff;
|
||||
border-color: #466AFF;
|
||||
&:hover{
|
||||
opacity: 0.8;
|
||||
background-color: #466AFF;
|
||||
border-color: #466AFF;
|
||||
}
|
||||
&:active{
|
||||
opacity: 1;
|
||||
background-color: #466AFF;
|
||||
border-color: #466AFF;
|
||||
}
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 5px; /*对垂直流动条有效*/
|
||||
}
|
||||
/*定义滑块颜色、内阴影及圆角*/
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 6px;
|
||||
box-shadow: inset 0 0 6px #FFF;
|
||||
background-color: #D4D4D4;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
box-shadow: inset 0 0 6px #fff;
|
||||
background-color: #FFF;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
import { Badge, Button, Checkbox, Menu, Pagination } from 'antd';
|
||||
import DelModal from '../../../Component/ModalFun';
|
||||
import NoneData from '../../../Nodata.js';
|
||||
import { noticeSourceType } from '../../../common/static';
|
||||
import './Index.scss';
|
||||
import '../manager/Index.scss'
|
||||
|
||||
function MyNotice(props) {
|
||||
let current_user = props.current_user;
|
||||
let resetUserInfo = props.resetUserInfo;
|
||||
//消息悬停框选择tab
|
||||
let popover = props.location.query && props.location.query.noticeType;
|
||||
let pageSize = 15;
|
||||
const [noticeType, setNoticeType] = useState(popover==="atme"?"2":"0");//消息类别tab栏选择
|
||||
const [selectedNum, setSelectedNum] = useState(0);//@我批量删除选择消息条数
|
||||
const [isBatchDelete, setIsBatchDelete] = useState(false);//@我是否批量删除
|
||||
const [batchDeleteCheckedAll, setBatchDeleteCheckAll] = useState(false);//@我批量删除--全选
|
||||
|
||||
const [noticeUnreadCount, setNoticeUnreadCount] = useState();//未读系统通知数量
|
||||
// const [letterUnreadCount, setLetterUnreadCount] = useState(0);//未读私信数量
|
||||
const [atUnreadCount, setAtUnreadCount] = useState();//未读@我数量
|
||||
const [messageList, setMessageList] = useState([]);
|
||||
const [messTotalCount, setMessTotalCount] = useState();//消息总数
|
||||
const [currentPage, setCurrentPage] = useState(1);//当前页数
|
||||
const [onlyUnread, setOnlyUnread] = useState();
|
||||
|
||||
useEffect(()=>{
|
||||
popover==="atme" ? setNoticeType("2"):setNoticeType("0");
|
||||
},[popover])
|
||||
|
||||
useEffect(()=>{
|
||||
resetUserInfo();
|
||||
},[noticeUnreadCount,atUnreadCount])
|
||||
|
||||
useEffect(() => {
|
||||
getMessageList();
|
||||
}, [noticeType, onlyUnread, currentPage, current_user])
|
||||
|
||||
function getMessageList() {
|
||||
const params = {
|
||||
type: noticeType === "0" ? "notification" : noticeType === "2" ? "atme" : "",
|
||||
status: onlyUnread ? onlyUnread : "",
|
||||
limit: pageSize,
|
||||
page: currentPage,
|
||||
};
|
||||
axios.get(`/users/${current_user.login}/messages.json`, {
|
||||
params: params,
|
||||
}).then((response) => {
|
||||
if(response && response.data){
|
||||
setNoticeUnreadCount(response.data.unread_notification);
|
||||
setAtUnreadCount(response.data.unread_atme);
|
||||
setMessageList(response.data.messages);
|
||||
setMessTotalCount(response.data.total_count);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function readNotice(id){
|
||||
if(id){
|
||||
const params = {
|
||||
type: noticeType === "0" ? "notification" : noticeType === "2" ? "atme" : "",
|
||||
ids:id,
|
||||
};
|
||||
axios.post(`/users/${current_user.login}/messages/read.json`,params).then((response)=>{
|
||||
if(response.status === 200){
|
||||
getMessageList();
|
||||
//已读当前页码最后一条数据时跳转到前一页
|
||||
let totlaPage = Math.ceil((messTotalCount-1)/pageSize);
|
||||
setCurrentPage(currentPage>=totlaPage? totlaPage : currentPage);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleClick(e) {
|
||||
setNoticeType(e.key);
|
||||
setCurrentPage(1);
|
||||
setOnlyUnread();
|
||||
if (e.key != "2") {
|
||||
setIsBatchDelete(false);
|
||||
}
|
||||
}
|
||||
|
||||
function onChange(e) {
|
||||
var checkboxNum = 0;
|
||||
let messageListNew=messageList.slice();
|
||||
messageListNew.map((item)=>{
|
||||
if(item.id===e.target.value){
|
||||
item.checkedBatch = e.target.checked;
|
||||
}
|
||||
item.checkedBatch?checkboxNum++:"";
|
||||
});
|
||||
setMessageList(messageListNew);
|
||||
setSelectedNum(checkboxNum);
|
||||
setBatchDeleteCheckAll(checkboxNum === messageList.length);
|
||||
}
|
||||
|
||||
|
||||
function onChangeAll(e) {
|
||||
setBatchDeleteCheckAll(e.target.checked);
|
||||
setSelectedNum(e.target.checked?messageList.length:0);
|
||||
let messageListNew=messageList.slice();
|
||||
messageListNew.map((item)=>{
|
||||
item.checkedBatch = e.target.checked;
|
||||
});
|
||||
setMessageList(messageListNew);
|
||||
}
|
||||
|
||||
function deleteNotice(id) {
|
||||
const ids = [];
|
||||
if(!id){
|
||||
messageList.map(item=>{
|
||||
item.checkedBatch && ids.push(item.id);
|
||||
});
|
||||
}
|
||||
DelModal({
|
||||
title: noticeType === "1" ? '删除私信用户' : id ? '删除消息' : '批量删除',
|
||||
contentTitle: noticeType === "1" ? '您确定要删除与 xxx 的聊天吗?' : id ? '您确定要删除这条@我消息吗?' : '您确定要删除选中的' + selectedNum + '条消息吗?',
|
||||
content: noticeType === "1" ? '此操作将删除与xxx的聊天框和xxx的所有聊天记录,请进行确认以防数据的丢失' : id ? '此操作将删除这条消息,请进行确认以防数据的丢失' : '此操作将删除选中的' + selectedNum + '条消息,请进行确认以防数据的丢失',
|
||||
onOk: () => {
|
||||
const params = {
|
||||
type: noticeType === "0" ? "notification" : noticeType === "2" ? "atme" : "",
|
||||
ids:id?id:ids,
|
||||
};
|
||||
axios.delete(`/users/${current_user.login}/messages.json`,{
|
||||
data:params,
|
||||
}).then((response)=>{
|
||||
if(response.status === 200){
|
||||
getMessageList();
|
||||
//删除当前页码最后一条数据时跳转到前一页
|
||||
let totlaPage = Math.ceil((messTotalCount-1)/pageSize);
|
||||
setCurrentPage(currentPage>=totlaPage? totlaPage : currentPage);
|
||||
setSelectedNum(0);
|
||||
setBatchDeleteCheckAll(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function cancelBatchDelete(){
|
||||
setIsBatchDelete(false);
|
||||
setSelectedNum(0);
|
||||
//取消选中效果
|
||||
let messageListNew=messageList.slice();
|
||||
messageListNew.map((item)=>{
|
||||
item.checkedBatch = false;
|
||||
});
|
||||
setMessageList(messageListNew);
|
||||
setBatchDeleteCheckAll(false);
|
||||
}
|
||||
|
||||
//跳转到消息详情页面
|
||||
function turnToMess(item){
|
||||
if(item.notification_url){
|
||||
window.open(`${item.notification_url}`);
|
||||
readNotice([item.id]);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="notice01">
|
||||
<div className="sshHead">
|
||||
<Menu mode="horizontal" selectedKeys={noticeType} onClick={handleClick}>
|
||||
<Menu.Item key="0"><Badge count={noticeUnreadCount} title="">系统通知</Badge></Menu.Item>
|
||||
{/* <Menu.Item key="1" id="item-private"><Badge count={0}>私信</Badge></Menu.Item> */}
|
||||
<Menu.Item key="2"><Badge count={atUnreadCount}>@我</Badge></Menu.Item>
|
||||
</Menu>
|
||||
{(noticeType==="0" && noticeUnreadCount>0) || (noticeType==="2"&& atUnreadCount>0) ? <button className="but25" onClick={()=>{readNotice([-1])}}>所有{noticeType === "0" ? "系统通知" : noticeType === "1" ? "私信" : "@我"}一键已读</button>:""}
|
||||
</div>
|
||||
|
||||
<div className={isBatchDelete ? "invisible " : "visible"}>
|
||||
<div className="vertical-center-style">
|
||||
{onlyUnread===1 || messageList && messageList.length>0 ? <Checkbox checked={onlyUnread} onChange={(e) => e.target.checked ? setOnlyUnread(1) : setOnlyUnread()}>仅看未读{noticeType === "1" ? `私信(12)` : noticeType === "0" ? `消息(${noticeUnreadCount})` : `消息(${atUnreadCount})`}</Checkbox>:""}
|
||||
</div>
|
||||
{noticeType === "2" && messageList && messageList.length > 0 ? <button className="batchDeleteBut" onClick={() => { setIsBatchDelete(true); }}>批量删除</button> : ""}
|
||||
</div>
|
||||
|
||||
{messageList && messageList.length===0 ? <NoneData _html="暂无相关消息"/>:""}
|
||||
|
||||
{messageList && messageList.length>0 && <div className={isBatchDelete ? 'visible' : 'invisible'}>
|
||||
<div className="vertical-center-style">
|
||||
<Checkbox onChange={onChangeAll} checked={batchDeleteCheckedAll}>全选</Checkbox>
|
||||
已选择 <span className="numberSpan">{selectedNum}</span> 项
|
||||
</div>
|
||||
<div>
|
||||
<button onClick={cancelBatchDelete}>取消</button>
|
||||
<button className="deleteBut" onClick={selectedNum > 0 ? ()=>deleteNotice() : () => { }}>删除</button>
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
{messageList && messageList.map(item => {
|
||||
// 系统消息
|
||||
if (noticeType === "0") {
|
||||
// 消息类别
|
||||
return (
|
||||
<div className="mynotice-content vertical-center-style" key={item.id}>
|
||||
<div className="mynotice-cont stretch-style">
|
||||
{item.status === 1 ? <Badge color="#FA2020" /> : <span className="system-notice-blank"></span>}
|
||||
<i className={"iconfont "+noticeSourceType[item.source]}></i>
|
||||
<span className={`sysNotice-length ${item.notification_url?'highlightSpan':''}`} onClick={() => {turnToMess(item)}} dangerouslySetInnerHTML={{__html: item.content}}></span>
|
||||
</div>
|
||||
<div className="mynotice-cont vertical-center-style float-left-little">
|
||||
<span className={item.status === 1?"timeSpan":""}>{item.time_ago}</span>
|
||||
{item.status === 1 && <span className="invisable-read" onClick={()=>readNotice([item.id])}>标记为已读</span>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
} else if (noticeType === "2") {
|
||||
//@我
|
||||
return (
|
||||
<div className={`mynotice-content vertical-center-style ${isBatchDelete?'batchDel':''}`} key={item.id}>
|
||||
<div className="mynotice-cont vertical-center-style">
|
||||
<Checkbox value={item.id} className={isBatchDelete ? 'visible-checkbox' : 'invisible-checkbox'} onChange={onChange} checked={item.checkedBatch}></Checkbox>
|
||||
{item.sender && <img src={`https://testforgeplus.trustie.net//${item.sender.image_url}`} className="currentImg" onClick={()=>{window.open(`/${item.sender && item.sender.login}`);}}/>}
|
||||
<div className={`atme-notice-text stretch-style ${item.notification_url && 'highlightSpan'}`} onClick={() => {turnToMess(item)}}>
|
||||
{item.status === 1 ? <Badge color="#FA2020"/> : <span className="system-notice-blank"></span>}
|
||||
{item.sender && <span className="atme-length" dangerouslySetInnerHTML={{__html: "<b class = 'atme-notice-name'>" + item.sender.name+ "</b> "+ item.content +" 中@我"}}></span>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mynotice-cont vertical-center-style">
|
||||
<span className={!isBatchDelete && item.status === 1?"timeSpan":""}>{item.time_ago}</span>
|
||||
{!isBatchDelete && item.status === 1 && <span className="invisable-read" onClick={()=>readNotice([item.id])}>标记为已读</span>}
|
||||
{!isBatchDelete && <span className="invisable-read float-left-little" onClick={()=>deleteNotice([item.id])}>删除</span>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
} else{
|
||||
//私信
|
||||
{/* <div className="mynotice-content vertical-center-style">
|
||||
<Badge count={95}><img src="https://testforgeplus.trustie.net//system/lets/letter_avatars/2/D/208_124_118/120.png" className="currentImg private-letter-img" /></Badge>
|
||||
<div className="private-letter-right">
|
||||
<div>
|
||||
<span>蒋宇航</span>
|
||||
<span className="timeSpan">4分钟前</span>
|
||||
<a onClick={deleteNotice}>删除</a>
|
||||
</div>
|
||||
<div onClick={() => props.history.push('/settings/notice/privateLetter')}>
|
||||
<span className="highlightSpan letter-length-limit">最好的OpenStack控制台,对标OpenStack社区Horizon项目,最好的OpenStack控制台,对标OpenStack社区Horizon项目,在易用性、页面性能等方面进行深度优化,提供简单控制台。</span>
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
}
|
||||
})}
|
||||
|
||||
{/* 分页 */}
|
||||
{!isBatchDelete && <div className="paging">
|
||||
<Pagination
|
||||
simple
|
||||
current = {currentPage}
|
||||
pageSize={pageSize}
|
||||
onChange={(page)=>{setCurrentPage(page)}}
|
||||
total = {messTotalCount}
|
||||
hideOnSinglePage
|
||||
></Pagination>
|
||||
</div>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default MyNotice;
|
|
@ -0,0 +1,259 @@
|
|||
.whiteBack .boies .sshHead{
|
||||
padding:0 10px 0px 0px;
|
||||
}
|
||||
.sshHead{
|
||||
.ant-badge{
|
||||
font-size: 16px;
|
||||
color: #333333;
|
||||
}
|
||||
.ant-menu-item{
|
||||
padding:0px;
|
||||
margin-right:34px!important;
|
||||
height: 34px;
|
||||
width: 64px;
|
||||
text-align: center;
|
||||
line-height: 0px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
li.ant-menu-item, .ant-menu-horizontal > .ant-menu-item {
|
||||
border-bottom: 0px;
|
||||
}
|
||||
|
||||
& .ant-menu-item-selected{
|
||||
color: #333333;
|
||||
font-weight: 400;
|
||||
text-shadow: 0.5px 0 #333;
|
||||
border-bottom: 2px solid #2A61FF !important;
|
||||
}
|
||||
|
||||
.ant-badge-count, .ant-badge-dot, .ant-badge .ant-scroll-number-custom-component {
|
||||
right: -6px;
|
||||
-webkit-box-shadow: 0 0 0 0;
|
||||
box-shadow: 0 0 0 0;
|
||||
}
|
||||
.ant-badge-multiple-words {
|
||||
padding: 0 0px;
|
||||
}
|
||||
|
||||
.ant-menu-horizontal {
|
||||
border-bottom: 0px solid #e8e8e8;
|
||||
}
|
||||
|
||||
button{
|
||||
padding:0 5px;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
color: #333333;
|
||||
background: #FAFBFC;
|
||||
border: 1px solid #D0D0D0;
|
||||
border-radius: 4px;
|
||||
height: 32px;
|
||||
}
|
||||
button:hover {
|
||||
background: #F3F4F6;
|
||||
}
|
||||
button:active {
|
||||
background: #EBECF0;
|
||||
}
|
||||
|
||||
.deleteBut{
|
||||
color: #DF0002;
|
||||
}
|
||||
|
||||
.deleteBut:hover{
|
||||
background: #DF0002;
|
||||
border: 1px solid #DF0002;
|
||||
color:#FFFFFF;
|
||||
}
|
||||
|
||||
.deleteBut:active{
|
||||
background: #CE0002;
|
||||
border: 1px solid #CE0002;
|
||||
color:#FFFFFF;
|
||||
}
|
||||
|
||||
.mynotice-content {
|
||||
justify-content: space-between;
|
||||
padding: 15px 0 15px 10px;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
color: #333333;
|
||||
&:hover{
|
||||
background: #F3F4F6;
|
||||
}
|
||||
|
||||
& img{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
& b{
|
||||
font-weight: 400;
|
||||
text-shadow: 0.5px 0 #333;
|
||||
}
|
||||
|
||||
& .invisable-read{
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover .invisable-read{
|
||||
display: block;
|
||||
color: #466AFF;
|
||||
opacity: 0.6;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover{
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .timeSpan{
|
||||
display: none;
|
||||
}
|
||||
|
||||
i{
|
||||
font-size: 16px !important;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.boldSpan{
|
||||
font-weight: 400;
|
||||
text-shadow: 0.5px 0 0 #333;
|
||||
margin: 0 8px;
|
||||
}
|
||||
& .currentImg{
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
& .private-letter-img + .ant-badge-count{
|
||||
top: 2px;
|
||||
right: 5px;
|
||||
height: 18px;
|
||||
min-width: 18px;
|
||||
line-height: 18px;
|
||||
padding: 0 0;
|
||||
}
|
||||
|
||||
& .highlightSpan:hover{
|
||||
color: #466AFF;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mynotice-cont{
|
||||
padding:0;
|
||||
cursor: default;
|
||||
& .visible-checkbox{
|
||||
margin-right: 10px;
|
||||
}
|
||||
& .invisible-checkbox{
|
||||
display: none;
|
||||
}
|
||||
.atme-notice-text{
|
||||
margin-left: 6px;
|
||||
|
||||
& .atme-notice-name{
|
||||
margin: 0 0 ;
|
||||
}
|
||||
|
||||
& .atme-length{
|
||||
max-width: 48rem;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& .ant-badge-count, .ant-badge-dot, .ant-badge .ant-scroll-number-custom-component {
|
||||
-webkit-box-shadow: 0 0 0 0;
|
||||
box-shadow: 0 0 0 0;
|
||||
top: 3px;
|
||||
right: 4px;
|
||||
min-width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
& .system-notice-blank{
|
||||
margin-right: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.batchDel{
|
||||
& .currentImg, & .atme-notice-text{
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.baselineDiv{
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.invisible {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.visible {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height: 30px;
|
||||
padding: 0 10px;
|
||||
color: #333333;
|
||||
margin-bottom: 5px;
|
||||
button{
|
||||
padding:0px 12px;
|
||||
}
|
||||
.batchDeleteBut{
|
||||
border:1px solid #466AFF;
|
||||
color: #466AFF;
|
||||
}
|
||||
}
|
||||
|
||||
.private-letter-right {
|
||||
flex: auto;
|
||||
margin: 0px 10px 0 16px;
|
||||
& div{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.letter-length-limit{
|
||||
max-width: 50rem;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.sysNotice-length{
|
||||
max-width: 52rem;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
|
||||
.numberSpan{
|
||||
color: #466AFF;
|
||||
}
|
||||
|
||||
.vertical-center-style{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.stretch-style{
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.float-left-little{
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.float-right-little{
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.paging{
|
||||
text-align: center;
|
||||
margin: 12px;
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import './Index.scss'
|
||||
import '../manager/Index.scss'
|
||||
import { Button, Input, Icon, Badge } from 'antd';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
function PrivateLetter(props){
|
||||
|
||||
const { TextArea,Search } = Input;
|
||||
|
||||
function deleteNotice(){
|
||||
alert("删除消息");
|
||||
}
|
||||
|
||||
return(
|
||||
<div className="private-letter notice01">
|
||||
<div className="pl-content">
|
||||
<div className="pl-name vertical-center-style">
|
||||
<Link to="/settings/notice/myNotice"><i className="iconfont icon-zuojiantou"></i></Link>
|
||||
<span>蒋宇航</span>
|
||||
</div>
|
||||
<div className="plcontent-list">
|
||||
<div className="vertical-center-style plclo">
|
||||
<img src="https://testforgeplus.trustie.net//system/lets/letter_avatars/2/D/208_124_118/120.png" className="currentImg"/>
|
||||
<div className="message-bubble mb-other"></div>
|
||||
<div className="notice-content vertical-center-style">
|
||||
嗨在吗?哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈
|
||||
<a className="pld01">删除</a>
|
||||
</div>
|
||||
<span>2021-08-29 11:59</span>
|
||||
</div>
|
||||
|
||||
<div className="notice-my vertical-center-style plclo">
|
||||
<img src="https://testforgeplus.trustie.net//system/lets/letter_avatars/2/D/208_124_118/120.png" className="currentImg"/>
|
||||
<div className="message-bubble"></div>
|
||||
<div className="notice-content vertical-center-style">
|
||||
哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈
|
||||
<a className="pld01">删除</a>
|
||||
</div>
|
||||
<span>2021-08-29 11:59</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className="private-letter-present">
|
||||
<div>
|
||||
<img src="https://testforgeplus.trustie.net//system/lets/letter_avatars/2/D/208_124_118/120.png" className="currentImg"/>
|
||||
<TextArea className="private-letter-cont" rows="2" />
|
||||
</div>
|
||||
<div className="presentNotice">
|
||||
<Button className="private-letter-cont-mt25 but25" type="primary">发送</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="pl-list">
|
||||
<div className="list-sort vertical-center-style">
|
||||
<Search
|
||||
className=""
|
||||
placeholder="搜索用户"
|
||||
enterButton={<i className="iconfont icon-sousuo"></i>}
|
||||
onSearch={value => console.log(value)}
|
||||
style={{ width: 265 }}
|
||||
/>
|
||||
</div>
|
||||
<div className="list-scroll">
|
||||
<div className="list-scroll-content vertical-center-style">
|
||||
<Badge count={5}><img src="https://testforgeplus.trustie.net//system/lets/letter_avatars/2/D/208_124_118/120.png" className="currentImg private-letter-img"/></Badge>
|
||||
<div className="private-letter-list-content-right">
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span>蒋宇航</span>
|
||||
<span className="private-letter-list-content-right-content-top-timeSpan">4分钟前</span>
|
||||
</div>
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span className="ls-content-span">最好的OpenStack控制台,对标OpenStack社区Horizon项目,在易用性、页面性能等方面进行深度优化,提供简单控制台。</span>
|
||||
<a onClick={deleteNotice}>删除</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="list-scroll-content vertical-center-style">
|
||||
<Badge count={5}><img src="https://testforgeplus.trustie.net//system/lets/letter_avatars/2/D/208_124_118/120.png" className="currentImg private-letter-img"/></Badge>
|
||||
<div className="private-letter-list-content-right">
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span>蒋宇航</span>
|
||||
<span className="private-letter-list-content-right-content-top-timeSpan">4分钟前</span>
|
||||
</div>
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span className="ls-content-span">最好的OpenStack控制台,对标OpenStack社区Horizon项目,在易用性、页面性能等方面进行深度优化,提供简单控制台。</span>
|
||||
<a onClick={deleteNotice}>删除</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="list-scroll-content vertical-center-style">
|
||||
<Badge count={5}><img src="https://testforgeplus.trustie.net//system/lets/letter_avatars/2/D/208_124_118/120.png" className="currentImg private-letter-img"/></Badge>
|
||||
<div className="private-letter-list-content-right">
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span>蒋宇航</span>
|
||||
<span className="private-letter-list-content-right-content-top-timeSpan">4分钟前</span>
|
||||
</div>
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span className="ls-content-span">最好的OpenStack控制台,对标OpenStack社区Horizon项目,在易用性、页面性能等方面进行深度优化,提供简单控制台。</span>
|
||||
<a onClick={deleteNotice}>删除</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="list-scroll-content vertical-center-style">
|
||||
<Badge count={5}><img src="https://testforgeplus.trustie.net//system/lets/letter_avatars/2/D/208_124_118/120.png" className="currentImg private-letter-img"/></Badge>
|
||||
<div className="private-letter-list-content-right">
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span>蒋宇航</span>
|
||||
<span className="private-letter-list-content-right-content-top-timeSpan">4分钟前</span>
|
||||
</div>
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span className="ls-content-span">最好的OpenStack控制台,对标OpenStack社区Horizon项目,在易用性、页面性能等方面进行深度优化,提供简单控制台。</span>
|
||||
<a onClick={deleteNotice}>删除</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="list-scroll-content vertical-center-style">
|
||||
<Badge count={5}><img src="https://testforgeplus.trustie.net//system/lets/letter_avatars/2/D/208_124_118/120.png" className="currentImg private-letter-img"/></Badge>
|
||||
<div className="private-letter-list-content-right">
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span>蒋宇航</span>
|
||||
<span className="private-letter-list-content-right-content-top-timeSpan">4分钟前</span>
|
||||
</div>
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span className="ls-content-span">最好的OpenStack控制台,对标OpenStack社区Horizon项目,在易用性、页面性能等方面进行深度优化,提供简单控制台。</span>
|
||||
<a onClick={deleteNotice}>删除</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="list-scroll-content vertical-center-style">
|
||||
<Badge count={5}><img src="https://testforgeplus.trustie.net//system/lets/letter_avatars/2/D/208_124_118/120.png" className="currentImg private-letter-img"/></Badge>
|
||||
<div className="private-letter-list-content-right">
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span>蒋宇航</span>
|
||||
<span className="private-letter-list-content-right-content-top-timeSpan">4分钟前</span>
|
||||
</div>
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span className="ls-content-span">最好的OpenStack控制台,对标OpenStack社区Horizon项目,在易用性、页面性能等方面进行深度优化,提供简单控制台。</span>
|
||||
<a onClick={deleteNotice}>删除</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="list-scroll-content vertical-center-style">
|
||||
<Badge count={5}><img src="https://testforgeplus.trustie.net//system/lets/letter_avatars/2/D/208_124_118/120.png" className="currentImg private-letter-img"/></Badge>
|
||||
<div className="private-letter-list-content-right">
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span>蒋宇航</span>
|
||||
<span className="private-letter-list-content-right-content-top-timeSpan">4分钟前</span>
|
||||
</div>
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span className="ls-content-span">最好的OpenStack控制台,对标OpenStack社区Horizon项目,在易用性、页面性能等方面进行深度优化,提供简单控制台。</span>
|
||||
<a onClick={deleteNotice}>删除</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="list-scroll-content vertical-center-style">
|
||||
<Badge count={5}><img src="https://testforgeplus.trustie.net//system/lets/letter_avatars/2/D/208_124_118/120.png" className="currentImg private-letter-img"/></Badge>
|
||||
<div className="private-letter-list-content-right">
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span>蒋宇航</span>
|
||||
<span className="private-letter-list-content-right-content-top-timeSpan">4分钟前</span>
|
||||
</div>
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span className="ls-content-span">最好的OpenStack控制台,对标OpenStack社区Horizon项目,在易用性、页面性能等方面进行深度优化,提供简单控制台。</span>
|
||||
<a onClick={deleteNotice}>删除</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="list-scroll-content vertical-center-style">
|
||||
<Badge count={5}><img src="https://testforgeplus.trustie.net//system/lets/letter_avatars/2/D/208_124_118/120.png" className="currentImg private-letter-img"/></Badge>
|
||||
<div className="private-letter-list-content-right">
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span>蒋宇航</span>
|
||||
<span className="private-letter-list-content-right-content-top-timeSpan">4分钟前</span>
|
||||
</div>
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span className="ls-content-span">最好的OpenStack控制台,对标OpenStack社区Horizon项目,在易用性、页面性能等方面进行深度优化,提供简单控制台。</span>
|
||||
<a onClick={deleteNotice}>删除</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="list-scroll-content vertical-center-style">
|
||||
<Badge count={5}><img src="https://testforgeplus.trustie.net//system/lets/letter_avatars/2/D/208_124_118/120.png" className="currentImg private-letter-img"/></Badge>
|
||||
<div className="private-letter-list-content-right">
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span>蒋宇航</span>
|
||||
<span className="private-letter-list-content-right-content-top-timeSpan">4分钟前</span>
|
||||
</div>
|
||||
<div className="ls-cont vertical-center-style">
|
||||
<span className="ls-content-span">最好的OpenStack控制台,对标OpenStack社区Horizon项目,在易用性、页面性能等方面进行深度优化,提供简单控制台。</span>
|
||||
<a onClick={deleteNotice}>删除</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default PrivateLetter;
|
|
@ -0,0 +1,192 @@
|
|||
.private-letter{
|
||||
border-radius: 4px 4px 0px 0px;
|
||||
border: 1px solid rgba(151, 151, 151, 0.24);
|
||||
display: flex;
|
||||
|
||||
.currentImg{
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
& .private-letter-img + .ant-badge-count{
|
||||
top: 2px;
|
||||
right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.pl-content{
|
||||
flex: auto;
|
||||
.pl-name{
|
||||
height: 3rem;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
|
||||
&>a{
|
||||
position: relative;
|
||||
left: 26px;
|
||||
color:#999999;
|
||||
}
|
||||
span{
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
flex: auto;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.plcontent-list{
|
||||
height: 24rem;
|
||||
padding:20px;
|
||||
overflow-y: scroll;
|
||||
|
||||
.plclo{
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.notice-my{
|
||||
flex-direction: row-reverse;
|
||||
|
||||
& .pld01{
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
& .notice-content{
|
||||
padding:8px 10px;
|
||||
background: #F4F4F4;
|
||||
border-radius:5px;
|
||||
position: relative;
|
||||
max-width: 20rem;
|
||||
|
||||
.pld01{
|
||||
display: none;
|
||||
|
||||
}
|
||||
&:hover .pld01{
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: -2em;
|
||||
color: #999999;
|
||||
font-size: 12px;
|
||||
&:hover{
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& .message-bubble{
|
||||
position:relative;
|
||||
width:0;
|
||||
height:0;
|
||||
font-size:0;
|
||||
border:solid 8px;
|
||||
border-color:#FFFFFF #FFFFFF #FFFFFF #F4F4F4;
|
||||
}
|
||||
|
||||
& .mb-other{
|
||||
border-color:#FFFFFF #F4F4F4 #FFFFFF #FFFFFF;
|
||||
}
|
||||
|
||||
& span{
|
||||
margin: 0 10px;
|
||||
font-size: 12px;
|
||||
color: #999999;
|
||||
line-height: 17px;
|
||||
}
|
||||
}
|
||||
.private-letter-present{
|
||||
padding:20px 20px;
|
||||
& div{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
flex: auto;
|
||||
}
|
||||
.private-letter-cont-mt25{
|
||||
margin-top: 8px;
|
||||
padding:0 22px;
|
||||
}
|
||||
|
||||
.private-letter-cont, .private-letter-cont .ant-input-suffix{
|
||||
background-color: #fafafa !important;
|
||||
margin-left: 17px;
|
||||
}
|
||||
|
||||
.private-letter-cont{
|
||||
resize:none;
|
||||
&:hover,&:focus{
|
||||
background-color: #fafafa !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pl-list{
|
||||
width: 30%;
|
||||
border-left: 1px solid #EEEEEE;
|
||||
.list-sort{
|
||||
justify-content: center;
|
||||
height: 3rem;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
& .ant-btn-primary{
|
||||
width: 2.3rem;
|
||||
color: #466AFF;
|
||||
background: #eff2ff;
|
||||
border: 1px solid rgba(151, 151, 151, 0.24);
|
||||
}
|
||||
|
||||
& .ant-btn{
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// & .ant-input:hover{
|
||||
// border: 1px solid red !important;
|
||||
// }
|
||||
}
|
||||
|
||||
.list-scroll{
|
||||
height: 32.4rem;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.list-scroll-content{
|
||||
padding: 10px 10px 15px 15px;
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
// &:last-child{
|
||||
// border-bottom: 0px;
|
||||
// }
|
||||
&:hover{
|
||||
background: #F3F4F6;
|
||||
}
|
||||
& a{
|
||||
display: none;
|
||||
}
|
||||
&:hover a{
|
||||
display: block;
|
||||
color: #466AFF;
|
||||
}
|
||||
}
|
||||
|
||||
.ls-cont{
|
||||
width: 13rem;
|
||||
// flex: auto;
|
||||
margin-left: 15px;
|
||||
justify-content: space-between;
|
||||
& .ls-content-span{
|
||||
max-width: 11rem;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vertical-center-style{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
img{
|
||||
width: 45x;
|
||||
height: 45px;
|
||||
}
|
|
@ -34,7 +34,7 @@ function New({ form , showNotification , history }) {
|
|||
return(
|
||||
<div>
|
||||
<div className="sshHead">
|
||||
<span><Link to={`/settings/SSH`} className="color-blue">SSH密钥</Link><i className="iconfont icon-youjiantou ml5 mr5 font-12"></i>添加SSH密钥</span>
|
||||
<span className="add-SSH-title"><Link to={`/settings/SSH`} className="blue-Purple">SSH密钥</Link><i className="iconfont icon-youjiantou ml5 mr5 font-12"></i>添加SSH密钥</span>
|
||||
</div>
|
||||
<Form className="sshForm">
|
||||
<Form.Item label="标题" validateStatus={msg && msg.status === 10001 ? "error":undefined} help={msg && msg.status === 10001 ? msg.message:undefined}>
|
||||
|
@ -51,7 +51,7 @@ function New({ form , showNotification , history }) {
|
|||
<TextArea placeholder="支持以'ssh-rsa','ssh-dss','ssh-ed25519','ecdsa-sha2-nistp256','ecdsa-sha2-nistp384','ecdsa-sha2-nistp521'开头" autoSize={{ minRows: 6, maxRows: 6 }}/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Button type="primary" style={{width:"100px"}} onClick={submit}>确定</Button>
|
||||
<button style={{width:"100px"}} onClick={submit} className="but25">确定</button>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -55,8 +55,8 @@ function SSH(props) {
|
|||
<DeleteBox visible={visible} onCancel={()=>setVisible(false)} onSuccess={onSuccess}/>
|
||||
<SSHDetail visible={visibleDesc} onCancel={()=>setVisibleDesc(false)} desc={content}/>
|
||||
<div className="sshHead">
|
||||
<span>SSH密钥</span>
|
||||
<Button type="primary" size="large" onClick={()=>props.history.push('/settings/SSH/new')}>添加SSH密钥</Button>
|
||||
<span className="text-shadow07">SSH密钥</span>
|
||||
<button type="primary" size="large" onClick={()=>props.history.push('/settings/SSH/new')} className="but25">添加SSH密钥</button>
|
||||
</div>
|
||||
{
|
||||
list && list.length > 0 &&
|
||||
|
@ -64,7 +64,7 @@ function SSH(props) {
|
|||
{
|
||||
list.map((i,k)=>{
|
||||
return(
|
||||
<List.Item>
|
||||
<List.Item key={i.id}>
|
||||
<img src={miyao} alt=""/>
|
||||
<div>
|
||||
<p className="color-grey-3"><a className="task-hide" style={{display:"block",fontWeight:"500"}} onClick={()=>{setContent(i);setVisibleDesc(true)}}>{i.name}</a></p>
|
||||
|
|
|
@ -102,8 +102,8 @@ class Index extends Component {
|
|||
>
|
||||
<p>
|
||||
<Link to={`/${owner}/${projectsId}/settings/labels`} className="w-100">
|
||||
<i className="iconfont icon-biaoqian3 font-18 mr10 color-grey-6"></i>
|
||||
项目标签
|
||||
<i className="iconfont icon-xiangmubiaoqian font-18 mr10 color-grey-6"></i>
|
||||
项目标记
|
||||
</Link>
|
||||
</p>
|
||||
</li>
|
||||
|
|
|
@ -295,23 +295,23 @@ class Setting extends Component {
|
|||
</Form.Item>
|
||||
<Form.Item label="项目类别">
|
||||
{getFieldDecorator("project_category_id", {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: "请选择大类别",
|
||||
},
|
||||
],
|
||||
})(<Select>{CategoryList}</Select>)}
|
||||
rules: [],
|
||||
})(
|
||||
<Select>
|
||||
<Option key={0} value={""}>未选择项目类别</Option>
|
||||
{CategoryList}
|
||||
</Select>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item label="项目语言">
|
||||
{getFieldDecorator("project_language_id", {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: "请选择项目语言",
|
||||
},
|
||||
],
|
||||
})(<Select>{LanguageList}</Select>)}
|
||||
rules: [],
|
||||
})(
|
||||
<Select>
|
||||
<Option key={0} value={""}>未选择项目语言</Option>
|
||||
{LanguageList}
|
||||
</Select>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item label="项目导航">
|
||||
{getFieldDecorator("project_units", {
|
||||
|
|
|
@ -258,11 +258,11 @@ function New({ form , match , showNotification , history }) {
|
|||
</span> */}
|
||||
<span>
|
||||
<Checkbox value="create">创建</Checkbox>
|
||||
<span>创建分支或标签</span>
|
||||
<span>创建分支或标记</span>
|
||||
</span>
|
||||
<span>
|
||||
<Checkbox value="delete">删除</Checkbox>
|
||||
<span>删除分支或标签</span>
|
||||
<span>删除分支或标记</span>
|
||||
</span>
|
||||
</div>
|
||||
<p className="color-grey-3 mt10 mb10">合并请求事件</p>
|
||||
|
|
|
@ -348,7 +348,7 @@ class NewTags extends Component {
|
|||
</a>
|
||||
<Popconfirm
|
||||
placement="bottom"
|
||||
title={"删除标签会将其从所有引用中删除。继续?"}
|
||||
title={"删除标记会将其从所有引用中删除,是否继续?"}
|
||||
okText="是"
|
||||
cancelText="否"
|
||||
onConfirm={() => this.deletetag(item.id)}
|
||||
|
@ -383,7 +383,7 @@ class NewTags extends Component {
|
|||
return (
|
||||
<div>
|
||||
<div className="topWrapper" style={{borderBottom:"1px solid #eee"}}>
|
||||
<span>共{data && data.issue_tags_count}个标签</span>
|
||||
<span>共{data && data.issue_tags_count}个标记</span>
|
||||
<ul className="topWrapper_select">
|
||||
<li>
|
||||
<Dropdown
|
||||
|
@ -393,7 +393,7 @@ class NewTags extends Component {
|
|||
placement="bottomCenter"
|
||||
>
|
||||
<span>
|
||||
标签
|
||||
标记
|
||||
<Icon type="caret-down" className="ml5" />
|
||||
</span>
|
||||
</Dropdown>
|
||||
|
@ -423,11 +423,11 @@ class NewTags extends Component {
|
|||
className="flex-a-center baseForm bbr"
|
||||
style={{ "justify-content": "space-between" }}
|
||||
>
|
||||
<span className="font-18 text-black">项目标签</span>
|
||||
<span className="font-18 text-black">项目标记</span>
|
||||
{data && data.user_admin_or_member ? (
|
||||
<Button type="primary" ghost onClick={this.newshow}>
|
||||
<Icon type="plus"></Icon>
|
||||
创建标签
|
||||
创建标记
|
||||
</Button>
|
||||
) : (
|
||||
""
|
||||
|
@ -442,7 +442,7 @@ class NewTags extends Component {
|
|||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: "请填写标签名字",
|
||||
message: "请填写标记名字",
|
||||
},
|
||||
],
|
||||
})(<Input placeholder="名称,10字以内" maxLength="10" />)}
|
||||
|
@ -481,7 +481,7 @@ class NewTags extends Component {
|
|||
onClick={this.createtagpost}
|
||||
className="fr"
|
||||
>
|
||||
创建标签
|
||||
创建标记
|
||||
</Button>
|
||||
{/* <a onClick={this.createtagpost} className="topWrapper_btn fr" >创建标签</a> */}
|
||||
<a onClick={this.newclose} className="a_btn cancel_btn fr">
|
||||
|
@ -497,7 +497,7 @@ class NewTags extends Component {
|
|||
</div>
|
||||
</div>
|
||||
<Modal
|
||||
title="编辑标签"
|
||||
title="编辑标记"
|
||||
onCancel={this.handleCancel}
|
||||
visible={this.state.isShow}
|
||||
onOk={this.handleok}
|
||||
|
|
|
@ -21,7 +21,7 @@ function AddTag({form , visible , onCancel ,onOk}){
|
|||
};
|
||||
return(
|
||||
<Modal
|
||||
title={"新增标签"}
|
||||
title={"新增标记"}
|
||||
closable={false}
|
||||
visible={visible}
|
||||
onCancel={onCancel}
|
||||
|
@ -32,11 +32,11 @@ function AddTag({form , visible , onCancel ,onOk}){
|
|||
centered
|
||||
>
|
||||
<Form {...layout}>
|
||||
<Form.Item label="标签名">
|
||||
<Form.Item label="标记名">
|
||||
{getFieldDecorator("tagName",{
|
||||
rules:[{required:true,message:"请输入标签名"}]
|
||||
rules:[{required:true,message:"请输入标记名"}]
|
||||
})(
|
||||
<Input placeholder="请输入标签名" width="200px" autoComplete="off" />
|
||||
<Input placeholder="请输入标记名" width="200px" autoComplete="off" />
|
||||
)}
|
||||
</Form.Item>
|
||||
</Form>
|
||||
|
|
|
@ -141,7 +141,7 @@ function Index(props){
|
|||
params:{id,tagName:tag}
|
||||
}).then(result=>{
|
||||
if(result && result.data){
|
||||
props.showNotification("标签删除成功");
|
||||
props.showNotification("标记删除成功");
|
||||
setIsSpin(true);
|
||||
getData();
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ export default ((props)=>{
|
|||
<div className="teamDetail" style={{paddingTop:"0px"}}>
|
||||
<div>
|
||||
<i className="iconfont icon-zuobiao mr5"></i>
|
||||
<Link to={`/${OIdentifier}`}>{OIdentifier}</Link>
|
||||
<Link to={`/${OIdentifier}`}>{detail && detail.organization && detail.organization.nickname}</Link>
|
||||
<i className="iconfont icon-youjiantou ml3 mr3 font-12 color-grey-9"></i>
|
||||
<span className="color-grey-9">{detail ? detail.name : "新建团队"}</span>
|
||||
</div>
|
||||
|
|
|
@ -198,7 +198,7 @@ class comments extends Component {
|
|||
</span>
|
||||
<span>
|
||||
{item.value && item.value.length > 0 ? (
|
||||
item.detail === "标签" ? (
|
||||
item.detail === "标记"? (
|
||||
<span
|
||||
className="issue-tag-show"
|
||||
style={{ background: item.value[0].color }}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
export const noticeSourceType = {
|
||||
// 易修
|
||||
IssueAssigned:"icon-yixiuicon1", // 有新指派给我的易修
|
||||
IssueAssignerExpire:"icon-yixiuicon1", // 我负责的易修截止日期到达最后一天
|
||||
IssueAtme:"icon-yixiuicon1", // 在易修中@我
|
||||
IssueChanged:"icon-yixiuicon1", // 我创建或负责的易修状态变更
|
||||
IssueCreatorExpire:"icon-yixiuicon1", // 我创建的易修截止日期到达最后一天
|
||||
IssueDelete:"icon-yixiuicon1", // 我创建或负责的易修删除
|
||||
IssueDeleted:"icon-yixiuicon1", // 我创建或负责的易修删除
|
||||
IssueJournal:"icon-yixiuicon1", // 我创建或负责的易修有新的评论
|
||||
//平台通知
|
||||
LoginIpTip:"icon-xitongtongzhiicon", //登录异常提示
|
||||
//个人状态类通知
|
||||
OrganizationJoined:"icon-xiaoxi2", // 账号被拉入组织
|
||||
OrganizationLeft:"icon-xiaoxi2", // 账号被移出组织
|
||||
OrganizationRole:"icon-xiaoxi2", // 账号组织权限变更
|
||||
ProjectJoined:"icon-xiaoxi2", // 账号被拉入项目
|
||||
ProjectLeft:"icon-xiaoxi2", // 账号被移出项目
|
||||
ProjectRole:"icon-xiaoxi2", // 账号仓库权限变更
|
||||
|
||||
//其他仓库通知
|
||||
ProjectDelete:"icon-daimakuicon1", // 我关注的仓库被删除
|
||||
ProjectFollowed:"icon-daimakuicon1", // 我管理的仓库被关注
|
||||
ProjectForked:"icon-daimakuicon1", // 我管理的仓库被复刻
|
||||
ProjectIssue:"icon-daimakuicon1", // 我管理/关注的仓库有新的易修
|
||||
ProjectSettingChanged:"icon-daimakuicon1", // 我管理的仓库项目设置被更改
|
||||
ProjectTransfer:"icon-daimakuicon1", // 我关注的仓库被转移
|
||||
ProjectVersion:"icon-daimakuicon1", // 我关注的仓库有新的发行版
|
||||
ProjectMemberJoined:"icon-daimakuicon1", // 我管理的仓库有成员加入
|
||||
ProjectMemberLeft:"icon-daimakuicon1", // 我管理的仓库有成员移出
|
||||
ProjectPraised:"icon-daimakuicon1", // 我管理的仓库被点赞
|
||||
//合并请求类通知
|
||||
ProjectPullRequest:"icon-hebingqingqiuicon", // 我管理/关注的仓库有新的合并请求
|
||||
PullRequestAssigned:"icon-hebingqingqiuicon", // 有新指派给我的合并请求
|
||||
PullRequestAtme:"icon-hebingqingqiuicon", // 在合并请求中@我
|
||||
PullRequestChanged:"icon-hebingqingqiuicon", // 我创建或负责的合并请求状态变更
|
||||
PullRequestJournal:"icon-hebingqingqiuicon", // 我创建或负责的合并请求有新的评论
|
||||
PullRequestClosed:"icon-hebingqingqiuicon", // 提交的合并请求被拒绝
|
||||
PullRequestMerged:"icon-hebingqingqiuicon", // 提交的合并请求被合并
|
||||
PullRequestClosed:"icon-hebingqingqiuicon", // 提交的合并请求被关闭
|
||||
//里程碑
|
||||
ProjectMilestone:"icon-lichengbeiicon", // 我管理的仓库有新的里程碑
|
||||
};
|
|
@ -0,0 +1,105 @@
|
|||
import { notification ,message} from 'antd';
|
||||
import axios from 'axios';
|
||||
import cookie from 'react-cookies';
|
||||
import Login from './Wiki/components/Login';
|
||||
|
||||
export const TokenKey = 'autologin_trustie';
|
||||
export default function javaFetch(productUrl,testUrl,developUrl ){
|
||||
let actionUrl='';
|
||||
if (window.location.href.indexOf('localhost') > -1) {
|
||||
actionUrl = developUrl;
|
||||
} else if(window.location.href.indexOf('testforgeplus')>-1){
|
||||
actionUrl = testUrl;
|
||||
axios.defaults.withCredentials = true;
|
||||
}else if (window.location.href.indexOf('forgeplus') > -1) {
|
||||
actionUrl = productUrl;
|
||||
axios.defaults.withCredentials = true;
|
||||
}
|
||||
|
||||
// 创建axios实例
|
||||
const service = axios.create({
|
||||
baseURL: actionUrl,
|
||||
timeout: 10000, // 请求超时时间
|
||||
});
|
||||
|
||||
// request拦截器
|
||||
service.interceptors.request.use(config => {
|
||||
if (cookie.load(TokenKey)) {
|
||||
console.log(cookie.load(TokenKey));
|
||||
config.headers['Authorization'] = cookie.load(TokenKey); // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
if (window.location.port === "3007") {
|
||||
// 模拟token为登录用户
|
||||
const token = sessionStorage.token;
|
||||
if (config.url.indexOf('?') === -1) {
|
||||
config.url = `${config.url}?token=${token}`;
|
||||
} else {
|
||||
config.url = `${config.url}&token=${token}`;
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}, error => {
|
||||
console.log(error); // for debug
|
||||
// Promise.reject(error);
|
||||
});
|
||||
// respone拦截器
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
const res = response||{};
|
||||
if (res.status === 400) {
|
||||
message.error(res.data.message || '操作失败');
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (res.status === 401) {
|
||||
message.error(res.data.message || '登录信息已过期');
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (res.status === 403) {
|
||||
message.error(res.data.message || '无权限!');
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (res.status === 40001) {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: '账户或密码错误!',
|
||||
});
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (response.status !== 200 && res.status !== 200) {
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: res.message,
|
||||
});
|
||||
} else {
|
||||
return response.data;
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log(error);
|
||||
let res = error.response||{};
|
||||
if (res.status === 400) {
|
||||
message.error(res.data.message || '操作失败');
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (res.status === 401) {
|
||||
message.error(res.data.message || '登录信息已过期');
|
||||
Login();
|
||||
return Promise.reject('error');
|
||||
}
|
||||
if (res.status === 403) {
|
||||
message.error(res.data.message || '无权限!');
|
||||
return Promise.reject('error');
|
||||
}
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: error.message,
|
||||
});
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
console.log(service);
|
||||
console.log(typeof service);
|
||||
|
||||
return {service,actionUrl};
|
||||
}
|
|
@ -125,7 +125,7 @@ export default Form.create()(
|
|||
</Form.Item>
|
||||
<AlignCenter>
|
||||
<span className="ant-form-item-label"></span>
|
||||
<Button type={"primary"} onClick={submit}>提交</Button>
|
||||
<Button className="but25" type={"primary"} onClick={submit}>提交</Button>
|
||||
{/* <Button type={"default"} onClick={()=>props.history.push(`/${current_user && current_user.login}`)} className="ml20">取消</Button> */}
|
||||
</AlignCenter>
|
||||
</Form>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import React , { useEffect , useState } from 'react';
|
||||
import './Index.scss';
|
||||
import { Menu } from 'antd';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Base from './Base';
|
||||
import Password from './Password';
|
||||
import './Index.scss';
|
||||
import '../../SecuritySetting/notice/manager/Index.scss';
|
||||
|
||||
function Index(props){
|
||||
// const { username } = props && props.match && props.match.params;
|
||||
|
@ -25,11 +26,14 @@ function Index(props){
|
|||
|
||||
|
||||
return(
|
||||
<div>
|
||||
<Menu selectedKeys={[key]} mode={'horizontal'} className="infosRightMenu">
|
||||
<Menu.Item key="0"><Link to={`/settings/profile`}>基本资料</Link></Menu.Item>
|
||||
{/* <Menu.Item key="1"><Link to={`/${username}/password`}>密码管理</Link></Menu.Item> */}
|
||||
</Menu>
|
||||
<div className="notice01">
|
||||
<div className="sshHead">
|
||||
<Menu selectedKeys={[key]} mode={'horizontal'} className="infosRightMenu">
|
||||
<Menu.Item key="0"><Link to={`/settings/profile`}>基本资料</Link></Menu.Item>
|
||||
{/* <Menu.Item key="0"><Link to={`/settings/profile`}>基本资料</Link></Menu.Item> */}
|
||||
{/* <Menu.Item key="1"><Link to={`/${username}/password`}>密码管理</Link></Menu.Item> */}
|
||||
</Menu>
|
||||
</div>
|
||||
<div style={{padding:"20px"}}>
|
||||
{
|
||||
key === "0" ?
|
||||
|
|
|
@ -19,6 +19,12 @@
|
|||
.ant-menu-item{
|
||||
a{
|
||||
font-size: 16px;
|
||||
color: #333333;
|
||||
position: relative;
|
||||
bottom: -10px;
|
||||
}
|
||||
a:hover{
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -89,7 +89,7 @@ export default Form.create()(
|
|||
</Form.Item>
|
||||
<AlignCenter style={{marginTop:"20px"}}>
|
||||
<span className="ant-form-item-label"></span>
|
||||
<Button type={"primary"} onClick={submit}>提交</Button>
|
||||
<Button className="but25" type={"primary"} onClick={submit}>提交</Button>
|
||||
<Button type={"default"} onClick={()=>props.history.push(`/${username}`)} className="ml20">取消</Button>
|
||||
</AlignCenter>
|
||||
</Form>
|
||||
|
|
Loading…
Reference in New Issue