Merge pull request '合并代码' (#602) from gitlink_server into pre_gitlink_server

This commit is contained in:
durian 2023-12-22 13:54:54 +08:00
commit 61eb9ca07a
45 changed files with 832 additions and 113 deletions

16
package-lock.json generated
View File

@ -172,7 +172,7 @@
"dependencies": {
"jsesc": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
"resolved": "http://173.15.15.82:8081/repository/npm-all/jsesc/-/jsesc-2.5.2.tgz",
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
}
}
@ -245,7 +245,7 @@
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"resolved": "http://173.15.15.82:8081/repository/npm-all/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"requires": {
"ansi-styles": "^3.2.1",
@ -341,12 +341,12 @@
},
"globals": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
"resolved": "http://173.15.15.82:8081/repository/npm-all/globals/-/globals-11.12.0.tgz",
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"resolved": "http://173.15.15.82:8081/repository/npm-all/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
@ -7248,7 +7248,7 @@
},
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"resolved": "http://173.15.15.82:8081/repository/npm-all/promise/-/promise-7.3.1.tgz",
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
"requires": {
"asap": "~2.0.3"
@ -8202,7 +8202,7 @@
},
"fsevents": {
"version": "1.2.13",
"resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-1.2.13.tgz",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
"optional": true,
"requires": {
@ -9677,7 +9677,7 @@
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"resolved": "http://173.15.15.82:8081/repository/npm-all/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"requires": {
"ansi-styles": "^3.2.1",
@ -19704,7 +19704,7 @@
},
"fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"optional": true

View File

@ -177,7 +177,7 @@
"eslintConfig": {
"extends": "react-app"
},
"proxy": "http://localhost:3000",
"proxy": "http://172.20.32.202:4000",
"port": "3007",
"devDependencies": {
"@babel/runtime": "7.0.0-beta.51",

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="zh-CN" class="notranslate translated-ltr" translate="no">
<html lang="zh-hans-CN" class="notranslate translated-ltr" translate="no">
<head>
<meta charset="utf-8">
@ -20,7 +20,7 @@
<meta name="octolytics-dimension-repository_nwo" content="GitLink"></meta>
<meta name="octolytics-dimension-repository_network_root_nwo" content="GitLink"></meta>
<meta name="theme-color" content="#000000">
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" />
<!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" /> -->
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<meta name="twitter:image:src" content="https://www.gitlink.org.cn/images/logo.png">
<meta name="twitter:site" content="@gitlink">

View File

@ -32,7 +32,7 @@ export function initAxiosInterceptors(props) {
// 判断网络是否连接
initOnlineOfflineListener();
var proxy = "https://testforgeplus.trustie.net";
var proxy = "http://172.20.32.202:4000";
//响应前的设置
axios.interceptors.request.use(
@ -55,6 +55,7 @@ export function initAxiosInterceptors(props) {
config.url = url;
}
}
config.withCredentials = false;
return config;
},
err => {

View File

@ -140,10 +140,10 @@ export function setImagesUrl(path){
}
export function getUrl(path, goTest) {
const local = 'https://testforgeplus.trustie.net'
if (isDev) {
return `${local}${path?path:''}`
}
// const local = 'http://172.20.32.202:8080'
// if (isDev) {
// return `${local}${path?path:''}`
// }
return `${path ? path: ''}`;
}

View File

@ -205,7 +205,7 @@ function AboutUs(){
<img src={earth} className="earthImg"/>
<div className="statistics_cont df">
<div>
<CountUp {...countUpProps} start={0} end={50000} />
<CountUp {...countUpProps} start={0} end={85000} />
<p>开发者</p>
</div>
<div>
@ -275,7 +275,7 @@ function AboutUs(){
</div>
</div>
</Carousel>
<p className="delivery">简历投递邮箱zengyt#csxjy.com.cn 曾先生 (@符号替换#)</p>
<p className="delivery">简历投递邮箱48630328#qq.com 徐女士 (@符号替换#)</p>
</div>
</div>
{/* 精选组织 */}

View File

@ -27,7 +27,7 @@ function Releases({ owner, projectsId, releaseVersions, distribution }) {
})
:
<div className="mt8">
您暂未发布任何版本
暂无发行版
{distribution && <Link className="color-blue ml20" to={{pathname:`/${owner}/${projectsId}/releases/new`,state:{stable:true}}}>创建新版本</Link>}
</div>
}

View File

@ -0,0 +1,167 @@
import React from 'react';
import { Button, message } from 'antd';
import { getImageUrl } from 'educoder';
import MDEditor from "../../../../modules/tpm/challengesnew/tpm-md-editor";
import Upload from "../../../../forge/Upload/Index";
import Attachments from "../../../../forge/Upload/attachment";
import UploadImg from "../../../../forge/Images/upload.png";
import './list.scss';
import '../../../../forge/Order/order.scss';
import { useState } from 'react';
import { Link } from 'react-router-dom';
import axios from 'axios';
import { addComment, editComment } from '../../api'
function EditComment(props){
const {owner, projectsId, index} = props.match.params;
const {current_user, current_user:{login}, docId, showNotification, reloadComment, cancelMd, parentId, replyId, updateId, showUserImg=true} = props;
const [content, setContent] = useState(props.content);
const [quillFlag, setQuillFlag] = useState(false);
// loading
const [journalSpin, setJournalSpin] = useState(false);
const [atWhoLoginList, setAtWhoLoginList] = useState(undefined);
const [fileList, setFileList] = useState(undefined);
const [attachmentClean, setAttachmentClean] = useState(true);
const [ save , setSave ] = useState(undefined);
useState(()=>{
setSave(props.defaultFileList);
},[props.defaultFileList])
//
function addJournals(){
if(!content){
setQuillFlag(true);
return
}
setJournalSpin(true);
console.log(updateId)
if(updateId){
//
const params = {
id: updateId,
notes: content,
attachmentIds: fileList,
receivers_login:atWhoLoginList
}
editComment(docId, params).then(res=>{
if(res && res.data && res.data.data){
//
reloadComment();
message.success('评论成功');
cancelMd();
setContent(undefined);
}
setJournalSpin(false);
})
}else{
//
const params = {
parentId: parentId,
replyId: replyId,
notes: content,
attachmentIds: fileList,
}
addComment(docId, params).then(res=>{
if(res && res.data && res.data.data){
//
reloadComment();
message.success('评论成功');
cancelMd();
setContent(undefined);
}
setJournalSpin(false);
})
}
};
function deleteLoad(id){
let arr = [];
let list = save;
if(list && list.length>0 ){
arr = list.filter(i=>i.id !== id);
}
setFileList(arr.map(i=>{return i.id}));
setSave(arr);
}
function UploadFunc(f){
let list = [];
let arr = [];
if(save && save.length>0 ){
arr = save.map(i=>{return i.id});
}
list = arr && arr.length>0 ? f.concat(arr) : f ;
setFileList(list);
};
return(
<div className="grid-item-top pb10">
<Link
to={`/${current_user && current_user.login}`}
className="show-user-link mr10"
>
<img
className="radius"
src={getImageUrl(
`/${current_user && current_user.image_url}`
)}
alt=""
width="30"
height="30"
style={{display: showUserImg ? '' : 'none'}}
/>
</Link>
<div style={{position:"relative"}}>
<MDEditor
placeholder={"添加评论..."}
height={300}
mdID={"orderdetail-add-descriptions" + replyId}
initValue={content}
onChange={(value)=>{setQuillFlag(false);setContent(value);}}
changeAtWhoLoginList = {(loginList)=>{setAtWhoLoginList(loginList); setAttachmentClean(true)}}
owner = {owner}
projectsId = {projectsId}
></MDEditor>
<p className="quillFlagBox">
{quillFlag && <span>请输入评论内容</span>}
</p>
<Upload
className="commentStyle"
isComplete={attachmentClean}
load={UploadFunc}
icon={
<img
src={UploadImg}
width="58"
alt=""
style={{ marginBottom: 15 }}
/>
}
size={100}
showNotification={showNotification}
// defaultFileList={props.defaultFileList}
/>
{props.defaultFileList && props.defaultFileList.length > 0 &&
<Attachments
attachments={props.defaultFileList}
showNotification={props.showNotification}
canDelete={true}
deleteLoad={deleteLoad}
></Attachments>
}
<p className="clearfix mt20">
<Button
type="primary"
onClick={addJournals}
loading={journalSpin}
className="mr15 colorButton"
>
评论
</Button>
<Button className="colorButton2" onClick={()=>{cancelMd()}}>取消</Button>
</p>
</div>
</div>
)
}
export default EditComment;

View File

@ -0,0 +1,226 @@
import React, { useEffect, useState } from 'react';
import { Button, Popconfirm, Radio, Input, message, Tooltip, Spin, Pagination } from 'antd';
import axios from 'axios';
import { getImageUrl, timeAgo } from 'educoder';
import RenderHtml from '../../../../components/render-html';
import Attachment from '../../../Upload/attachment';
import EditComment from './editComment';
import Nodata from '../../../Nodata';
import CheckProfile from '../../../Component/ProfileModal/Profile';
import './list.scss';
import { Link } from 'react-router-dom';
import { getCommentList, deleteComment } from '../../api'
function IssueCommentList(props){
const{docId, history: {location}, reload, reloadComment, showNotification, current_user:{login, admin, image_url, username}, isManager, showLoginDialog, author} = props;
const {owner, projectsId, index} = props.match.params;
const [category, setCategory] = useState('comment');
const [journals, setJournals] = useState(undefined);
// /markdown1 2 3 4 5
const [showEdit, setShowEdit] = useState(false);
const [parentId, setParentId] = useState(undefined);
const [replyId, setReplyId] = useState(undefined);
// id
const [updateId, setUpdateId] = useState(undefined);
//
const [open, setOpen] = useState(undefined);
// css 线
const [spin, setSpin] = useState(false);
// issue
const [journalsCount, setJournalsCount] = useState(undefined);
//
const limit = 50;
const [page, setPage] = useState(1);
const [totalCount, setTotalCount] = useState(undefined);
// icon
const journalsIcon ={
'issue': 'icon-chuangjianqianbao',
'branch_name': 'icon-fenzhi3',
'assigner': 'icon-chengyuan2',
'status_id': 'icon-xiugaibaobiaomoban',
'fixed_version_id': 'icon-lichengbeiicon2',
'due_date': 'icon-riqi',
'issue_tag': 'icon-biaoji2',
'description': 'icon-xiugaibaobiaomoban',
'subject': 'icon-xiugaibaobiaomoban',
'start_date': 'icon-riqi',
'priority_id': 'icon-youxian',
'attachment': 'icon-xiugaibaobiaomoban'
}
useEffect(()=>{
setSpin(true);
let params = {
limit: limit,
page: page
}
getCommentList(docId, params).then(res=>{
if(res && res.data && res.data.data){
const {journals, total_comment_journals_count, total_count} = res.data.data;
if(category === 'all'){
const array = [];
let start = undefined;
let isJournalCount = 0;
journals.map((item, index)=>{
!isJournalCount && (start = index)
item.is_journal_detail && (isJournalCount++)
if(!item.is_journal_detail && isJournalCount < 10){
isJournalCount = 0;
return
}
if(isJournalCount >= 10 && (!item.is_journal_detail || journals.length-1 === index)){
array.push({start, count: isJournalCount});
isJournalCount = 0;
}
})
array.map((item, i)=>{
journals[item.start].numCount = item.count-1;
for (let index = 0; index < item.count; index++) {
journals[item.start+index].start = journals[item.start].id;
journals[item.start+index].closeAndSpan = true;
}
})
}
setTotalCount(total_count);
setJournalsCount(total_comment_journals_count);
setJournals(journals);
setSpin(false)
}
})
}, [reload, category, page])
function commentCtx(v){
return <RenderHtml owner={owner} projectsId={projectsId} className="break_word_comments imageLayerParent commentRenderHtml" value={v} url={location}/>;
};
//
function deleteCommentFunc(id){
deleteComment(docId, id).then(res=>{
if(res && res.data && !res.data.data.status){
reloadComment();
message.success('删除成功');
}
})
}
// markdown
function cancelMd(){
setShowEdit(false);
}
return(
<div className="commentListBox">
{/* 评论 */}
<div className={`${!login && journalsCount > 0 && 'pb15'}`}>
<div className='typeActionBox mb20'>
<div className='line'></div>
<div>评论{ journalsCount > 0 && `(共${ journalsCount }条评论)` }</div>
</div>
</div>
{/* 评论快速入口-仅有评论且登录时展示 */}
{login && category !== 'operate' && journalsCount > 0 && <div className={`pb30 ${journalsCount > 0 && 'pt15'}`}><div className='gotoComment'>点击<a className='ml5' href='#addComments'>添加评论</a></div></div>}
{/* 评论/操作日志 展示列表 */}
<Spin spinning={spin}>
<div className={`issueCommentsBox ${category === 'comment' && !spin && 'justComment'}`}>
{journals && (journals.length > 0 && journals.map(item=>{return <div key={item.id} className='commentContentBox pb30'>
{/* 评论 */}
<div className='commentOperationBor'></div>
<Link to={`/${item.user.login}`}><img src={getImageUrl(item.user.image_url)} alt="" className='commentUserImg mr15'/></Link>
<div className='commentContentRight'>
{/* 判断是否是编辑状态 */}
{(showEdit === 2 && updateId === item.id) ? <div className='mt15 mr20'><EditComment {...props} cancelMd={cancelMd} updateId={updateId} reloadComment={reloadComment} content={item.notes} defaultFileList={item.attachments} showUserImg={false}/></div> : <div>
<div className='commentContent'>
<div className='flexCenter font-14'>
<div>
<Link to={`/${item.user.login}`}>{item.user.name}</Link>
<span className='ml15 timeAgo font-14'>{timeAgo(item.created_at)}</span>
</div>
{login && <div>
{/* 平台管理员/仓库管理员/发布评论者/issue创建者 */}
{(admin || isManager || login === item.user.login || username === author) && <Popconfirm
placement="bottom"
title={`确定要删除此条评论吗?${item.children_journals.length > 0 ? '子评论也将被一起删除。' : ''}`}
okText="是"
cancelText="否"
onConfirm={() => deleteCommentFunc(item.id)}
>
<Button type='link' className='color-grey-89'><i className='iconfont icon-fuzhi-shanchu font-14 mr8'></i>删除</Button>
</Popconfirm>}
{/* 仅评论者可修改 */}
{login === item.user.login && <Button type='link' className='color-grey-89' onClick={()=>{setUpdateId(item.id); setShowEdit(2)}}><i className='iconfont icon-a-bianji12 font-14 mr8'></i>修改</Button>}
<CheckProfile {...props} sureFunc={()=>{setParentId(item.id); setReplyId(item.id); setShowEdit(3)}}><Button type='link' className='color-grey-89'><i className='iconfont icon-a-xiaoxi1 font-14 mr8'></i>回复</Button></CheckProfile>
</div>}
</div>
<div className='contentHtml mb5'>{commentCtx(item.notes)}</div>
{item && item.attachments && item.attachments.length > 0 && <div className='attachmentBox mb5'><Attachment
attachments={item.attachments}
showNotification={showNotification}
canDelete={false}
/></div>}
</div>
</div>}
{showEdit === 3 && replyId === item.id && <div className='contentHtml mr20'><EditComment {...props} cancelMd={cancelMd} parentId={parentId} replyId={replyId} reloadComment={reloadComment}/></div>}
{/* 评论回复部分 */}
{item.children_journals.map(i =>{
return <div className='commentReply' key={i.id}>
{(showEdit === 4 && updateId === i.id) ? <div className='mr20'><EditComment {...props} cancelMd={cancelMd} updateId={updateId} reloadComment={reloadComment} content={i.notes} defaultFileList={i.attachments}/></div> : <div>
<div className='flexCenter'>
<div>
<Link to={`/${i.user.login}`}><img src={getImageUrl(i.user.image_url)} alt="" className='commentUserImg mr8'/></Link>
<Link to={`/${i.user.login}`}>{i.user.name}</Link>
{i.reply_user && <span className='ml5 timeAgo mr3'>回复</span>}
<span>{i.reply_user && i.reply_user.name}</span>
<span className='ml15 timeAgo font-14'>{timeAgo(i.created_at)}</span>
</div>
{login && <div>
{/* 平台管理员/仓库管理员/发布评论者/回复评论者/issue创建者 */}
{(admin || isManager || login === i.user.login || (i.reply_user && login === i.reply_user.login) || username === author) && <Popconfirm
placement="bottom"
title={"确定要删除当前回复吗?"}
okText="是"
cancelText="否"
onConfirm={() => deleteCommentFunc(i.id)}
>
<Button type='link' className='color-grey-89'><i className='iconfont icon-fuzhi-shanchu font-14 mr8'></i>删除</Button>
</Popconfirm>}
{/* 仅回复评论者可修改 */}
{login === i.user.login && <Button type='link' className='color-grey-89' onClick={()=>{setUpdateId(i.id); setShowEdit(4)}}><i className='iconfont icon-a-bianji12 font-14 mr8'></i>修改</Button>}
<CheckProfile {...props} sureFunc={()=>{setParentId(item.id);setReplyId(i.id); setShowEdit(5)}}>
<Button type='link' className='color-grey-89'><i className='iconfont icon-a-xiaoxi1 font-14 mr8'></i>回复</Button>
</CheckProfile>
</div>}
</div>
<div className='contentHtml mt5 mb10'>{commentCtx(i.notes)}</div>
{i && i.attachments && i.attachments.length > 0 && <div className='attachmentBox'><Attachment
attachments={i.attachments}
showNotification={showNotification}
canDelete={false}
/></div>}
</div>}
{showEdit === 5 && replyId === i.id && <div className='contentHtml mr20'><EditComment {...props} cancelMd={cancelMd} parentId={parentId} replyId={replyId} reloadComment={reloadComment}/></div>}
</div>})}
</div>
</div>}))}
</div>
</Spin>
{totalCount>limit && <div className='mt20 paginationIssueComment mb20'>
<Pagination simple current={page} pageSize={limit} total={totalCount} onChange={(page)=>setPage(page)}/>
</div>}
{/* 添加评论 */}
{category !== 'operate' && <div className="pb30" style={{marginTop: journalsCount ? '-5px' : '30px'}}>
{login ? showEdit === 1 ? <EditComment {...props} cancelMd={cancelMd}/> : <div className="addComments" id='addComments'>
<img src={getImageUrl(image_url)} alt="" />
<div style={{flex:1}}>
<CheckProfile {...props} sureFunc={()=>{setShowEdit(1)}}>
<Input className='addCommentBox' placeholder="添加评论"/>
</CheckProfile>
</div>
</div> : <div className='unLoginComment font-15 pl20'>
{/* 未登录用户 */}
<a className='mr5 loginBtn' onClick={()=>{showLoginDialog()}}>登录</a>并参与评论与回复
</div>}
</div>}
</div>
)
}
export default IssueCommentList;

View File

@ -0,0 +1,217 @@
.typeActionBox{
display: flex;
align-items: center;
font-size: 16px;
.line {
width: 3px;
height: 14px;
background: var(--primary-color);
margin-right: 13px;
}
}
.commentUserImg{
height: 28px;
width: 28px;
border-radius: 50%;
object-fit: cover;
}
.issueCommentsBox{
.operationLog, .commentContentBox{
position: relative;
min-height: 62px;
display: flex;
>.flexCenter, >a{
z-index: 2;
}
&::before, &::after{
content: '';
width: 1px;
height: 50%;
position: absolute;
background: #eee;
left: 12px;
z-index: 1;
}
&::after{
background: #eee;
top: 50%;
}
}
.commentContentBox+.operationLog .operationCommentBor, .operationLog+.commentContentBox .commentOperationBor{
border-top: 1px solid #eee;
width: 98.5%;
position: absolute;
left: 12px;
}
.operationLog+.commentContentBox{
&>a, &>.commentContentRight{
margin-top: 25px;
}
}
.timeAgo{
color:#acb0bf;
}
.operationLog:last-child::after, .operationLog:first-child::before, .commentContentBox:last-child::after, &.justComment .commentContentBox::before, &.justComment .commentContentBox::after{
display: none;
}
.operationLog:first-child, .commentContentBox+.operationLog{
margin-top: -15px;
}
.commentContentBox:last-child::before{
height: 35%;
}
.flexCenter{
display: flex;
align-items: center;
justify-content: space-between;
}
.commentRenderHtml.markdown-body p{
font-size: 14px !important;
}
.commentReply{
padding: 15px 0 0 20px;
background-color: hsla(225, 31%, 95%, 0.41);
&>div{
padding-bottom: 5px;
}
&+.commentReply>div{
margin-top: -15px;
padding-top: 15px;
border-top: 1px dashed #eee;
}
}
.opBox{
justify-content: flex-start;
// flex: 1;
// width: 100%;
}
.commentContentBox{
display: flex;
align-items: flex-start;
}
.commentContentRight{
flex: 1;
background-color:#fafafc;
// border:1px solid var(--light-color-2);
border:1px solid rgba(42, 97, 255, 0.23);
border-radius:6px;
position: relative;
top: -6px;
padding: 10px 15px 16px;
width: 0;
&::before{
content: '';
display: block;
position: absolute;
top: 13px;
left: -14px;
width: 0;
height: 0;
overflow: hidden;
font-size: 0;
line-height: 0;
border: 7px;
border-style: solid;
border-color: transparent rgba(42, 97, 255, 0.23) transparent transparent;
}
&::after{
content: '';
display: block;
width: 0;
height: 0;
overflow: hidden;
font-size: 0;
line-height: 0;
border: 6px;
border-style: solid;
border-color: transparent #fafafc transparent transparent;
position: absolute;
top: 14px;
left: -11px;
}
}
}
.attachmentBox{
margin-top: -8px;
}
.color-grey-89{
color: #898d9d;
// &:hover {
// color: var(--primary-color);
// }
}
// 添加评论样式
.unLoginComment{
height:58px;
line-height: 58px;
background-color:var(--more-light-color);
border-radius:4px;
color: rgba(84, 87, 103, 1);
.loginBtn{
color: var(--primary-color);
}
}
.quillFlagBox{
color: red;
margin-bottom: 5px !important;
height: 28px;
}
.addComments{
display: flex;
align-items: center;
background-color:var(--more-light-color);
border-radius:4px;
padding:7px 10px;
&>img{
height: 28px;
width: 28px;
border-radius: 50%;
margin-right: 13px;
}
}
.addCommentBox{
width: 100%;
height: 30px;
border: none;
&:focus {
border-color: var(--primary-color) !important;
}
}
.paginationIssueComment{
text-align: center;
}
.gotoComment{
// background-color:var(--more-light-color);
background-color:rgba(241, 243, 252, 0.55);
border-radius:4px;
color: rgba(172, 176, 191, 1);
padding: 8px 20px;
margin-top: -10px;
&>a{color: var(--primary-color);}
}
// .commentStyle {
// &:hover {
// border-color: var(--primary-color) !important;
// }
// }
.colorButton {
background-color: var(--primary-color);
border-color: var(--primary-color);
&:hover {
background-color: var(--light-color);
border-color: var(--primary-color);
}
&:focus {
background-color: var(--primary-color);
border-color: var(--primary-color);
}
}
.colorButton2 {
&:hover {
border-color: var(--primary-color);
color: var(--light-color);
}
&:focus {
color: var(--primary-color);
}
}

View File

@ -10,7 +10,7 @@ function PublicBanner(props){
const [ key , setKey ] = useState("1");
const { deptId } = props.match.params;
const { pathname } = props.history.location;
const { data , adminUrl, temp } = props;
const { data:{sectionHomepageShow, sectionHomepageTitle, sectionProjectShow, sectionProjectTitle, sectionResourceShow, sectionResourceTitle, sectionCmsShow, sectionCmsTitle, sectionMemberShow, sectionMemberTitle, sectionHelperShow, sectionHelperTitle}, data , adminUrl, temp } = props;
useEffect(()=>{
if(pathname){
@ -53,13 +53,13 @@ function PublicBanner(props){
}
<div className="bannerMenus">
<Menu mode={"horizontal"} selectedKeys={[key]}>
<Menu.Item key={"1"}><Link to={`/zone/${deptId}`}><img src={require(`../img/${temp}Menu1.png`)} alt="" width="29px"/>首页</Link></Menu.Item>
<Menu.Item key={"2"}><Link to={`/zone/${deptId}/projects`}><img src={require(`../img/${temp}Menu2.png`)} alt="" width="34px"/>开源项目</Link></Menu.Item>
<Menu.Item key={"3"}><Link to={`/zone/${deptId}/source`}><img src={require(`../img/${temp}Menu3.png`)} alt="" width="33px"/>资源发布</Link></Menu.Item>
<Menu.Item key={"4"}><Link to={`/zone/${deptId}/news`}><img src={require(`../img/${temp}Menu4.png`)} alt="" width="32px"/>{ tempConfig[temp].mainTitle }</Link></Menu.Item>
{sectionHomepageShow && <Menu.Item key={"1"}><Link to={`/zone/${deptId}`}><img src={require(`../img/${temp}Menu1.png`)} alt="" width="29px"/>{sectionHomepageTitle}</Link></Menu.Item>}
{sectionProjectShow && <Menu.Item key={"2"}><Link to={`/zone/${deptId}/projects`}><img src={require(`../img/${temp}Menu2.png`)} alt="" width="34px"/>{sectionProjectTitle}</Link></Menu.Item>}
{sectionResourceShow && <Menu.Item key={"3"}><Link to={`/zone/${deptId}/source`}><img src={require(`../img/${temp}Menu3.png`)} alt="" width="33px"/>{sectionResourceTitle}</Link></Menu.Item>}
{sectionCmsShow && <Menu.Item key={"4"}><Link to={`/zone/${deptId}/news`}><img src={require(`../img/${temp}Menu4.png`)} alt="" width="32px"/>{sectionCmsTitle}</Link></Menu.Item>}
{/* <Menu.Item key={"5"}><img src={Menu5} alt="" width="27px"/>Sig小组</Menu.Item> */}
<Menu.Item key={"6"}><Link to={`/zone/${deptId}/VIP`}><img src={require(`../img/${temp}Menu6.png`)} alt="" width="36px"/>{ tempConfig[temp].member }</Link></Menu.Item>
{data && data.helperShow === 1 && <Menu.Item key={"8"}><Link to={`/zone/${deptId}/help`}><img src={require(`../img/${temp}Menu8.png`)} alt="" width="36px"/>{data.helperTitle}</Link></Menu.Item>}
{sectionMemberShow && <Menu.Item key={"6"}><Link to={`/zone/${deptId}/VIP`}><img src={require(`../img/${temp}Menu6.png`)} alt="" width="36px"/>{ sectionMemberTitle }</Link></Menu.Item>}
{sectionHelperShow && <Menu.Item key={"8"}><Link to={`/zone/${deptId}/help`}><img src={require(`../img/${temp}Menu8.png`)} alt="" width="36px"/>{data.sectionHelperTitle}</Link></Menu.Item>}
{ adminUrl && <Menu.Item key={"7"}><a onClick={()=>{window.location.href=adminUrl}}><img src={require(`../img/${temp}Menu7.png`)} alt="" width="34px"/>后台管理</a></Menu.Item> }
</Menu>
</div>

View File

@ -209,7 +209,7 @@ function ProjectSource(props) {
return (
<div className="in_pro">
<div className="boxmain" style={{ paddingTop: "56px" }}>
<p className="in_title mb30">{data && data.helperTitle}</p>
<p className="in_title mb30">{data && data.sectionHelperTitle}</p>
<Spin spinning={loading}>
{
wikiList && (wikiList.length > 0 ? <Box className='zoneHelpBox'>

View File

@ -24,7 +24,7 @@ function Main(props){
const [ isSpin , setIsSpin ] = useState(true);
const [ newCateId , setNewCateId ] = useState(undefined);
const { deptId , cateId } = props.match.params;
const { id, temp, role, history } = props;
const { id, temp, role, history, sectionCmsTitle } = props;
const menu = (
<Menu>
@ -121,7 +121,7 @@ function Main(props){
<div className="main_content">
<div className="boxmain">
<div className='titleButBox'>
<p className="in_title">{tempConfig[temp].mainTitle}</p>
<p className="in_title">{sectionCmsTitle}</p>
{role && role.role !== "None" && <div className='createButs mt10'>
{role.role === "Member" && <Button type="primary" ghost className='mr20'>
<Link to={`/zone/${deptId}/news/self`}>我的文章</Link>

View File

@ -1,4 +1,4 @@
import React,{ useState , useEffect } from 'react';
import React,{ useState , useEffect, useRef } from 'react';
import { Badge, Breadcrumb , Divider, Spin } from 'antd';
import liulan from '../img/liulan.png';
import RenderHtml from '../../../components/render-html';
@ -8,6 +8,7 @@ import { IsPC } from 'educoder';
import { tempConfig } from '../tempInfo';
import Acce from '../Component/mobile/accessory';
import { addMeta, setSeoMeta } from 'educoder';
import CommentList from '../Component/comments/list'
function NewsDetail(props){
@ -16,6 +17,7 @@ function NewsDetail(props){
const [ cmsDir , setCmsDir ] = useState(undefined);
const [ content , setContent]=useState(undefined);
const [ isSpin , setIsSpin]=useState(false);
const [ commentReload, setCommentReload] = useState(undefined);
const temp = props.temp;
const zonedetail = props.data;
@ -76,6 +78,7 @@ function NewsDetail(props){
setIsSpin(false)
})
}
return(
<React.Fragment>
{
@ -120,6 +123,13 @@ function NewsDetail(props){
<span>暂无详情~</span>
}
</div>
{
//
detail.auditStatus === '1' && <div className="info_text mt30">
<CommentList {...props} docId={ id } reload={commentReload} author={ detail.createBy } reloadComment={()=>{setCommentReload(Math.random())}}/>
</div>
}
</div>
}
</Spin>

View File

@ -22,7 +22,7 @@ function ProjectSource(props){
const [ searchName , setSearchName ] = useState(undefined);
const [ value , setValue ] = useState(undefined);
const [ loading , setLoading ] = useState(false);
const { id, temp } = props;
const { id, temp, sectionProjectTitle } = props;
useEffect(()=>{
if(id){
@ -79,7 +79,7 @@ function ProjectSource(props){
<div className="in_pro">
{/* <Banner {...props}/> */}
<div className="boxmain" style={{paddingTop:"56px"}}>
<p className="in_title">开源项目</p>
<p className="in_title">{sectionProjectTitle}</p>
{ temp === tempEnum.zone1 && <p className="project_sub_title">聚合开源特色项目搭建硬件开源服务桥梁</p> }
<Box>
<ul className="in_pro_menu">

View File

@ -23,7 +23,7 @@ function Source(props){
const [ search , setSearch ] = useState(undefined);
const [ isSpin , setIsSpin ] = useState(true);
const limit = 20;
const { id , temp, history, role } = props;
const { id , temp, history, role, sectionResourceTitle } = props;
useEffect(()=>{
id && getLists();
@ -80,7 +80,7 @@ function Source(props){
return(
<div className={`${temp}_source_box`}>
<div className="source_h">
<p className="in_title">资源发布</p>
<p className="in_title">{sectionResourceTitle}</p>
<div style={{marginTop:"30px",textAlign:"center"}} className='titleButBox'>
<Search
placeholder="请输入资源名称"

View File

@ -23,7 +23,7 @@ function ZoneVIP(props){
const [ isSpin , setIsSpin ] = useState(true);
const [ applyVisible , setApplyVisible ] = useState(false);
const [ memberStatus , setMemberStatus] = useState(memberStatusEnum.notMember);
const { id, showNotification, checkIfLogin, showLoginDialog, temp } = props;
const { id, showNotification, checkIfLogin, showLoginDialog, temp, sectionMemberTitle } = props;
useEffect(()=>{
if(id){
@ -74,7 +74,7 @@ function ZoneVIP(props){
return(
<div className={`boxmain ${temp}_VIP_box`}>
<p className="in_title">{ tempConfig[temp].member }</p>
<p className="in_title">{ sectionMemberTitle }</p>
<p className="vip_sub_title">{ tempConfig[temp].vipDesc }</p>
{ memberStatus === memberStatusEnum.notMember && <Button className="zone_apply_button" onClick={ apply }>申请加入</Button> }
{ memberStatus === memberStatusEnum.applying && <div className="mt20 tips" ><Icon type="check-circle" theme="filled" />您的申请已提交请耐心等待管理员审核!</div> }
@ -83,8 +83,10 @@ function ZoneVIP(props){
<Spin spinning={isSpin}>
<div style={{minHeight:400}}>
{
vipLists && (vipLists.length > 0 ? <MemberList vipLists={vipLists} temp={temp}/> : <div style={{marginTop:30,backgroundColor:"#fff",padding:"20px"}}>
<Nodata _html={"暂无数据"}/>
vipLists && (vipLists.length > 0 ? <MemberList vipLists={vipLists} temp={temp}/> : <div style={{marginTop:30,padding:"20px"}}>
{
temp === tempEnum.zone1 ? <Nodata _html="暂无数据" img={ nodata }/> : <Nodata _html="暂无数据" />
}
</div>)
}
</div>

View File

@ -252,4 +252,40 @@ export function updateMyResource(data) {
method: 'PUT',
data: data
});
}
// 评论相关
// 评论列表
export function getCommentList(id, params) {
return fetch({
url: `cms/doc/open/${ id }/journalList`,
method: 'GET',
params
})
}
// 新增评论
export function addComment(id, data) {
return fetch({
url: `cms/docComment/${ id }`,
method: 'POST',
data: data
})
}
// 编辑评论
export function editComment(id, data) {
return fetch({
url: `cms/docComment/${ id }/${ data.id }`,
method: 'PUT',
data: data
})
}
// 删除评论
export function deleteComment(docId, id) {
return fetch({
url: `cms/docComment/${ docId }/${ id }`,
method: 'DELETE',
})
}

View File

@ -177,7 +177,7 @@ function Index(props){
<Route
path="/zone/:deptId/news/:cateId"
render={(p) => (
<Main {...props} {...p} id={id} temp={ temp } role={role}/>
<Main {...props} {...p} id={id} temp={ temp } role={role} sectionCmsTitle={data && data.sectionCmsTitle}/>
)}
></Route>
<Route
@ -213,25 +213,25 @@ function Index(props){
<Route
path="/zone/:deptId/source"
render={(p) => (
<Source {...props} {...p} id={id} temp={ temp } role={role}/>
<Source {...props} {...p} id={id} temp={ temp } role={role} sectionResourceTitle={data && data.sectionResourceTitle}/>
)}
></Route>
<Route
path="/zone/:deptId/VIP"
render={(p) => (
<VIP {...props} {...p} id={id} temp={ temp }/>
<VIP {...props} {...p} id={id} temp={ temp } sectionMemberTitle={data && data.sectionMemberTitle}/>
)}
></Route>
<Route
path="/zone/:deptId/projects"
render={(p) => (
<ProjectSource {...props} {...p} id={id} temp={ temp }/>
<ProjectSource {...props} {...p} id={id} temp={ temp } sectionProjectTitle={data && data.sectionProjectTitle}/>
)}
></Route>
<Route
path="/zone/:deptId/news"
render={(p) => (
<Main {...props} {...p} id={id} temp={ temp } role={role}/>
<Main {...props} {...p} id={id} temp={ temp } role={role} sectionCmsTitle={data && data.sectionCmsTitle}/>
)}
></Route>
{data && data.helperShow === 1 && <Route

View File

@ -1126,10 +1126,12 @@
margin-right: 7px;
}
}
.none_panels {
background-color: #FFFFFF;
margin: 25px 25px 25px 0;
border-radius: 12px;
.vip_list {
.none_panels {
background-color: #FFFFFF;
margin: 25px 25px 25px 0;
border-radius: 12px;
}
}
}
.zone_parter{

View File

@ -4,6 +4,8 @@ html[data-theme="zone"] {
--more-light-color: rgba(70, 106, 255, 0.05);
--linear-back-color: linear-gradient(89.9deg,rgba(70, 106, 255, 0) 0%,rgba(70, 106, 255, 0.09) 100%);
--tag-back: rgba(70, 106, 255, 0.12);
--light-color-2: rgba(70,106,255,0.23);
--light-color-3: rgba(70,106,255,0.55);
}
html[data-theme="zone1"] {
--primary-color: #089f7f;
@ -11,4 +13,6 @@ html[data-theme="zone1"] {
--light-color: rgba(7, 165, 131, 0.85);
--linear-back-color: linear-gradient(89.9deg,rgba(7, 165, 131, 0) 0%,rgba(7, 165, 131, 0.09) 100%);
--tag-back: rgba(142, 147, 161, 0.1);
--light-color-2: rgba(7, 165, 131, 0.23);
--light-color-3: rgba(7, 165, 131, 0.55);
}

View File

@ -82,7 +82,9 @@ function AllMenus({owner,projectsId,chooseFunc,update,defaultNames,defaultIds,op
const url = `/v1/${owner}/${projectsId}/issue_tags`;
axios.get(url,{params:{keyword:tag,only_name:true}}).then(result=>{
if(result && result.data){
setTagList(result.data.issue_tags);
let list = [{id:-1,name:"无标记"}];
list = [...list,...result.data.issue_tags];
setTagList(list);
}
})
}
@ -95,7 +97,9 @@ function AllMenus({owner,projectsId,chooseFunc,update,defaultNames,defaultIds,op
const url = `/v1/${owner}/${projectsId}/milestones`;
axios.get(url,{params:{keyword:millstone,only_name:true}}).then(result=>{
if(result && result.data){
setMillstoneList(result.data.milestones);
let list = [{id:-1,name:"无里程碑"}];
list = [...list,...result.data.milestones];
setMillstoneList(list);
}
})
}
@ -106,18 +110,21 @@ function AllMenus({owner,projectsId,chooseFunc,update,defaultNames,defaultIds,op
},[charge,update])
function getCharge(){
let list = [{id:-1,name:"未指派负责人"}];
if(update){
const url = `/v1/${owner}/${projectsId}/collaborators`;
axios.get(url,{params:{keyword:charge,only_name:true}}).then(result=>{
if(result && result.data){
setChargeList(result.data.collaborators);
list = [...list,...result.data.collaborators];
setChargeList(list);
}
})
}else{
const url = `/v1/${owner}/${projectsId}/issue_assigners`;
axios.get(url,{params:{keyword:charge,only_name:true}}).then(result=>{
if(result && result.data){
setChargeList(result.data.assigners);
list = [...list,...result.data.assigners];
setChargeList(list);
}
})
}

View File

@ -7,7 +7,7 @@ import Attachments from "../../../../forge/Upload/attachment";
import UploadImg from "../../../../forge/Images/upload.png";
import './list.scss';
import '../../../../forge/Order/order.scss';
import { useState } from 'react';
import { useState,useEffect } from 'react';
import { Link } from 'react-router-dom';
import axios from 'axios';
@ -23,7 +23,7 @@ function EditComment(props){
const [attachmentClean, setAttachmentClean] = useState(true);
const [ save , setSave ] = useState(undefined);
useState(()=>{
useEffect(()=>{
setSave(props.defaultFileList);
},[props.defaultFileList])

View File

@ -31,8 +31,9 @@ function Menus({className,name, ids , lists , size , imgControl , searchFunc , c
function changeMenusValue(i){
let l = ids;
let id = i.id.toString();
if(double){
if(double && id!=="-1"){
l = ids ? ids.split(",") : [] ;
l = l && l.length>0 ? l.filter(i=>i.toString()!=="-1") :[];
let nameArr = names ? names.split(",") : [] ;
if(l && l.indexOf(id)>=0){
l = l.filter(k=>k.toString() !== id);
@ -69,7 +70,7 @@ function Menus({className,name, ids , lists , size , imgControl , searchFunc , c
{
data.map((i,j)=>{
return <Menu.Item key={i.id}>
{imgControl && <img src={getImageUrl(i.image_url)} alt=""/>}
{imgControl && i.image_url && <img src={getImageUrl(i.image_url)} alt=""/>}
{i.color && <span style={{backgroundColor:i.color,marginRight:"0px"}} className="colorpiece"></span>}
<span className="task-hide" onClick={()=>changeMenusValue(i)}>{i.name}</span>
</Menu.Item>

View File

@ -308,7 +308,7 @@ function Details(props){
}).then(result=>{
if(result && result.data && result.data.project_issues_index){
window.scrollTo(0,0);
props.showNotification("任务复制成功!");
props.showNotification("疑修复制成功!");
props.history.push(`/${owner}/${projectsId}/issues/${result.data.project_issues_index}`);
}
}).catch(error=>{})

View File

@ -237,13 +237,17 @@ function List(props){
// allValue updateIds
function sureUpdate(){
const url = `/v1/${owner}/${projectsId}/issues/batch_update`;
const { assigner_id ,issue_tag_ids , milestone_id ,issue_priorities_id , status_id } = updateChooseIds;
let assigner = assigner_id ? assigner_id === "-1" ? [] : assigner_id.split(",") : undefined;
let issueTag = issue_tag_ids ? issue_tag_ids === "-1" ? [] : issue_tag_ids.split(",") : undefined;
let milestone = milestone_id ? milestone_id === "-1" ? "" : milestone_id : undefined;
axios.patch(url,{
assigner_ids: updateChooseIds && updateChooseIds.assigner_id && updateChooseIds.assigner_id.split(","),
assigner_ids: assigner ,
ids: allValue,
issue_tag_ids: updateChooseIds && updateChooseIds.issue_tag_ids && updateChooseIds.issue_tag_ids.split(","),
milestone_id: updateChooseIds && updateChooseIds.milestone_id,
priority_id: updateChooseIds && updateChooseIds.issue_priorities_id,
status_id: updateChooseIds && updateChooseIds.status_id
issue_tag_ids: issueTag,
milestone_id: milestone,
priority_id: issue_priorities_id,
status_id: status_id
}).then(result=>{
if(result){
setUpdateIds(undefined);

View File

@ -198,7 +198,7 @@ function New(props){
}).then(result=>{
if(result && result.data && result.data.project_issues_index){
window.scrollTo(0,0);
props.showNotification("任务创建成功!");
props.showNotification("疑修创建成功!");
props.history.push(`/${owner}/${projectsId}/issues/${result.data.project_issues_index}`);
}
}).catch(error=>{})

View File

@ -93,12 +93,12 @@ function Sign(props){
<Menu.Item key={"4"} value="asc" createName="issues_count">
按疑修数量升序排序
</Menu.Item>
<Menu.Item key={"5"} value="desc" createName="pull_requests_count">
{/* <Menu.Item key={"5"} value="desc" createName="pull_requests_count">
按合并请求数量降序排序
</Menu.Item>
<Menu.Item key={"6"} value="asc" createName="pull_requests_count">
按合并请求数量升序排序
</Menu.Item>
</Menu.Item> */}
</Menu>
);
@ -240,8 +240,8 @@ function Sign(props){
</p>
<p style={{flex:2}} className="task-hide">{i.description}</p>
<p>
<span className="mr12">{i.issues_count || 0} 疑修</span>
<span className="line">{i.pull_requests_count || 0} 合并请求</span>
<span>{i.issues_count || 0} 疑修</span>
{/* <span className="line">{i.pull_requests_count || 0} 合并请求</span> */}
</p>
<p>
<a className="color-blue mr12" onClick={()=>editFunc(i)}>编辑</a>

View File

@ -62,9 +62,11 @@ function CoderDepot(props){
let branchName = props.match.params.branchName;
branchName = returnbar(branchName);
let pathname = props.history.location.pathname;
let search = props.history.location.search
const { platform , mirror_status , bannerList , projectDetail } = props ;
//distribution
const distribution = projectDetail && projectDetail.type ===0 && ( projectDetail.permission && projectDetail.permission !== "Reporter");
useEffect(()=>{
if(bannerList && bannerList.length>0){
let a = bannerList.filter(i=>i.menu_name === "pulls");
@ -138,6 +140,15 @@ function CoderDepot(props){
}
},[projectsId,owner,pathname,defaultBranch,mirror_status])
//
useEffect(()=>{
if (projectsId && owner && defaultBranch && mirror_status===0 && !search){
let b = turnbar(branchName) ;
let url = pathname.split(`/tree/${b}/`)[1];
getFileInfo(url,branchName);
}
},[search])
useEffect(()=>{
if(platform && mirror_status===0){
setReadOnly(props.history.location.search.indexOf('edit') !== -1);

View File

@ -54,7 +54,7 @@ function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId , platform
</span>
<span title="init project">
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.commit && item.commit.sha}`)}`} title={item.commit && item.commit.message}>
{getEmoji(getMessage(item.commit && item.commit.message))}
{getEmoji(getMessage(item.commit && item.commit.message.split('\n')[0]))}
</Link>
</span>
<span title={item.commit && item.commit.created_at}>{item.commit && item.commit.time_from_now}</span>

View File

@ -145,7 +145,7 @@ class UserSubmitComponent extends Component {
let b = currentBranch || branch;
let src = `/${owner}/${projectsId}${(values.branchname ? `/tree/${turnbar(values.branchname)}` : (b ? `/tree/${turnbar(b)}`:""))}${detail.path ? `/${returnbar(detail.path)}` : ""}`;
this.props.history.push(src);
this.props.showNotification("文件修改成功!");
this.props.showNotification("文件修改成功! ");
}
})
.catch((error) => {

View File

@ -6,6 +6,8 @@ import axios from "axios";
import { AlignCenter, AlignTop } from "../../Component/layout";
import { Link } from "react-router-dom";
import { getImageUrl } from "../../../common/UrlTool";
import { ImageLayerOfCommentHOC } from "../../../modules/page/layers/ImageLayerOfCommentHOC";
import { withRouter } from "react-router";
const { TextArea } = Input;
function CreateSite(props) {
@ -18,6 +20,11 @@ function CreateSite(props) {
useEffect(() => {
document.title = "创建站点";
setFieldsValue({
identifier: `http://${current_user.login}.${site_page_deploy_domain || 'gitlink.net'}`,
repository_name: `${current_user.login}.${site_page_deploy_domain || 'gitlink.net'}`,
name: `${current_user.login}.${site_page_deploy_domain || 'gitlink.net'}`
})
}, []);
useEffect(()=>{
@ -56,7 +63,8 @@ function CreateSite(props) {
...values,
clone_addr: theme && theme.clone_url,
theme: theme && theme.name,
user_id: current_user.user_id
user_id: current_user.user_id,
identifier: values.identifier.split("http://")[1]
}).then(res=>{
if(res && res.status === 200){
message.success("新建成功");
@ -94,18 +102,20 @@ function CreateSite(props) {
>
{getFieldDecorator("identifier", {
rules: [{ required: true, message: "请输入站点标识" },
{pattern: /^[a-zA-Z0-9]{2,100}$/, message: '长度2-100只能包含数字和字母'}],
// {pattern: /^[a-zA-Z0-9]{2,100}$/, message: '2-100'}
],
})(
<Input
onChange={(e) => {
setTag(e.target.value);
}}
placeholder="请输入站点标识"
disabled
/>
)}
<span style={{wordBreak: 'break-all'}}>
{/* <span style={{wordBreak: 'break-all'}}>
http://{current_user.login}.{site_page_deploy_domain}/{tag}
</span>
</span> */}
</Form.Item>
<Form.Item name="建站工具" label="建站工具">
{getFieldDecorator("language_frame", {initialValue: 0})(
@ -124,9 +134,9 @@ function CreateSite(props) {
<AlignTop style={{flexWrap: 'wrap'}}>
{themes && themes.map(item=>{
const {image, name, clone_url} = item;
return <div className="mr20 themeBox" onClick={()=>{setTheme(item)}}>
return <div className="mr20 themeBox imageLayerParent" onClick={()=>{setTheme(item)}}>
<i className={`iconfont icon-wancheng ${theme && theme.clone_url === clone_url ? 'active' : ''}`}></i>
<img src={getImageUrl(image)} alt="" width="125px" height="85px"/>
<img src={getImageUrl(image)} alt="" width="125px" height="85px" className="imageTarget"/>
<p className="task-hide" style={{maxWidth: '120px'}}>{name}</p>
</div>
})}
@ -147,7 +157,7 @@ function CreateSite(props) {
rules: [{ required: true, message: "请输入项目标识" },
{pattern: /^[a-zA-Z0-9][a-zA-Z0-9_.-]{2,100}[a-zA-Z0-9]$/, message: "长度2-100只能包含数字、字母、下划线、中划线、英文句号必须以数字和字母开头不能以下划线/中划线/英文句号开头和结尾"}],
})(
<Input placeholder="请输入项目标识"/>
<Input placeholder="请输入项目标识" disabled/>
)}
</Form.Item>
</AlignCenter>
@ -159,7 +169,7 @@ function CreateSite(props) {
rules: [{ required: true, message: "请输入项目名称" },
{type: 'string', max: 50, min: 1, message: "长度1-50"}],
})(
<Input placeholder="请输入项目名称"/>
<Input placeholder="请输入项目名称" disabled/>
)}
</Form.Item>
<Form.Item name="项目简介" label="项目简介">
@ -185,4 +195,7 @@ function CreateSite(props) {
</Fragment>
);
}
export default Form.create()(CreateSite);
export default withRouter(ImageLayerOfCommentHOC({
imgSelector: ".imageLayerParent img, .imageLayerParent .imageTarget",
parentSelector: ".newContainer",
})(Form.create()(CreateSite)));

View File

@ -1,6 +1,5 @@
.mySites_head{
height: 65px;
line-height: 64px;
border-bottom: 1px solid rgba(224, 230, 245, 1);
color:#151d40;
font-size:17px;

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect, Fragment } from "react";
import { Button, Pagination, Spin } from "antd";
import { Button, Pagination, Spin, Tooltip } from "antd";
import './index.scss';
import '../../users/Material/Index.scss';
import '../bot/exploit/index.scss'
@ -38,7 +38,9 @@ function MySiteList(props){
return <Spin spinning={loading}>
<FlexAJ className="mySites_head">
<span>我的站点</span>
{id_card_verify && website_permission && <Button type="primary" onClick={()=>{history.push(`/settings/mysite/create`)}}>新建站点</Button>}
{id_card_verify && website_permission && total >= 1 ? <Tooltip title="您已存在站点,请勿重复创建">
<Button type="primary" disabled>新建站点</Button>
</Tooltip> : <Button type="primary" onClick={()=>{history.push(`/settings/mysite/create`)}}>新建站点</Button>}
</FlexAJ>
{/* 站点权限被管理员关闭 */}
{id_card_verify && !website_permission && <div className="tipsBox font-15 mt20">您的站点权限被锁定请联系平台管理员</div>}

View File

@ -48,7 +48,7 @@ function ServerIndex(props){
}
></Route>
{/* 个人建站服务 */}
{projectDetail && projectDetail.author.type === "User" && <Route path="/:owner/:projectsId/service/pages"
{projectDetail && projectDetail.web_site && projectDetail.author.type === "User" && <Route path="/:owner/:projectsId/service/pages"
render={
() => (<Pages {...props}/>)
}

View File

@ -64,7 +64,8 @@ function Main(props){
<Link to={`/${owner}/${projectsId}/service/reposyncer`} className="btnhover">查看详情</Link>
</span>
</li> */}
{projectDetail && projectDetail.author.type === "User" && <li>
{/* 是站点仓库则显示,否则隐藏 */}
{projectDetail && projectDetail.web_site && projectDetail.author.type === "User" && <li>
<span className="servername">
<img src={require('./img/logo.png')} alt=""/>
<a onClick={openDetail}>个人建站服务</a>

View File

@ -277,6 +277,8 @@ class Setting extends Component {
let mirror = projectDetail && projectDetail.mirror;
let type = projectDetail && projectDetail.type;
const forked_from_project_id = this.props && this.props.projectDetail && this.props.projectDetail.forked_from_project_id;
// 站点仓库不允许修改项目名称和标识
const isWebSiteRepo = projectDetail && projectDetail.web_site;
return (
<div>
<DivertModal
@ -298,7 +300,7 @@ class Setting extends Component {
message: "请输入项目名称",
},
],
})(<Input placeholder="请输入项目名称" />)}
})(<Input placeholder="请输入项目名称" disabled={isWebSiteRepo}/>)}
{
projectDetail && projectDetail.type && projectDetail.type !== 0 ?
<span className="color-grey-9">该项目导入于 <a className="color-grey-6" target="_blank" href={projectDetail.mirror_url}>{projectDetail.mirror_url}</a></span>
@ -335,7 +337,7 @@ class Setting extends Component {
},
],
})(
<Input placeholder="项目标识请使用与项目相关的英文关键字" maxLength="100" />
<Input placeholder="项目标识请使用与项目相关的英文关键字" maxLength="100" disabled={isWebSiteRepo}/>
)}
</Form.Item>
<Form.Item label="项目简介">

View File

@ -54,7 +54,7 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
const content = Base64.decode(res.data.md_content);
setContent(content);
setFieldsValue({
title: res.data.name,
title: search === "?copy" ? `${res.data.name}(复制)` : res.data.name,
md_content: content,
});
}
@ -123,7 +123,7 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
return;
}
const {md_content, title} = values;
if (wikiName) {
if (wikiName && search!== "?copy") {
updateWiki({
owner,
repo: projectsId,
@ -160,7 +160,7 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
function dealRes(res, title) {
if (res && (res.message === "201" || res.message === "200")) {
if(wikiName){
if(wikiName && search!== "?copy"){
// wikisidebar
if(wikiName === title){
message.success("操作成功");
@ -173,7 +173,14 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
}
}else{
//
if(search.includes("?key")){
if(search === "?copy"){
// keykey
const keyArr = key.split('-');
keyArr.pop();
const list = menuList;
addChildrenByKey(list, keyArr.join('-'), title);
updateSidebar(treeToMd(list), title);
}else if(search.includes("?key")){
// menuListkeychildren push[[]]
const list = menuList;
addChildrenByKey(list, key, title);
@ -316,7 +323,7 @@ export default Form.create()(({ form, history, showNotification, projectDetail,
return (
<div className="wiki-main">
<div className="wiki-head">
<span className="head-title"><span className="back-wiki" onClick={goBack}>Wiki</span> <Icon type="right" /> {wikiName ? '编辑' : '新增'}页面</span>
<span className="head-title"><span className="back-wiki" onClick={goBack}>Wiki</span> <Icon type="right" /> {wikiName ? search === "?copy" ? '复制' : '编辑' : '新增'}页面</span>
</div>
<div >

View File

@ -101,6 +101,7 @@ export default (props) => {
...firstWiki,
key: firstWikiNode.key
})
if(window.location.pathname.indexOf('/wiki') === -1) return
history.push(`/${owner}/${projectsId}/wiki/${title}/${firstWikiNode.key}`);
} else {
setFileArr([]);
@ -231,8 +232,8 @@ export default (props) => {
});
}
function goEdit() {
history.push(`/${owner}/${projectsId}/wiki/${encodeURI(checkItem.name)}/${checkItem.key}/edit`);
function goEdit(params) {
history.push(`/${owner}/${projectsId}/wiki/${encodeURI(checkItem.name)}/${checkItem.key}/edit${params}`);
}
function preview() {
@ -327,7 +328,8 @@ export default (props) => {
</span>
<span className="time-ago font-14">上次修改于{checkItem.commit ? timeAgo(checkItem.commit.author.date) : '刚刚'}</span>
</div>
{permission && <Button type="primary" onClick={goEdit}>编辑</Button>}
{permission && <Button type="primary" ghost onClick={()=>{goEdit(`?copy`)}} className='mr10'>复制</Button>}
{permission && <Button type="primary" onClick={()=>{goEdit("")}}>编辑</Button>}
</div>
{itemDetail&&itemDetail.md_content&&<RenderHtml className="wiki-content-detail editor-content-panel imageLayerParent" value={ itemDetail && Base64.decode(itemDetail.md_content) } url={history.location}/>}

View File

@ -179,14 +179,14 @@ export function findNodeByKey(list, key){
}
// 找到children中有相同key的数组
export function findNodeByChildrenKey(list, key){
export function findBrotherNodesByKey(list, key){
for (let index = 0; index < list.length; index++) {
const element = list[index];
if (element.key == key) {
return list;
}else if (element.children.length) {
let result = findNodeByChildrenKey(element.children, key);
if (result) {
}else if (element.children && element.children.length) {
let result = findBrotherNodesByKey(element.children, key);
if (result.length) {
return result;
}
}

View File

@ -3,7 +3,7 @@ import { Tree, Dropdown, Menu, message, Modal, Input } from 'antd';
import DelModal from '../../components/ModalFun';
import './index.scss';
import '../../components/ModalFun/index.scss';
import { deleteWiki, findNodeByChildrenKey, findNodeByKey, getWiki, treeToMd, updateWiki } from '../../api';
import { deleteWiki, findBrotherNodesByKey, findNodeByKey, getWiki, treeToMd, updateWiki } from '../../api';
import { useEffect } from 'react';
import { Base64 } from 'js-base64';
import { splicingTabs } from '../../utils';
@ -356,20 +356,21 @@ export default function Sidebar(props) {
}else{
// isEditName 1 2
const titleToJudge = isEditName === 2 ? `[[${menuName}]]` : `- ${menuName}`;
const {children, node, title, key} = visible;
const list = findNodeByChildrenKey(menuList, key) || [];
const {title, key} = visible;
if(title.trim() === titleToJudge){
setAddMenuError("请修改名称");
return
}
//
const list = findBrotherNodesByKey(menuList, key) || [];
if(list.map(item=>item.title.trim()).includes(titleToJudge)){
message.error("不能与同级目录名称相同");
setAddMenuError("不能与同级目录名称相同");
return
}
// wiki
const sameNameWiki = fileArrInit.filter(item=>item.name === menuName)
if(isEditName === 2 && sameNameWiki.length){
message.error("wiki名称不可重复");
setAddMenuError("wiki名称不可重复");
return
}
// sidebar

View File

@ -21,10 +21,10 @@ export default function UploadWiki(props) {
},
beforeUpload: beforeUpload,
onChange(info) {
//
const fileName = info.file.name.substring(0,info.file.name.lastIndexOf("."))
if (info.file.status === 'done') {
if (info.file.response.message === '201') {
//
const fileName = info.file.name.substring(0,info.file.name.lastIndexOf("."))
// sidebar
if(!fileArrInit.length){
// wiki
@ -42,13 +42,14 @@ export default function UploadWiki(props) {
message.success(`${fileName} 上传成功`);
history.push(`/${owner}/${projectsId}/wiki/${encodeURI(fileName)}/0`);
setReload(Math.random());
} else if (info.file.response.message === '500') {
message.error(info.file.response.data || '文件上传失败');
} else {
message.error('文件上传失败');
}
} else if (info.file.status === 'error') {
message.error(`${info.file.name} 上传失败`);
const {message: responseMes} = info.file.response;
if(responseMes.indexOf('wiki page already exists') !== -1){
message.error("已存在相同文件名的文件")
}else{
message.error(responseMes || `${fileName} 上传失败`);
}
}
},
};

View File

@ -3,9 +3,10 @@ import { Link } from 'react-router-dom';
import { AlignCenter } from '../../Component/layout';
import { TagInfo } from '../../Utils/TagColor';
import { getImageUrl } from 'educoder';
import { truncateCommitId } from "../../common/util";
function Activity({list}) {
function typeForUrl(trend_type,project,id){
function typeForUrl(trend_type,project,id,commit_log){
const { owner , identifier } = project;
switch(trend_type){
case 'Issue':
@ -14,6 +15,9 @@ function Activity({list}) {
return `/${owner && owner.login}/${identifier}/releases`;
case 'PullRequest':
return `/${owner && owner.login}/${identifier}/pulls/${id}`;
case 'CommitLog':
const commit = commit_log && commit_log.commit_id;
return `/${owner && owner.login}/${identifier}/commits/${truncateCommitId(commit)}`;
default :
return '';
}
@ -32,7 +36,7 @@ function Activity({list}) {
{i.priority && TagInfo(`${i.priority}`,"")}
{i.issue_status && <span className="status">{i.issue_status}</span> }
</AlignCenter>
<p className="aDesc"><Link to={typeForUrl(i.trend_type,i.project,i.trend_id)}>{i.action_type}{i.name}</Link></p>
<p className="aDesc"><Link to={typeForUrl(i.trend_type,i.project,i.trend_id,i.commit_log)}>{i.action_type}{i.name}</Link></p>
</div>
</li>
)

View File

@ -320,7 +320,6 @@ const Glcc = (propsF) => {
<FreeResult id={id} round={round} period={period} current_user={current_user} history={props.history}/>
)}
></Route>
{/* openmmlab列表 */}
<Route
path="/glcc/openmmlab"

View File

@ -45,7 +45,7 @@
cursor: pointer;
/* 行内样式 */
max-width: 100% !important;
height: auto !important;
/* height: auto !important; */
}
.markdown-body pre ol.linenums,.markdown-body pre ul.linenums{
padding-left: 0px;
@ -57,7 +57,7 @@
.markdown-body video{
/* 行内样式 */
max-width: 100% !important;
height: auto !important;
/* height: auto !important; */
}
ol,