Reposyncer仓库同步
@@ -63,9 +63,9 @@ function Main(props){
查看详情
-
+ */}
{/* 是站点仓库则显示,否则隐藏 */}
- {projectDetail && projectDetail.web_site && projectDetail.author.type === "User" &&
+ {/* {projectDetail && projectDetail.web_site && projectDetail.author.type === "User" &&
个人建站服务
@@ -74,7 +74,7 @@ function Main(props){
查看详情
- }
+ } */}
)
diff --git a/src/forge/Settings/CollaboratorMember.jsx b/src/forge/Settings/CollaboratorMember.jsx
index 0f407bf21..5b850d9e5 100644
--- a/src/forge/Settings/CollaboratorMember.jsx
+++ b/src/forge/Settings/CollaboratorMember.jsx
@@ -62,7 +62,7 @@ function CollaboratorMember({projectsId,owner,project_id,author,showNotification
if(page > 1 && ( listData && listData.length === 1)){
setPage(page-1);
}else{
- setListData(result.data.members);
+ setListData(result.data.members || []);
setTotal(result.data.total_count);
}
setIsSpin(false);
diff --git a/src/forge/Settings/Setting.js b/src/forge/Settings/Setting.js
index be7eebe8f..96b779531 100644
--- a/src/forge/Settings/Setting.js
+++ b/src/forge/Settings/Setting.js
@@ -15,8 +15,8 @@ const menu = [
{name:"代码库",index:"code"},
{name:"疑修 (Issue)",index:"issues"},
{name:"合并请求 (PR)",index:"pulls"},
- {name:"引擎 (Engine)",index:"devops"},
- {name:"数据集",index:"dataset"},
+ // {name:"引擎 (Engine)",index:"devops"},
+ // {name:"数据集",index:"dataset"},
// {name:"资源库",index:"resources"},
{name:"里程碑",index:"versions"},
{name:"维基 (Wiki)",index:"wiki"},
diff --git a/src/forge/Team/Index.jsx b/src/forge/Team/Index.jsx
index 0461b26ec..b4b316f68 100644
--- a/src/forge/Team/Index.jsx
+++ b/src/forge/Team/Index.jsx
@@ -1,5 +1,6 @@
-import React from 'react';
+import React,{useEffect,useState} from 'react';
+import axios from 'axios';
import { Route, Switch } from "react-router-dom";
import Loadable from "react-loadable";
import Loading from "../../Loading";
@@ -7,7 +8,8 @@ import { withRouter } from "react-router";
import { SnackbarHOC } from "educoder";
import { CNotificationHOC } from "../../modules/courses/common/CNotificationHOC";
import { TPMIndexHOC } from "../../modules/tpm/TPMIndexHOC";
-import ProjectDetail from '../Main/Detail'
+import ProjectDetail from '../Main/Detail';
+import { checkOpenedEnterprise } from './api';
import '../css/index.scss';
import './Index.scss';
@@ -42,6 +44,33 @@ const SubDetailIndex = Loadable({
// });
const team = CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(
((props)=>{
+ const OIdentifier = props.match.params.OIdentifier;
+ const [ organizeDetail , setOrganizeDetail ] = useState(undefined);
+ const [ enterpriseOpenInfo, setEnterpriseOpenInfo] = useState(false);
+ useEffect(()=>{
+ if(OIdentifier){
+ getDetail(OIdentifier);
+ }
+ },[OIdentifier]);
+
+ function getDetail(identifier) {
+ const url = `/organizations/${identifier}.json`;
+ axios.get(url).then(result=>{
+ if(result && result.data){
+ setOrganizeDetail(result.data);
+ const {id} = result.data;
+ checkOrgOpenEnterprise(id)
+ }
+ }).catch(error=>{})
+ }
+
+ function checkOrgOpenEnterprise(orgId){
+ checkOpenedEnterprise(orgId).then(res=>{
+ if(res && res.data.code === 200){
+ setEnterpriseOpenInfo(res.data.data)
+ }
+ })
+ }
return (
@@ -84,7 +113,7 @@ const team = CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(
{
- return
+ return
}}
>
@@ -92,9 +121,17 @@ const team = CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(
(
-
+
)}
>
+
+ {/* 开通企业工作台 */}
+ {
+ return
+ }}
+ >
{/* 组织下的项目详情 */}
(
-
+
)}
>
diff --git a/src/forge/Team/List.jsx b/src/forge/Team/List.jsx
index c69910749..9aa263d17 100644
--- a/src/forge/Team/List.jsx
+++ b/src/forge/Team/List.jsx
@@ -7,7 +7,7 @@ import Item from './ListItem';
import Right from './RightBox';
import NoData from '../Nodata';
import CheckProfile from '../Component/ProfileModal/Profile';
-import { Menu , Pagination , Dropdown , Spin , Tooltip , Radio } from 'antd';
+import { Menu , Pagination , Dropdown , Spin , Tooltip , Radio , Button } from 'antd';
import ConcentrateProject from '../users/GeneralView/ConcentrateProject';
import { getImageUrl } from 'educoder';
import RenderHtml from "../../components/render-html";
@@ -22,27 +22,12 @@ function List(props){
const [ search , setSearch ] = useState(undefined);
const [ page , setPage ] = useState(1);
const [ sortBy , setSortBy ] = useState("updated_on");
- const [ organizeDetail , setOrganizeDetail ] = useState(undefined);
const [ mode , setMode ] = useState("overview");
const OIdentifier = props.match.params.OIdentifier;
- const { current_user } = props;
- console.log(props);
+ const { organizeDetail, enterpriseOpenInfo } = props;
+ console.log("------------------",enterpriseOpenInfo,props);
- useEffect(()=>{
- if(OIdentifier){
- getDetail(OIdentifier);
- }
- },[OIdentifier]);
-
- function getDetail(id) {
- const url = `/organizations/${id}.json`;
- axios.get(url).then(result=>{
- if(result && result.data){
- setOrganizeDetail(result.data);
- }
- }).catch(error=>{})
- }
useEffect(()=>{
if(organizeDetail){
@@ -113,9 +98,21 @@ function List(props){
{organizeDetail && organizeDetail.nickname}
- {organizeDetail && organizeDetail.is_admin ?
- 设置
- :""}
+
+ {
+ !enterpriseOpenInfo.isOpen ? organizeDetail.is_admin && (
+
+
+
+ ) :
+ enterpriseOpenInfo.url ? (
+
+ ) : (
+
+ )
+ }
+ {organizeDetail.is_admin && }
+
diff --git a/src/forge/Team/Setting/TeamSettingIndex.jsx b/src/forge/Team/Setting/TeamSettingIndex.jsx
index 91db1156b..1078ec924 100644
--- a/src/forge/Team/Setting/TeamSettingIndex.jsx
+++ b/src/forge/Team/Setting/TeamSettingIndex.jsx
@@ -41,7 +41,7 @@ const CLANew = Loadable({
export default (( props )=>{
const pathname = props.location.pathname;
const OIdentifier = props.match.params.OIdentifier;
- const {organizeDetail} = props;
+ const {organizeDetail , enterpriseOpened, mygetHelmetapi} = props;
useEffect(()=>{
if(organizeDetail){
const {nickname} = organizeDetail;
@@ -68,8 +68,8 @@ export default (( props )=>{
const array = {list:[
{name:'基本设置',icon:"icon-base",href:`/${OIdentifier}/setting`},
{name:'组织首页管理',icon:"icon-huabanfuben",href:`/${OIdentifier}/setting/index`},
- {name:'组织成员管理',icon:"icon-zuzhichengyuan",href:`/${OIdentifier}/setting/member`},
- {name:'组织团队管理',icon:"icon-zuzhixiangmu",href:`/${OIdentifier}/setting/group`},
+ {name:'组织成员管理',icon:"icon-zuzhichengyuan",href:`/${OIdentifier}/setting/member`, hide: enterpriseOpened},
+ {name:'组织团队管理',icon:"icon-zuzhixiangmu",href:`/${OIdentifier}/setting/group`, hide: enterpriseOpened},
// {name:'管理web钩子',icon:"icon-zhongqingdianxinicon10",href:`/${OIdentifier}/setting/hooks`}
{name:'CLA管理',img:claIcon,href:`/${OIdentifier}/setting/agreement`,hide:organizeDetail && !organizeDetail.enabling_cla}
],
@@ -78,7 +78,7 @@ export default (( props )=>{
return(
- 组织设置} nav={array}>
+ 组织设置} nav={array} history={props.history}>
diff --git a/src/forge/Team/Setting/enterprise.jsx b/src/forge/Team/Setting/enterprise.jsx
new file mode 100644
index 000000000..4c0fe52a6
--- /dev/null
+++ b/src/forge/Team/Setting/enterprise.jsx
@@ -0,0 +1,177 @@
+import React, { useEffect, useState } from 'react';
+import { WhiteBack , FlexAJ } from '../../Component/layout';
+import { Table , Pagination , Button, message, Select, Spin } from 'antd';
+import styled from 'styled-components';
+import './teamSetting.scss';
+import { createEnterpriseByGitlinkOrgId, getRoleList, getUserList, checkOpenedEnterprise } from '../api';
+
+const Img = styled.img`{
+ width:30px;
+ height:30px;
+ border-radius:50%;
+}`
+const limit = 15;
+export default (({organizeDetail,history,match, current_user})=>{
+ const OIdentifier = match.params.OIdentifier;
+ const {login} = current_user
+ const [ page , setPage ] = useState(1);
+ const [ total , setTotal ] = useState(0);
+ const [ data , setData ] = useState(undefined);
+ const [ roleList, setRoleList] = useState([]);
+ const [loading, setLoading] = useState(false);
+ // 定时器
+ let intervalId = null;
+ console.log(organizeDetail);
+
+ useEffect(()=>{
+ getRoleList().then(res=>{
+ const {code, rows} = res && res.data
+ if(code === 200){
+ setRoleList(rows);
+ }
+ })
+ }, [])
+
+ useEffect(()=>{
+ if(organizeDetail){
+ const {nickname} = organizeDetail;
+ document.title = `开通组织工作台-${nickname}`;
+ pollData()
+ }
+ }, [organizeDetail])
+
+ useEffect(()=>{
+ if(organizeDetail && organizeDetail.id){
+ getData(organizeDetail.id);
+ }
+ },[organizeDetail,page])
+
+ // 轮询函数
+ const pollData = () => {
+ checkOpenedEnterprise(organizeDetail.id).then(res=>{
+ if(res && res.data.code === 200){
+ const {data} = res.data;
+ if(data.isOpen && !data.url){
+ setLoading(true)
+ }else if(data.isOpen){
+ clearInterval(intervalId);
+ window.location = data.url
+ }
+ }
+ })
+ };
+
+ function getData(id){
+ getUserList(id).then(res=>{
+ const {code, rows, total} = res && res.data
+ if(code === 200){
+ setData(rows);
+ setTotal(total);
+ }
+ })
+ }
+
+ // 切换分页
+ function ChangePage(page){
+ setPage(page);
+ }
+
+ const columns = [
+ {
+ title: '头像',
+ dataIndex: 'imageUrl',
+ render:(value)=>{
+ return(
+
+ )
+ }
+ },
+ {
+ title: '用户名',
+ dataIndex: 'nickname',
+ },
+ {
+ title: '邮箱',
+ dataIndex: 'email',
+ },
+ {
+ title: '所属团队',
+ dataIndex: ['role', 'roleKey'],
+ width:"20%",
+ render:(value,record)=>{
+ return
+ }
+ },
+ {
+ title: '操作',
+ dataIndex: 'username',
+ key: "action",
+ render:(value)=>{
+ return (
+
+ )
+ }
+ }
+ ]
+
+ function createEnterprise(){
+ const users = data.length > 0 ? data.map(item=>{return {userId: item.userId, roleKey: item.role.roleKey}}) :[];
+ createEnterpriseByGitlinkOrgId(organizeDetail.id, users).then(res=>{
+ if(res && res.data.code === 200){
+ message.success('开通成功');
+ intervalId = setInterval(pollData, 1000);
+ }else{
+ message.error(res && res.data.msg)
+ }
+ })
+ }
+ return(
+
+
+
+ 首次创建组织工作台时,系统将根据组织团队用户在组织工作台中根据不同团队初始化成不同角色。请您知悉以下角色权限,再次确认组织成员的角色分配。
+ 组织管理员:原owner团队成员,对组织内所有代码库均具有管理员权限,在组织工作台中拥有最高管理权限
+ 项目管理员:原管理员团队成员,对组织内所有代码库均具有管理员权限,在组织工作台中拥有项目管理权限
+ 普通成员:原开发者及报告者团队成员,对组织内所有代码库均具有开发者权限,在组织工作台中拥有项目基础使用权限及查看权限
+
+
+
+ {/* {setSearch(value)}}/> */}
+
+ {/*
+ 角色筛选
+ */}
+
+
+
+ {
+ total > limit ?
+
+ :""
+ }
+
+
+
+
+
+
+
+ )
+})
\ No newline at end of file
diff --git a/src/forge/Team/Sub/Detail.jsx b/src/forge/Team/Sub/Detail.jsx
index 6062fd13a..184fc1742 100644
--- a/src/forge/Team/Sub/Detail.jsx
+++ b/src/forge/Team/Sub/Detail.jsx
@@ -26,9 +26,14 @@ const Setting = Loadable({
loader: () => import("../Setting/TeamSettingIndex"),
loading: Loading,
});
+const Enterprise = Loadable({
+ loader: () => import("../Setting/enterprise"),
+ loading: Loading,
+});
function Detail(props){
const OIdentifier = props.match.params.OIdentifier;
const pathname = props.location.pathname;
+ const {enterpriseOpened} = props;
const [ detail , setDetail ] = useState(undefined);
const [ flag , setFlag ] = useState(true);
@@ -86,18 +91,11 @@ function Detail(props){
title={detail.nickname}
desc={!buttonflag && detail.description}
img={detail.avatar_url}
- rightBtn={
-
- {flag && !buttonflag && detail.is_admin ?
- 设置
- :""}
- {buttonflag &&
-
- 组织成员{detail.num_users && {detail.num_users}}
- 组织团队{detail.num_teams &&{detail.num_teams}}
-
- }
-
+ rightBtn={buttonflag && !enterpriseOpened &&
+
+ 组织成员{detail.num_users && {detail.num_users}}
+ 组织团队{detail.num_teams &&{detail.num_teams}}
+
}
bottomInfos={
!buttonflag &&
@@ -140,16 +138,15 @@ function Detail(props){
{
- return
+ return
+ }}
+ >
+ {
+ return
}}
>
-
- {
- return
- }}
- >
)
diff --git a/src/forge/Team/api.js b/src/forge/Team/api.js
new file mode 100644
index 000000000..057bd76e5
--- /dev/null
+++ b/src/forge/Team/api.js
@@ -0,0 +1,36 @@
+
+import fetch from './fetch';
+
+// 查询组织是否开通企业
+export function checkOpenedEnterprise(orgId){
+ return fetch({
+ url:`/pms/pmsEnterprise/${orgId}/workbenchUrl`,
+ method: 'get',
+ })
+ }
+
+// 组织升级为企业
+export function createEnterpriseByGitlinkOrgId(orgId, data) {
+ return fetch({
+ url: `/pms/pmsEnterprise/createByGitlinkOrgId/${orgId}`,
+ method: 'POST',
+ data: data
+ })
+ }
+
+// 可选角色列表
+export function getRoleList(){
+ return fetch({
+ url:`/pms/pmsEnterprise/roleList`,
+ method: 'get',
+ })
+ }
+
+ // 获取工作台初始用户列表
+ export function getUserList(orgId){
+ return fetch({
+ url:`/pms/pmsEnterprise/gitlinkUserList/${orgId}`,
+ method: 'get',
+ })
+ }
+
\ No newline at end of file
diff --git a/src/forge/Information/fetch.js b/src/forge/Team/fetch.js
similarity index 57%
rename from src/forge/Information/fetch.js
rename to src/forge/Team/fetch.js
index f74c1faef..ad8534771 100644
--- a/src/forge/Information/fetch.js
+++ b/src/forge/Team/fetch.js
@@ -1,26 +1,30 @@
+
import axios from 'axios';
+import cookie from 'react-cookies';
import { message , notification } from 'antd';
+// import { TokenKey } from '../javaFetch';
+
+export const TokenKey = 'autologin_trustie';
function beforeFetch(actionUrl){
if (window.location.href.indexOf('localhost') < 0) {
axios.defaults.withCredentials = true;
}
- const config = {
+
+ const service = axios.create({
baseURL: actionUrl,
timeout: 1800000, // 请求超时时间
- }
+ });
- const service = axios.create(config);
-
- service.interceptors.request.use(request => {
- let deptId = sessionStorage.getItem('deptId')
-
- if (deptId) {
- // 用于权限区分
- request.headers['Dept-Id'] = deptId
+ service.interceptors.request.use(config => {
+ if (cookie.load(TokenKey)) {
+ // '4b126b99cc7314b1afff1d08ab1d1f5b7561310e'
+ config.headers['Authorization'] = cookie.load(TokenKey); // 让每个请求携带自定义token 请根据实际情况自行修改
}
- return request
- })
+ return config;
+ }, error => {
+ console.log(error);
+ });
service.interceptors.response.use(
response => {
@@ -47,8 +51,9 @@ function beforeFetch(actionUrl){
)
return service;
}
-let settings = localStorage.chromesetting&&JSON.parse(localStorage.chromesetting);
-let actionUrl = settings && settings.common.zone +'/api';
+let settings = localStorage.chromesetting && localStorage.chromesetting !=="undefined" && JSON.parse(localStorage.chromesetting);
+let actionUrl = settings && settings.common.gateway +'/api';
+// let actionUrl = 'http://119.3.190.9:4100/api';
const service = beforeFetch(actionUrl);
export const httpUrl = actionUrl;
diff --git a/src/forge/Wiki/EditWiki.jsx b/src/forge/Wiki/EditWiki.jsx
deleted file mode 100644
index bf89653c8..000000000
--- a/src/forge/Wiki/EditWiki.jsx
+++ /dev/null
@@ -1,370 +0,0 @@
-import React, { useEffect, useCallback, useState } from 'react';
-import { Button, Checkbox, Form, Icon, Radio, Input, message } from 'antd';
-import MDEditor from "../../modules/tpm/challengesnew/tpm-md-editor";
-import DelModal from './components/ModalFun';
-import { weekModal, monthModal } from './components/config';
-import { getWiki, wikiPages, addWiki, updateWiki, markdownToTree, treeToMd } from './api';
-import './Index.scss';
-import { Base64 } from 'js-base64';
-
-
-export default Form.create()(({ form, history, showNotification, projectDetail, match, project }) => {
- const {location:{pathname, search}} = history;
- const permission = projectDetail && projectDetail.permission && projectDetail.permission !== "Reporter";
-
- const { getFieldDecorator, validateFields, setFieldsValue } = form;
- let projectsId = match.params.projectsId;
- let owner = match.params.owner;
- let wikiName = ''
- let key = '';
- if (!pathname.endsWith('/wiki/add')) {
- wikiName = pathname.split('/')[4];
- key = pathname.split('/')[5];
- }else{
- key = search.split('=').pop();
- }
-
- const [fileArrInit, setFileArrInit] = useState(null);
- const [content, setContent] = useState("欢迎来到Wiki");
- const [modal, setModal] = useState(false);
- const [operateFlag, setOperateFlag ] = useState(false);
- const [modalType, setModalType] = useState();
- const [sidebar, setSidebar] = useState(undefined);
- const [menuList, setMenuList] = useState(undefined);
-
- useEffect(()=>{
- if(projectDetail){
- const { author, name} = projectDetail;
- if(wikiName){
- document.title = `编辑${wikiName}-维基-${author.name}/${name}`;
- }else{
- document.title = `新建维基-${author.name}/${name}`;
- }
- }
- }, [projectDetail, wikiName])
-
- useEffect(() => {
- wikiName && project && getWiki({
- owner,
- repo: projectsId,
- pageName: wikiName,
- projectId: project.id
- }).then(res => {
- if (res && res.data) {
- const content = Base64.decode(res.data.md_content);
- setContent(content);
- setFieldsValue({
- title: search === "?copy" ? `${res.data.name}(复制)` : res.data.name,
- md_content: content,
- });
- }
- });
- }, [owner, wikiName]);
-
- // 加载wiki列表
- useEffect(() => {
- project && wikiPages({
- owner: owner,
- repo: projectsId,
- projectId: project.id
- }).then(res => {
- if (res && res.message === "200" && Array.isArray(res.data)) {
- setFileArrInit(res.data);
- // 仓库存在没有创建过wiki的情况
- if(res.data.length){
- // 获取sidebar文件内容
- getWiki({
- owner,
- repo: projectsId,
- pageName: '_Sidebar',
- projectId: project.id
- }).then(res => {
- if (res && res.data) {
- const sidebarDecode = Base64.decode(res.data.md_content);
- setSidebar(sidebarDecode);
- key && setMenuList(markdownToTree(sidebarDecode))
- }
- });
- }
- } else {
- setFileArrInit([]);
- }
- });
- }, [project]);
-
- const helper = useCallback(
- (label, name, rules, widget, initialValue, rightComponent) => (
-
- {getFieldDecorator(name, { rules, initialValue, validateFirst: true, })(widget)}
- {rightComponent}
-
- ), []);
-
-
- function onContentChange(value) {
- setContent(value);
- setFieldsValue({
- md_content: value
- });
- };
-
- // 保存wiki文件,包括新增和修改
- function saveFile() {
- if(operateFlag) {
- setOperateFlag(true);
- return;
- };
- validateFields((err, values) => {
- if (!err) {
- const {md_content, title} = values;
- if (wikiName && search!== "?copy") {
- updateWiki({
- owner,
- repo: projectsId,
- projectId: project.id,
- pageName: wikiName,
- title,
- message: '',
- content_base64: Base64.encode(md_content)
- }).then(res => dealRes(res, title));
- } else {
- // 由于wiki在底层是由wikiname标识的md文件,所以对于所有的页面,都不能重名
- if (Array.isArray(fileArrInit)) {
- for (const item of fileArrInit) {
- if (item.name === title) {
- message.error('不能与已有文件标题相同');
- setOperateFlag(false);
- return false;
- }
- }
- }
- addWiki({
- owner,
- repo: projectsId,
- projectId: project.id,
- pageName: title,
- title,
- message: '',
- content_base64: Base64.encode(md_content)
- }).then(res => dealRes(res, title));
- }
- }
- })
- }
-
- function dealRes(res, title) {
- if (res && (res.message === "201" || res.message === "200")) {
- if(wikiName && search!== "?copy"){
- // 如果有更改wiki文件名,则修改sidebar
- if(wikiName === title){
- message.success("操作成功");
- goBack();
- }else{
- // 找到相同的key值node修改title参数,再保存sidebar
- const newMenuList = menuList;
- editTitleByKey(newMenuList, key, title);
- updateSidebar(treeToMd(newMenuList), title);
- }
- }else{
- // 根据路由判断是新增的一级页面还是子页面
- if(search === "?copy"){
- // 截断key的前几位,获取父元素的key值
- const keyArr = key.split('-');
- keyArr.pop();
- const list = menuList;
- addChildrenByKey(list, keyArr.join('-'), title);
- updateSidebar(treeToMd(list), title);
- }else if(search.includes("?key")){
- // 遍历menuList找到相同key的节点,children push[[页面]]
- const list = menuList;
- addChildrenByKey(list, key, title);
- updateSidebar(treeToMd(list), title);
- }else{
- if(fileArrInit.length){
- updateSidebar(`${sidebar}\n[[${title}]]`, title);
- }else{
- // 仓库第一次创建wiki文件
- addWiki({
- owner,
- repo: projectsId,
- projectId: project.id,
- pageName: "_Sidebar",
- title: "_Sidebar",
- message: '',
- content_base64: Base64.encode(`[[${title}]]`)
- }).then(res => {
- if(res && res.message === "201"){
- message.success("操作成功");
- goBack();
- }
- });
- }
- }
- }
- } else if (res && res.message === "500") {
- setOperateFlag(false);
- message.error('请检查格式是否正确或文件名是否重复');
- } else {
- setOperateFlag(false);
- showNotification(res.data || "操作失败");
- }
- }
-
- function updateSidebar(content, newTitle){
- updateWiki({
- owner,
- repo: projectsId,
- projectId: project.id,
- pageName: '_Sidebar',
- title: '_Sidebar',
- message: '',
- content_base64: Base64.encode(content)
- }).then(res => {
- if (res && res.message === "200") {
- message.success("操作成功");
- if(newTitle){
- // 用户修改了wiki名称
- history.push(`/${owner}/${projectsId}/wiki/${encodeURI(newTitle)}/${key}`)
- return;
- }
- goBack();
- }
- });
- }
-
- // 递归menuList, 找到相同key值修改title名称
- function editTitleByKey(list, key, newTitle){
- for (let index = 0; index < list.length; index++) {
- const element = list[index];
- if (element.key == key) {
- const {title} = element;
- element.title = `${title.substring(0, title.indexOf('[['))}[[${newTitle}]]`;
- return true;
- }else if (element.children.length) {
- let result = editTitleByKey(element.children, key, newTitle);
- if (result) {
- return result;
- }
- }
- }
- }
-
- // 递归menuList 创建子页面
- function addChildrenByKey(list, key, name){
- for (let index = 0; index < list.length; index++) {
- const element = list[index];
- if (element.key == key) {
- const {title} = element;
- element.children.push({
- title: `\t${title.substring(0, title.indexOf('- '))}[[${name}]]`,
- children: []
- });
- return true;
- }else if (element.children.length) {
- let result = addChildrenByKey(element.children, key, name);
- if (result) {
- return result;
- }
- }
- }
- }
-
- function goBack() {
- history.go(-1);
- }
-
- function changeModal(e) {
- setModal(e.target.checked);
- if (!e.target.checked) {
- setModalType();
- }
- }
-
- function changeModalType(e) {
- let value = e.target.value;
- if (!content) {
- setModalContent(value);
- return;
- }
- DelModal({
- title: '添加模版',
- contentTitle: `您确定要添加“${value}”模板吗`,
- content: `此操作会将“${value}”模板替换编辑栏内所有内容,请确认以防文件的丢失`,
- okText: '确认添加',
- onOk: () => {
- setModalType(value);
- setModal(true);
- setModalContent(value);
- }
- });
- }
-
- function setModalContent(value) {
- if (value === '周报') {
- setContent(weekModal);
- setFieldsValue({
- md_content: weekModal
- });
- } else if (value === '月报') {
- setContent(monthModal);
- setFieldsValue({
- md_content: monthModal
- });
- }
- }
-
-
- return (
-
-
- Wiki {wikiName ? search === "?copy" ? '复制' : '编辑' : '新增'}页面
-
-
-
-
标题
- {helper(
- "",
- "title",
- [
- { required: true, message: "请输入标题" },
- { pattern: /^(?!-).*$/, message: '不能以-开头' }
- ],
-
- )}
-
-
-
- {getFieldDecorator('md_content', {
- rules: [{ required: true, message: "请输入wiki内容" }],
- validateFirst: true,
- initialValue: "欢迎来到Wiki"
- })()}
-
-
- 添加模版
-
-
- 周报
- 月报
-
-
-
-
- {permission &&
}
-
-
- )
-})
\ No newline at end of file
diff --git a/src/forge/Wiki/Index.jsx b/src/forge/Wiki/Index.jsx
deleted file mode 100644
index 08288c366..000000000
--- a/src/forge/Wiki/Index.jsx
+++ /dev/null
@@ -1,342 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import { Button, Dropdown, Icon, Input, Menu, Select, message, Spin, Modal } from 'antd';
-import { getImageUrl, timeAgo } from 'educoder';
-import CopyTool from '../Component/CopyTool';
-import Welcome from './Welcome';
-import RenderHtml from "../../components/render-html";
-
-import { wikiPages, getWiki, parseSidebar, updateWiki, treeToMd, deleteSameKey } from './api';
-import { httpUrl } from './fetch';
-import './Index.scss';
-import './components/ModalFun/index.scss';
-import { isArray } from 'lodash';
-import { Base64 } from 'js-base64';
-import Sidebar from './components/sidebar';
-import UploadWiki from './components/uploadWiki';
-import axios from 'axios';
-const InputGroup = Input.Group;
-const { Option } = Select;
-
-export default (props) => {
- const { match, history, showNotification, project, projectDetail } = props;
- const {location:{pathname}} = history;
- const permission = projectDetail && projectDetail.permission && projectDetail.permission !== "Reporter";
- let projectsId = match.params.projectsId;
- let owner = match.params.owner;
-
- const [fileArrInit, setFileArrInit] = useState(null);
- const [checkItem, setCheckItem] = useState({});
- const [itemDetail, setItemDetail] = useState({});
-
- const [fileArr, setFileArr] = useState([]);
- const [fileList, setFileList] = useState([]);
- const [reload, setReload] = useState();
-
- const [urlType, setUrlType] = useState('HTTPS');
- const [visible, setVisible] = useState(false);
- const [menuName, setMenuName] = useState(undefined);
- const [addMenuError, setAddMenuError] = useState(undefined);
- const [sidebar, setSidebar] = useState(undefined);
- const [defaultSelectedKeys, setDefaultSelectedKeys] = useState(undefined);
-
- useEffect(()=>{
- window.scrollTo(0,0);
- }, [])
-
- useEffect(()=>{
- if(projectDetail){
- const { author, name} = projectDetail;
- if(Object.keys(checkItem).length === 0){
- document.title = `维基-${author.name}/${name}`;
- }else{
- document.title = `${checkItem.name}-维基-${author.name}/${name}`;
- }
- }
- }, [projectDetail, checkItem])
-
- // 加载wiki列表
- useEffect(() => {
- project && wikiPages({
- owner: owner,
- repo: projectsId,
- projectId: project.id
- }).then(async res => {
- if (res && res.message === "200" && isArray(res.data)) {
- setFileArr(res.data);
- setFileArrInit(res.data);
- // 解析sidebar获取目录list
- const info = await parseSidebar(res.data, {
- owner: owner,
- repo: projectsId,
- projectId: project.id
- })
- if(!info){return}
- const {menuList, sidebar} = info;
- setSidebar(sidebar)
- setFileList(menuList);
- let firstWikiNode = undefined;
- if(!pathname.endsWith('/wiki')){
- const {wikiName} = match.params;
- firstWikiNode = findNodeByName(menuList, wikiName);
- } else{
- // 找到目录树中第一个[[页面]]
- firstWikiNode = findFirstWiki(menuList);
- }
- // 当前选中wiki被删除
- !firstWikiNode && (firstWikiNode = findFirstWiki(menuList));
- // 设置目录 选中节点初始化
- setDefaultSelectedKeys([firstWikiNode.key+""]);
- const title = firstWikiNode.titleStr;
- const firstWiki = res.data.filter(item => { return title === item.name })[0];
- setCheckItem({
- ...firstWiki,
- key: firstWikiNode.key
- })
- if(window.location.pathname.indexOf('/wiki') === -1) return
- history.push(encodeURI(`/${owner}/${projectsId}/wiki/${firstWiki.sub_url}/${firstWikiNode.key}`));
- } else {
- setFileArr([]);
- setFileArrInit([]);
- }
- });
- }, [project, reload])
-
- // 加载单个wiki详情,sub_url: 后端转义的字符串
- useEffect(() => {
- project && checkItem.sub_url && getWiki({
- owner: owner,
- repo: projectsId,
- pageName: checkItem.sub_url,
- projectId: project.id
- }).then(res => {
- if (res && res.message === "200") {
- setItemDetail(res.data);
- } else {
- showNotification("加载失败")
- }
- });
- }, [project, checkItem]);
-
- function findNodeByName(list, name){
- for (let index = 0; index < list.length; index++) {
- const element = list[index];
- if (element.title.indexOf(`[[${name}]]`) !== -1) {
- return element;
- }else if (element.children.length) {
- let result = findNodeByName(element.children, name);
- if (result) {
- return result;
- }
- }
- }
- }
-
- // 初始化页面:递归menulist找到第一个页面
- function findFirstWiki(list){
- for (let index = 0; index < list.length; index++) {
- const element = list[index];
- if (element.title.trim().startsWith('[[')) {
- return element;
- }else if (element.children.length) {
- let result = findFirstWiki(element.children);
- if (result) {
- return result;
- }
- }
- }
- }
-
-
- function filterTree(list, value, arr = []){
- if(!list.length) return []
- for(let item of list){
- const bool = item.title.match(new RegExp(value, 'i'));
- let node = JSON.parse(JSON.stringify(item));
- node.children = [];
- bool && arr.push(node);
- if(item.children && item.children.length){
- filterTree(item.children, value, bool ? node.children : arr);
- }
- }
- return arr
- }
-
-
- function goUser(login) {
- window.location.href = `/${login}`;
- }
-
- function addFile() {
- // 新增一级页面
- history.push(`/${owner}/${projectsId}/wiki/add`);
- }
-
- // 新增目录
- function addMenu(){
- if(!menuName){
- setAddMenuError('请输入目录名称');
- return;
- }
- if(new RegExp("^[ ]+$").test(menuName)){
- setAddMenuError("不能仅输入空格");
- return;
- }
- // 校验一级目录中是否有相同名称
- const oneMenuList = fileList.filter(item=>!item.title.trim().startsWith('[[')).map(i=>i.title.trim())
- if(oneMenuList.includes(`- ${menuName}`)){
- setAddMenuError('不能与已有文件标题相同');
- return;
- }
-
- // 重写fileList,再转换成md内容,最后保存sidebar
- const newSidebarList = fileList.concat({title: `- ${menuName}`, children: []})
- updateWikiFun(newSidebarList, 1);
- }
-
- // 更新wiki sidebar文件
- function updateWikiFun(sidebarList, type){
- updateWiki({
- owner,
- repo: projectsId,
- projectId: project.id,
- pageName: '_Sidebar',
- title: '_Sidebar',
- message: '',
- content_base64: Base64.encode(treeToMd(sidebarList))
- }).then(res => {
- if (res && res.message === "200") {
- if(type === 1){
- setVisible(false);
- setMenuName(undefined);
- message.success('操作成功');
- }
- // setFileList(sidebarList);
- setReload(Math.random());
- }else {
- message.error(res.data || "操作失败");
- }
- });
- }
-
- function goEdit(params) {
- history.push(encodeURI(`/${owner}/${projectsId}/wiki/${checkItem.sub_url}/${checkItem.key}/edit${params}`));
- }
-
- function preview() {
- window.open(encodeURI(`/${owner}/${projectsId}/wiki/preview/${project.name}/${project.id}`));
- }
-
- // 支持 Markdown,Html,Pdf格式文件
- const menu = (
-
- );
-
- function downloadWiki(type) {
- window.open(`${httpUrl}/api/wikiExport/wikiExport-wrapper?repoName=${projectsId}&owner=${owner}&type=${type}&projectName=${project.name}&projectId=${project.id}`);
- }
-
- function changeitem(item){
- const {name, key} = item;
- const wiki = fileArrInit.filter(item => { return item.name == name })[0];
- if(!wiki){
- // 不存在的wiki,修正sidebarfindSameKeyByDel
- const menuListByDel = deleteSameKey(fileList, key);
- updateWikiFun(menuListByDel);
- message.success("不存在的wiki")
- return
- }
- setCheckItem({
- ...wiki,
- key
- })
- history.push(encodeURI(`/${owner}/${projectsId}/wiki/${name}/${key}`));
- }
-
- return (
-
- {fileArrInit && fileArrInit.length ?
-
-
-
-
- {
- permission ?
-
-
-
-
: "Wiki文档"
- }
-
-
- {
- permission &&
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* 读sidebar转换成目录树 */}
-
-
-
-
-
- {checkItem.wiki_clone_link &&
-
-
-
- }
-
-
-
-
-
-
-
{checkItem.name}
-
{ checkItem.commit && goUser(checkItem.commit.author.name) }}>
- {itemDetail.image_url &&
}
- {itemDetail.userName}
-
-
上次修改于{checkItem.commit ? timeAgo(checkItem.commit.author.date) : '刚刚'}
-
- {permission &&
}
- {permission &&
}
-
-
- {itemDetail && itemDetail.md_content &&
}
-
-
-
- :
-
- }
- {setVisible(false);setAddMenuError(undefined);setMenuName(undefined);}} onOk={addMenu} className="wikiAddMenu myself-modal" width={450} centered>
- 目录名称:
- {setMenuName(e.target.value);setAddMenuError(undefined)}} maxLength={50} autoFocus>
- {addMenuError}
-
-
- )
-}
diff --git a/src/forge/Wiki/Index.scss b/src/forge/Wiki/Index.scss
deleted file mode 100644
index 58ffcef09..000000000
--- a/src/forge/Wiki/Index.scss
+++ /dev/null
@@ -1,424 +0,0 @@
-$wikiColor: #466aff;
-$primaryBtnHover: #6482ff;
-body {
- width: 100% !important;
-}
-.ant-spin-nested-loading > div > .ant-spin.opacitySpin{
- max-height: 100vh;
- background: rgba(255,255,255,1);
-}
-.wiki-main {
- width: 1200px;
- min-height: 400px;
- margin: 20px auto 60px;
-
- .ant-btn-primary {
- background-color: $wikiColor;
- border-color: $wikiColor;
- &:hover,
- &:focus,
- &:active {
- background-color: $primaryBtnHover;
- }
- }
-
- .ant-btn-default:hover,
- .ant-btn-default:active,
- .ant-btn-default:focus {
- background: #f3f4f6;
- color: #333;
- border-color: #d0d0d0;
- }
-
- .wiki-head {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 0 20px;
- height: 64px;
- background: #fafcff;
- box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.13);
- border-radius: 4px;
- border-bottom-left-radius: 0;
- .ant-btn .anticon {
- margin: 0 -3px 0 0;
- }
- }
-
- .head-title {
- font-size: 20px;
- color: #05101a;
- line-height: 30px;
- font-weight: 500;
-
- .anticon-right {
- color: #666;
- font-size: 0.9rem;
- }
- }
-
- .back-wiki {
- color: $wikiColor;
- cursor: pointer;
- &:hover {
- color: $primaryBtnHover;
- }
- }
-
- .head-log-middle {
- width: 3rem;
- height: 3rem;
- margin-right: 0.35rem;
- border-radius: 50%;
- }
-
- .head-log-small {
- width: 1.5rem;
- height: 1.5rem;
- margin-right: 0.35rem;
- border-radius: 50%;
- }
-
- .user-box {
- font-size: 12px;
- font-family: "PingFangSC-Medium";
- color: $wikiColor;
- cursor: pointer;
- &:hover {
- color: $primaryBtnHover;
- }
- .head-log-small {
- position: relative;
- top: -2px;
- }
- }
-
- .time-ago {
- font-size: 12px;
- color: #333;
- letter-spacing: 0;
- line-height: 17px;
- font-weight: 400;
- font-family: "PingFangSC-Regular";
- }
-
- // .has-error .ant-form-explain,
- // .has-error .ant-form-split {
- // position: absolute;
- // }
- // .wiki-md .ant-form-explain{
- // bottom: -6px;
- // }
- .wiki-nav {
- max-height: 60vh;
- .wiki-search {
- padding: 0 14px;
- .ant-input-suffix {
- right: 20px;
- }
- &:hover .ant-input,
- &:focus .ant-input {
- border-color: $wikiColor !important;
- }
- }
- }
-
- .wiki-nav-parent {
- width: 280px;
- flex: none;
- // .wiki-nav-scroll{
- // width: 280px;
- // overflow-y: scroll;
- // }
- }
-
- .ant-form-item-children .ant-input:hover {
- border-color: $wikiColor !important;
- }
-
- .ant-checkbox-checked .ant-checkbox-inner {
- background-color: $wikiColor;
- border-color: $wikiColor;
- }
- .ant-radio-checked .ant-radio-inner,
- .ant-radio-checked::after {
- border-color: $wikiColor;
- }
-
- .ant-radio-inner::after {
- background-color: $wikiColor;
- }
-
- .ant-radio-group {
- display: block;
- margin: 10px 0 0 30px;
- }
-
- .ant-radio-wrapper:hover .ant-radio,
- .ant-radio:hover .ant-radio-inner,
- .ant-radio-input:focus + .ant-radio-inner {
- border-color: $wikiColor;
- }
-}
-
-#wikiUrl:focus {
- border-right: 1px solid #d9d9d9 !important;
-}
-
-.wiki-body {
- display: flex;
-}
-
-.wiki-content {
- flex: auto;
- width: 75%;
-}
-
-.wiki-content-detail {
- padding: 0 20px;
- word-break: break-all;
-}
-
-.ant-input-group.ant-input-group-compact.copy-url {
- display: flex;
- margin-top: 20px;
- .ant-select-selection__rendered {
- margin: 0 14px 0 5px;
- width: 3rem;
- font-size: 12px;
- }
- .ant-select-arrow {
- right: 4px;
- }
- .ant-input {
- font-size: 12px;
- font-family: "PingFangSC-Regular";
- color: #666;
- letter-spacing: 0;
- font-weight: 400;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- word-break: break-all;
- }
-
- .copy-wiki {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- padding: 0 5px;
- background: #fff;
- font-size: 1rem !important;
- border: 1px solid #d9d9d9;
- border-left: 0;
- color: $wikiColor;
- cursor: pointer;
- }
-}
-
-.wiki-url-type {
- .ant-select-dropdown-menu-item {
- font-size: 12px;
- }
-}
-
-.wiki-nav {
- min-height: 500px;
- padding: 20px 0;
- background: #ffffff;
- border: 1px solid rgba(153, 153, 153, 0.22);
- overflow-y: scroll;
- flex: none;
- color: #333;
- .ant-tree.ant-tree-directory > li.ant-tree-treenode-selected > span.ant-tree-node-content-wrapper::before, .ant-tree.ant-tree-directory .ant-tree-child-tree > li.ant-tree-treenode-selected > span.ant-tree-node-content-wrapper::before{
- background-color: #F4F6FF;
- }
- .ant-tree.ant-tree-directory > li span.ant-tree-node-content-wrapper.ant-tree-node-selected, .ant-tree.ant-tree-directory .ant-tree-child-tree > li span.ant-tree-node-content-wrapper.ant-tree-node-selected{
- color: $primary-color;
- }
- .ant-tree.ant-tree-directory > li.ant-tree-treenode-selected > span.ant-tree-switcher, .ant-tree.ant-tree-directory .ant-tree-child-tree > li.ant-tree-treenode-selected > span.ant-tree-switcher{
- color: $primary-color;
- }
-}
-
-.wiki-nav-title {
- display: flex;
- justify-content: space-between;
- align-items: center;
- height: 50px;
- padding: 0 10px 0 10px;
- font-size: 14px;
- letter-spacing: 0;
- font-weight: 400;
- font-family: "PingFangSC-Regular";
- border-bottom: 1px solid #eee;
- line-height: 16px;
- cursor: pointer;
-
- .delete-title-icon {
- display: none;
- }
-
- &:hover {
- background-color: #fbfbfb;
- .delete-title-icon {
- display: inline-block;
- }
- }
-}
-
-.wiki-nav-title-parent {
- padding: 0 14px;
- &:hover {
- background: #fbfbfb;
- }
-}
-
-.wiki-nav-title.active {
- color: $wikiColor;
-}
-
-.wiki-content-head {
- margin: 20px 0 20px 20px;
- padding: 0 20px 20px 0;
- display: flex;
- justify-content: space-between;
- align-items: center;
- border-bottom: 1px solid #eee;
-}
-
-.wiki-content-head-left {
- width: 90%;
-}
-
-.nav-title-left {
- display: inline-flex;
- max-width: 90%;
- svg {
- margin-right: 0.5rem;
- flex: none;
- }
- .nav-title-left-text {
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- }
-}
-
-.wiki-detail-title {
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
-}
-// 预览页面样式文件
-.wiki-preview {
- overflow-y: scroll;
- height: 100%;
- .previewWiki{
- overflow-y: auto;
- .ant-tree-title{
- font-size: 16px;
- padding-left: 6px;
- }
- }
- .previewContent{
- flex: none;
- margin: 0 auto;
- }
- .wiki-body {
- width: 95%;
- }
- .ant-btn-primary {
- background-color: $wikiColor;
- border-color: $wikiColor;
- &:hover,
- &:focus,
- &:active {
- background-color: $primaryBtnHover;
- }
- }
- .preview-head {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 0 12rem 0 2rem;
- width: 100%;
- height: 8vh;
- background: rgb(39, 47, 76);
- color: #fff;
- }
-
- .preview-head-left {
- display: inline-flex;
- align-items: center;
- font-size: 24px;
- cursor: pointer;
-
- .icon-wendangyulan_icon {
- font-size: 24px !important;
- font-weight: 700;
- }
- }
-
- .preview-head-right {
- display: flex;
-
- .copy-url {
- margin-top: 0;
- }
- .copy-desc {
- width: 6rem;
- padding-top: 1px;
- flex:none
- }
- }
-
- .wiki-nav-title {
- padding: 0 10px 0 40px;
- }
- .wiki-nav-title.active {
- background-color: #f3f4f6;
- }
-
- .wiki-content-head {
- padding: 10px 20px 10px 20px;
- }
-
- .wiki-nav {
- padding: 20px 0;
- width: 20vw;
- border-bottom: 0;
- height: 92vh;
- }
- .wiki-content-detail {
- padding: 0 40px;
- img {
- max-width: 100%;
- }
- }
-
- .ant-btn:hover {
- background: #f3f4f6;
- color: #333;
- border-color: #d0d0d0;
- }
-}
-.wikiMEDEditor .editormd-dialog-footer{
- padding: 0;
-}
-.wikiAddMenu{
- &.myself-modal .ant-modal-body{
- text-align: left;
- padding: 40px 30px;
- }
-}
-.wikiAddMenuError{
- color: red;
-}
-.expendedAllAction{
- cursor: pointer;
- text-align: right;
- padding-right: 15px;
- color: $primary-color;
- border-bottom: 1px solid #d0d0d0;
-}
\ No newline at end of file
diff --git a/src/forge/Wiki/Preview.jsx b/src/forge/Wiki/Preview.jsx
deleted file mode 100644
index 4dfec1cc3..000000000
--- a/src/forge/Wiki/Preview.jsx
+++ /dev/null
@@ -1,181 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import { Input, Button, Select, Dropdown, Icon, Menu, message, Tree } from 'antd';
-import CopyTool from '../Component/CopyTool';
-import { wikiPages, getWiki, parseSidebar, } from './api';
-import { httpUrl } from './fetch';
-import './Index.scss';
-import { Base64 } from 'js-base64';
-import RenderHtml from '../../components/render-html';
-const {DirectoryTree, TreeNode} = Tree;
-const InputGroup = Input.Group;
-const { Option } = Select;
-
-export default (props) => {
- const { match, history, showNotification } = props;
-
- let projectsId = match.params.projectsId;
- let owner = match.params.owner;
-
- let projectName = match.params.projectName;
- let projectId = match.params.projectId;
- let key = 1;
-
- const [checkItem, setCheckItem] = useState({});
- const [itemDetail, setItemDetail] = useState({});
-
- const [fileArr, setFileArr] = useState([]);
- const [urlType, setUrlType] = useState('HTTPS');
- const [fileList, setFileList] = useState([]);
-
- useEffect(()=>{
- if(checkItem && checkItem.name){
- document.title = `${checkItem.name}-维基预览`
- }
- }, [checkItem])
-
- useEffect(() => {
- projectsId && wikiPages({
- owner: owner,
- repo: projectsId,
- projectId: projectId,
- }).then(async res => {
- if (res && res.message === "200") {
- setFileArr(res.data);
- // 解析sidebar获取目录list
- const info = await parseSidebar(res.data, {
- owner: owner,
- repo: projectsId,
- projectId
- })
- const {menuList, sidebar} = info;
- setFileList(menuList);
- if (res.data.length) {
- setCheckItem(res.data[0]);
- };
- } else {
- showNotification("加载失败")
- }
- });
- }, [])
-
-
- useEffect(() => {
- projectsId && checkItem.sub_url && getWiki({
- owner: owner,
- repo: projectsId,
- pageName: checkItem.sub_url,
- projectId: projectId,
- }).then(res => {
- if (res && res.message === "200") {
- setItemDetail(res.data);
- } else {
- showNotification("加载失败")
- }
- });
- }, [checkItem]);
-
- function goBack() {
- history.push(`/${owner}/${projectsId}/wiki`);
- }
-
- // 支持 Markdown,Html,Pdf格式文件
- const menu = (
-
- );
-
- function downloadWiki(type) {
- window.open(`${httpUrl}/api/wikiExport/wikiExport-wrapper?repoName=${projectsId}&owner=${owner}&type=${type}&projectName=${projectName}&projectId=${projectId}`);
- }
-
- function renderTreeNodes(data) {
- return data && data.length > 0 && data.map((item) => {
- let title = item.title.trim();
- const isFile = title.startsWith('[[') && title.endsWith(']]');
- title = isFile ? title.substring(2,title.length-2) : title.substring(2, title.length);
- return (
-
- {renderTreeNodes(item.children)}
-
- );
- });
- }
-
- function selectTree(keys,event){
- let {isFile, key, titleStr} = event.node.props.dataRef;
- if(isFile){
- const wiki = fileArr.filter(item => { return item.name == titleStr })[0];
- setCheckItem({
- ...wiki,
- key
- })
- }
- }
-
- return (
-
-
-
-
- {projectName}
-
-
- 克隆地址
- {
- fileArr.length && fileArr[0].wiki_clone_link ?
-
-
-
- : ''
- }
-
-
-
-
-
-
-
-
-
-
- {/* {
- fileArr.map(item => {
- return
{ setCheckItem(item) }}>
-
-
- {item.name}
-
-
- })
- } */}
- {/* 读sidebar转换成目录树 */}
- {fileList && fileList.length ?
- {renderTreeNodes(fileList)}
- : ''}
-
-
-
-
-
{checkItem.name}
-
-
- {itemDetail && itemDetail.md_content &&
}
-
-
-
-
-
- )
-}
\ No newline at end of file
diff --git a/src/forge/Wiki/Welcome/index.css b/src/forge/Wiki/Welcome/index.css
deleted file mode 100644
index d146549c8..000000000
--- a/src/forge/Wiki/Welcome/index.css
+++ /dev/null
@@ -1,51 +0,0 @@
-.welcome-main {
- display: flex;
- flex-flow: column nowrap;
- justify-content: center;
- align-items: center;
- width: 1200px;
- min-height: 400px;
- padding: 20px;
- margin: 20px auto;
- background: #fafcff;
- font-family: "PingFangSC-Medium";
- border-radius: 4px;
- border: 1px solid rgba(42, 97, 255, 0.23);
-}
-.welcome-main .icon-huanying_icon {
- font-size: 48px !important;
- font-weight: 700;
-}
-.welcome-main .welcome-title {
- display: inline-flex;
- align-items: center;
- margin: 10px 0;
- font-size: 26px;
- color: #333333;
- font-weight: 500;
-}
-.welcome-main .wiki-title {
- display: inline-block;
- max-width: 20em;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-.welcome-main .welcome-content {
- font-size: 14px;
- color: #333333;
- font-weight: 400;
-}
-.welcome-main .wiki-line {
- margin: 50px 0 40px;
- width: 400px;
- height: 1px;
- background: #eeeeee;
-}
-.welcome-main .welcome-des {
- font-size: 16px;
- color: #333333;
- font-weight: 500;
-}
-
-/*# sourceMappingURL=index.css.map */
diff --git a/src/forge/Wiki/Welcome/index.jsx b/src/forge/Wiki/Welcome/index.jsx
deleted file mode 100644
index a83adb269..000000000
--- a/src/forge/Wiki/Welcome/index.jsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from 'react';
-import { Button } from 'antd';
-// import { addWiki } from '../api';
-import './index.scss';
-import UploadWiki from '../components/uploadWiki';
-
-export default (props) => {
- const { project, isManager, history, showNotification, match, reloadList } = props;
-
- let projectsId = match.params.projectsId;
- let owner = match.params.owner;
-
- function addFile() {
- history.push(`/${owner}/${projectsId}/wiki/add`);
- }
-
- return (
-
-
-
欢迎使用
-
- {project && project.name}
-
- Wiki
-
Wiki主要是您项目的产品设计、文档描述、注释等等
-
-
- {
- isManager ?
-
-
-
:
该项目暂时没有创建Wiki
- }
-
- )
-}
\ No newline at end of file
diff --git a/src/forge/Wiki/Welcome/index.scss b/src/forge/Wiki/Welcome/index.scss
deleted file mode 100644
index 2250db0df..000000000
--- a/src/forge/Wiki/Welcome/index.scss
+++ /dev/null
@@ -1,59 +0,0 @@
-.welcome-main {
- display: flex;
- flex-flow: column nowrap;
- justify-content: center;
- align-items: center;
- width: 1200px;
- min-height: 400px;
- padding: 20px;
- margin: 20px auto;
- background: rgba(250, 252, 255, 1);
- font-family: "PingFangSC-Medium";
- border-radius: 4px;
- border: 1px solid rgba(42, 97, 255, 0.23);
-
- .icon-huanying_icon {
- font-size: 48px !important;
- font-weight: 700;
- }
-
- .welcome-title {
- display: inline-flex;
- align-items: center;
- margin: 10px 0;
- font-size: 26px;
- color: #333333;
- font-weight: 500;
- }
-
- .wiki-title {
- display: inline-block;
- max-width: 20em;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
- .welcome-content {
- font-size: 14px;
- color: #333333;
- font-weight: 400;
- }
-
- .wiki-line {
- margin: 50px 0 40px;
- width: 400px;
- height: 1px;
- background: #eeeeee;
- }
-
- .welcome-des {
- font-size: 16px;
- color: #333333;
- font-weight: 500;
- }
- .welcomeUploadBtn{
- color: $primary-color;
- border-color: $primary-color;
- }
-}
diff --git a/src/forge/Wiki/api.js b/src/forge/Wiki/api.js
index 301d096cf..ff83ed70e 100644
--- a/src/forge/Wiki/api.js
+++ b/src/forge/Wiki/api.js
@@ -1,10 +1,10 @@
import { Base64 } from 'js-base64';
-import fetch from './fetch';
+import fetch, {httpUrl} from './fetch';
// 获取wiki列表
-export function wikiPages(params) {
+export function getWikiPages(params) {
return fetch({
- url: '/api/wiki/wikiPages',
+ url: '/api/wiki/open/wikiPages',
method: 'get',
params
});
@@ -13,25 +13,31 @@ export function wikiPages(params) {
// 获取单个wiki
export function getWiki(params) {
return fetch({
- url: '/api/wiki/getWiki',
+ url: '/api/wiki/open/getWiki',
method: 'get',
params
});
}
//新增wiki
-export function addWiki(data) {
+export function addWiki(repoInfo, title, content){
return fetch({
- url: '/api/wiki/createWiki',
+ url: '/api/wiki/open/createWiki',
method: 'post',
- data: data
+ data: {
+ ...repoInfo,
+ pageName: title,
+ title: title,
+ message: '',
+ content_base64: Base64.encode(content)
+ }
});
}
//更新wiki
export function updateWiki(data) {
return fetch({
- url: '/api/wiki/updateWiki',
+ url: '/api/wiki/open/updateWiki',
method: 'PUT',
data: data
});
@@ -40,103 +46,133 @@ export function updateWiki(data) {
//删除wiki
export function deleteWiki(data) {
return fetch({
- url: '/api/wiki/deleteWiki',
+ url: '/api/wiki/open/deleteWiki',
method: 'DELETE',
data,
});
}
-// 初始化sidebar文件
-export async function parseSidebar(wikiList, info){
- const sidebarArr = wikiList.filter(item => item.name === '_Sidebar');
- let ReInfo = undefined;
- if(sidebarArr.length){
- // 有sidebar文件,执行解析
- // 通过getWiki获取sidebar文件内容
- await getWiki({
- ...info,
- pageName: '_Sidebar'
- }).then(res=>{
- if(res && res.message === "200"){
- const sidebarCont = Base64.decode(res.data.md_content);
- const list = wikiList.filter(item=> sidebarCont.indexOf(`[[${item.name}]]`) === -1 && item.name !== "_Sidebar");
- const wikiSidebar = list.map(item=>`\n[[${item.name}]]`).join("");
- if(list.length){
- // sidebar存在丢失的wiki
- updateWiki({
- ...info,
- pageName: '_Sidebar',
- title: '_Sidebar',
- message: '',
- content_base64: Base64.encode(`${sidebarCont}${wikiSidebar}`)
- })
- }
- ReInfo={
- menuList: markdownToTree(list.length ? `${sidebarCont}${wikiSidebar}` : sidebarCont, wikiList),
- sidebar: sidebarCont
- }
- }
- })
- }else{
- // 如果没有wiki目录,那么不处理
- if(!wikiList.length){
- return
- }
- // 没有sidebar文件,根据用户的目录结构进行初始化(\n[[item.name]]结构)
- const wikiArr = [];
- wikiList.map(item=>{
- wikiArr.push(`[[${item.name}]]`)
- });
- const wikiSidebarStr = wikiArr.join('\n');
- await addWiki({
- ...info,
+// 导出wiki
+export function exportWiki(params){
+ return `${httpUrl}/api/wiki/open/wikiExport-wrapper${params}`;
+}
+
+// 修改sidebar文件
+export function updateSidebar(repoInfo, sidebarContent){
+ return updateWiki({
+ ...repoInfo,
+ pageName: '_Sidebar',
+ title: '_Sidebar',
+ message: '',
+ content_base64: Base64.encode(sidebarContent)
+ })
+}
+
+// 检查有wiki但是sidebar没有目录的情况
+function updateSidebarByCheckWikiInSidebar(repoInfo, wikiList, sidebar){
+ const list = wikiList.filter(item=> sidebar.indexOf(`[[${item.title}]]`) === -1 && item.title !== "_Sidebar");
+ const wikiSidebar = list.map(item=>`\n[[${item.title}]]`).join("");
+ if(list.length){
+ // sidebar存在丢失的wiki
+ updateWiki({
+ ...repoInfo,
pageName: '_Sidebar',
title: '_Sidebar',
message: '',
- content_base64: Base64.encode(wikiSidebarStr)
+ content_base64: Base64.encode(`${sidebar}${wikiSidebar}`)
})
- ReInfo={
- menuList: markdownToTree(wikiSidebarStr, wikiList),
- sidebar: wikiSidebarStr
- }
}
- return ReInfo;
+ return list.length ? `${sidebar}${wikiSidebar}` : sidebar
}
-export function markdownToTree(markdownText, wikiList){
- const lines = markdownText.split('\n');
+export async function getMenuListAndSidebarData(repoInfo){
+ // deleteWiki({...repoInfo, pageName: "_Sidebar"})
+ // return
+ async function getWikis(){
+ await getWikiPages(repoInfo).then(res=>{
+ if(res && res.code === 200){
+ info.wikiPages = res.data
+ }
+ })
+ }
+ const info = {
+ wikiPages: [],
+ menuList: [],
+ sidebar: ''
+ };
+ await getWikis();
+ const {wikiPages} = info;
+ if(!wikiPages.length){
+ // 未创建过wiki
+ return info;
+ }
+ const sidebarIndex = wikiPages.findIndex(item=>item.title === "_Sidebar");
+ // 判断有无sidebar文件,有转化sidebar内容为目录树,没有则根据pages创建平级关系的sidebar
+ if(sidebarIndex > -1){
+ // 转化sidebar内容为目录树
+ await getWiki({
+ ...repoInfo,
+ pageName: '_Sidebar'
+ }).then(res=>{
+ if(res && res.code === 200){
+ const sidebarContent = updateSidebarByCheckWikiInSidebar(repoInfo, wikiPages, Base64.decode(res.data.content_base64));
+ info.menuList = markdownToTree(sidebarContent, wikiPages);
+ info.sidebar = sidebarContent;
+ }
+ })
+ }else{
+ // 没有sidebar文件,根据用户的目录结构进行初始化(\n[[item.title]]结构)
+ const wikiArr = [];
+ wikiPages.map(item=>{
+ wikiArr.push(`[[${item.title}]]`)
+ });
+ const sidebarContent = wikiArr.join('\n');
+ await addWiki(repoInfo, "_Sidebar", sidebarContent)
+ info.menuList = markdownToTree(sidebarContent, wikiPages);
+ info.sidebar = sidebarContent;
+ }
+ return info;
+}
+
+export function markdownToTree(sidebarContent, wikiPages){
+ // 构建{wikiName: wikiName转义得到的地址(java端做了特殊处理,所以不能用encodeURIComponent等方法)}
+ const wikiNameAndSubUrl = {}
+ wikiPages && wikiPages.map(item=>{
+ return wikiNameAndSubUrl[item.title] = item.sub_url
+ })
+
+ const lines = sidebarContent.split('\n');
let key = -1;
- // stack: [{一级目录},{二级目录}]
- let stack = [];
+ let stack = []; // stack: [{一级目录},{二级目录}]
+
let root = {
title: "root",
children: [],
key: key++
}
- const wikiNameAndSubUrl = {}
- wikiList && wikiList.map(item=>{
- return wikiNameAndSubUrl[item.name] = item.sub_url
- })
+
lines.map((item, index) =>{
const title = item.trim();
const isFile = title.startsWith('[[') && title.endsWith(']]');
const titleStr = isFile ? title.substring(2, title.length - 2) : title.substring(2, title.length)
+ // level:空格的个数(层级)
+ const level = item.search(/\S/);
const node = {
// 带空格+[[]]或者- 标识
title: item,
children: [],
- key: undefined,
+ key: '-1',
// 纯内容
titleStr,
// 编码后的title,获取wiki内容用title_sub
title_sub: wikiNameAndSubUrl[titleStr],
// 是否是wiki文件
- isFile: isFile
+ isFile: isFile,
+ // 层级(空格的个数)
+ level
}
- // level:空格的个数(层级)
- const level = item.search(/\S/);
if(!level){
- node.key = key+"";
+ node["key"] = key+"";
key++;
// push根目录
stack = [];
@@ -155,14 +191,14 @@ export function markdownToTree(markdownText, wikiList){
}else{
// 更深的层级 找key = stack最后一个item的key
const parentNodeByRoot = findNodeByKey(rootNode.children, parentNode.key);
- node.key = `${parentNodeByRoot.key}-${parentNodeByRoot.children.length}`
+ node.key = `${parentNodeByRoot && parentNodeByRoot.key}-${parentNodeByRoot && parentNodeByRoot.children.length}`
parentNodeByRoot && parentNodeByRoot.children.push(node);
}
// 下一个节点的空格个数(层级)
const nextNodeLevel = lines[index+1] && lines[index+1].search(/\S/);
- if(nextNodeLevel>level && (title.startsWith('- ') || title.startsWith('* '))){
+ if(+nextNodeLevel>level && (title.startsWith('- ') || title.startsWith('* '))){
stack.push(node);
- }else if(nextNodeLevel{
+ list.push(item.title)
+ readList(list, item.children)
+ })
+ }
+
+ const list = [];
+ readList(list, menuList)
+ return list.join('\n');
+}
+
+// 检查wiki文件是否重名
+export function findSamaNameWiki(list=[], name){
+ return list && list.find(item=>{return item.title === name})
+}
+
+// 递归menuList, 找到相同key值,push子节点
+export function addChildrenByKey(list, key, name){
+ for (let index = 0; index < list.length; index++) {
+ const element = list[index];
+ if (element.key == key) {
+ const {title} = element;
+ element.children.push({
+ title: `\t${title.substring(0, title.indexOf('- '))}${name}`,
+ children: [],
+ key: '',
+ });
+ return true;
+ }else if (element.children.length) {
+ let result = addChildrenByKey(element.children, key, name);
+ if (result) {
+ return result;
+ }
+ }
+ }
+ return false;
+}
+
+// 遍历目录树,找到第一个wiki / 通过wiki名称找节点
+export function findNodeByFirstOrContrastName(list, name){
+ for (let index = 0; index < list.length; index++) {
+ const element = list[index];
+ if (name ? name === element.titleStr : element.isFile) {
+ return element;
+ }else if (element.children.length) {
+ let result = findNodeByFirstOrContrastName(element.children, name);
+ if (result) {
+ return result;
+ }
+ }
+ }
+}
+
+// 递归menuList, 找到相同key值修改title名称
+// newTitle: [[name]] / - name
+export function editMenuTitleByKey(list, key, newTitle){
+ for (let index = 0; index < list.length; index++) {
+ const element = list[index];
+ if (element.key == key) {
+ element.title = newTitle;
+ return true;
+ }else if (element.children.length) {
+ let result = editMenuTitleByKey(element.children, key, newTitle);
+ if (result) {
+ return result;
+ }
+ }
+ }
+ return false;
+}
+
+// 通过key找节点
export function findNodeByKey(list, key){
for (let index = 0; index < list.length; index++) {
const element = list[index];
@@ -185,7 +296,7 @@ export function findNodeByKey(list, key){
return undefined;
}
-// 找到children中有相同key的数组
+// 遍历目录树, 找到children中有相同key的数组
export function findBrotherNodesByKey(list, key){
for (let index = 0; index < list.length; index++) {
const element = list[index];
@@ -201,75 +312,14 @@ export function findBrotherNodesByKey(list, key){
return [];
}
-// 目录结构转md内容
-export function treeToMd(treeList){
- const list = []
- readList(list, treeList)
- return list.join('\n');
-}
-
-function readList(list, readChildren){
- readChildren.map(item=>{
- list.push(item.title)
- readList(list, item.children)
- })
-}
-
-export function generateList(list) {
- const dataList = [];
- generate(list);
-
- function generate(data){
- for (let i = 0; i < data.length; i++) {
- const node = data[i];
- const { key, titleStr } = node;
- dataList.push({ key, title: titleStr });
- if (node.children) {
- generate(node.children);
- }
- }
- }
-
- return dataList;
-};
-
-export const getParentKey = (key, tree) => {
- let parentKey;
- for (let i = 0; i < tree.length; i++) {
- const node = tree[i];
- if (node.children) {
- if (node.children.some(item => item.key === key)) {
- parentKey = node.key;
- } else if (getParentKey(key, node.children)) {
- parentKey = getParentKey(key, node.children);
- }
- }
- }
- return parentKey;
-};
-
-export function findFirstWiki(list){
- for (let index = 0; index < list.length; index++) {
- const element = list[index];
- if (element.isFile) {
- return element;
- }else if (element.children.length) {
- let result = findFirstWiki(element.children);
- if (result) {
- return result;
- }
- }
- }
-}
-
-// 递归过滤相同key值的节点
-export function deleteSameKey(list, key){
+// 递归menuList, 删除相同key值的节点
+export function findSameKeyByDel(list, key){
return list.filter(item => {
if (item.key === key) {
return false
}
if(item.children && item.children.length > 0){
- item.children = deleteSameKey(item.children , key)
+ item.children = findSameKeyByDel(item.children , key)
}
return true
})
diff --git a/src/forge/Wiki/components/ModalFun/index.scss b/src/forge/Wiki/components/ModalFun/index.scss
index 9f2e95b0e..019294d64 100644
--- a/src/forge/Wiki/components/ModalFun/index.scss
+++ b/src/forge/Wiki/components/ModalFun/index.scss
@@ -16,6 +16,9 @@
.ant-modal-body {
text-align: center;
}
+ .ant-form-explain{
+ text-align: left;
+ }
.content-title {
display: flex;
justify-content: center;
diff --git a/src/forge/Wiki/components/clone.jsx b/src/forge/Wiki/components/clone.jsx
new file mode 100644
index 000000000..c71029f1b
--- /dev/null
+++ b/src/forge/Wiki/components/clone.jsx
@@ -0,0 +1,17 @@
+import React, { useState } from "react";
+import { Input, Select } from "antd";
+import CopyTool from "../../Component/CopyTool";
+const { Option } = Select;
+
+const Clone = (({wikiPages})=>{
+ const [urlType, setUrlType] = useState("HTTPS");
+
+ return !!wikiPages.length && wikiPages[0].wiki_clone_link && { setUrlType(v) }}>
+
+
+
+ } addonAfter={} id="wikiUrl" value={urlType === 'HTTPS' ? wikiPages[0].wiki_clone_link.https : wikiPages[0].wiki_clone_link.ssh}/>
+})
+
+export default Clone
\ No newline at end of file
diff --git a/src/forge/Wiki/components/download.jsx b/src/forge/Wiki/components/download.jsx
new file mode 100644
index 000000000..bc1042ed9
--- /dev/null
+++ b/src/forge/Wiki/components/download.jsx
@@ -0,0 +1,26 @@
+import React from "react";
+import { Button, Dropdown, Icon, Menu } from "antd";
+import { exportWiki } from "../api";
+
+const Download = (({wikiParams, projectName})=>{
+ const downloadType = [
+ {key: 0, label: 'markdown'},
+ {key: 1, label: 'html'},
+ {key: 2, label: 'pdf'}
+ ]
+ const {owner, repo, projectId} = wikiParams;
+
+ return
+ {downloadType.map(item=>{
+ return {
+ window.open(exportWiki(`?repoName=${repo}&owner=${owner}&projectName=${projectName}&projectId=${projectId}&type=${item.label}`));
+ }}>{item.label}
+ })}
+
+ }>
+
+
+})
+
+export default Download
\ No newline at end of file
diff --git a/src/forge/Wiki/components/editMenuModal.jsx b/src/forge/Wiki/components/editMenuModal.jsx
new file mode 100644
index 000000000..a02f011e8
--- /dev/null
+++ b/src/forge/Wiki/components/editMenuModal.jsx
@@ -0,0 +1,179 @@
+import React, { useEffect, useState } from "react";
+import { Input, Modal, Form, Button, message } from "antd";
+import './ModalFun/index.scss'
+import { addChildrenByKey, editMenuTitleByKey, findBrotherNodesByKey, findNodeByKey, findSamaNameWiki, getWiki, treeToMd, updateSidebar, updateWiki } from "../api";
+
+// 新建/编辑弹框
+const EditModal = Form.create()((props) => {
+ const {wikiParams, form: editForm, typeMenuModal, wikiPageInitDetail, cancel, history, reload} = props;
+ const {validateFields, getFieldDecorator} = editForm;
+ // typeMenuModal: 类型 新建子目录/目录 编辑
+ const regex = /^addMenuBy.*$/;
+ const regexEdit = /^editMenu.*$/;
+ const regexEditWiki = /^editWiki.*$/;
+ const title = regex.test(typeMenuModal) ? '新增子' : /^edit.*$/.test(typeMenuModal) ? '编辑' : '新建';
+ const {menuList=[], sidebar="", wikiPages=[]} = wikiPageInitDetail || {};
+ const [initMenu, setInitMenu] = useState();
+ const [wikiContent, setWikiContent] = useState();
+ const [label, setLabel] = useState("目录");
+
+ useEffect(()=>{
+ if(!typeMenuModal || !menuList.length) return
+ // 编辑名称
+ if(/^edit.*$/.test(typeMenuModal)){
+ const key = typeMenuModal.substring(8);
+ const node = findNodeByKey(menuList, key)
+ setLabel(node.isFile ? '页面' : '目录')
+ setInitMenu({
+ title: node.titleStr
+ })
+ editForm.setFieldsValue({
+ name: node.titleStr
+ })
+ if(regexEditWiki.test(typeMenuModal)){
+ setInitMenu({
+ title: node.titleStr,
+ title_sub: node.title_sub
+ })
+ // 获取wiki content
+ getWiki({
+ ...wikiParams,
+ pageName: node.title_sub
+ }).then(res=>{
+ if(res && res.code === 200){
+ setWikiContent(res.data.content_base64);
+ }
+ })
+ }
+ }
+ }, [typeMenuModal, sidebar])
+
+ // 提交表单
+ function submit(e) {
+ e.preventDefault();
+ validateFields(async (err, values) => {
+ if (!err) {
+ const { name } = values;
+ let sidebarContent = undefined;
+ let sameNameMenu = undefined;
+ if (typeMenuModal === "addMenu") {
+ // 新增一级目录:校验一级目录中是否有相同名称
+ sameNameMenu = menuList.find(item => !item.isFile && item.titleStr === name);
+ sidebarContent = `${sidebar}\n- ${name}`
+ } else if (regex.test(typeMenuModal)) {
+ // 新增子目录: 通过key找到节点,遍历节点children,是否有相同名称
+ const key = typeMenuModal.substring(9) || '';
+ const nodeBySameKey = findNodeByKey(menuList, key);
+ sameNameMenu = nodeBySameKey.children.find(item => !item.isFile && item.titleStr === name);
+ addChildrenByKey(menuList, key, `- ${name}`);
+ sidebarContent = treeToMd(menuList)
+ } else if (regexEdit.test(typeMenuModal)) {
+ // 编辑目录名称: 兄弟节点无相同名称
+ const key = typeMenuModal.substring(8) || '';
+ const brotherNodes = findBrotherNodesByKey(menuList, key);
+ sameNameMenu = brotherNodes.find(item => !item.isFile && item.titleStr !== initMenu.title && item.titleStr === name)
+ editMenuTitleByKey(menuList, key, `${'\t'.repeat(key.split('-').length - 1)}- ${name}`);
+ sidebarContent = treeToMd(menuList)
+ } else if (regexEditWiki.test(typeMenuModal)) {
+ // 编辑wiki名称,不允许wiki名称重复,并且还需要修改wiki的标题
+ // findSamaNameWiki: 返回的是个wiki对象
+ sameNameMenu = findSamaNameWiki(wikiPageInitDetail.wikiPages, name);
+ }
+ if (sameNameMenu) {
+ // message.error('不能与已有名称重复');
+ editForm.setFields({name: {value: name, errors:[new Error('不能与已有名称重复')]}});
+ } else {
+ // 编辑wiki成功后再给sidebarContent赋值,修改sidebar
+ if (regexEditWiki.test(typeMenuModal)) {
+ wikiContent && await updateWiki({
+ ...wikiParams,
+ // 原名称
+ pageName: initMenu.title_sub,
+ // 现名称
+ title: name,
+ content_base64: wikiContent,
+ message: '',
+ }).then(res => {
+ if (res && res.code === 200) {
+ const key = typeMenuModal.substring(8) || '';
+ editMenuTitleByKey(menuList, key, `${'\t'.repeat(key.split('-').length - 1)}[[${name}]]`);
+ sidebarContent = treeToMd(menuList)
+ }
+ })
+ }
+ // 编辑sidebar
+ sidebarContent && updateSidebar(wikiParams, sidebarContent).then(resByUpdateSidebar => {
+ if (resByUpdateSidebar && resByUpdateSidebar.code === 200) {
+ message.success(/^add.*$/.test(typeMenuModal) ? "新增成功" : '编辑成功');
+ close();
+ reload();
+ if(regexEditWiki.test(typeMenuModal)){
+ history.push(`/${wikiParams.owner}/${wikiParams.repo}/wiki?wiki=${encodeURIComponent(name)}`)
+ }
+ }
+ })
+ }
+ }
+ })
+ }
+
+ function close(){
+ editForm.resetFields();
+ cancel();
+ }
+
+ return (
+
+
+
+
+
+ {getFieldDecorator('name', {
+ rules: [
+ { required: true, message: `请输入${label}名称` },
+ { pattern: /^(?!-).*$/, message: '不能以-开头' }
+ ],
+ })()}
+
+
+
+
+
+
+
+
+ );
+});
+
+export default EditModal
\ No newline at end of file
diff --git a/src/forge/Wiki/components/treeByWikiSidebar.jsx b/src/forge/Wiki/components/treeByWikiSidebar.jsx
new file mode 100644
index 000000000..b9ccaf69f
--- /dev/null
+++ b/src/forge/Wiki/components/treeByWikiSidebar.jsx
@@ -0,0 +1,402 @@
+import React , { useEffect, useState } from 'react';
+import { ConfigProvider, Divider, Dropdown, Icon, Input, Menu, Modal, Tree, TreeNodeProps, message } from 'antd';
+import { Link } from 'react-router-dom';
+import DelModal from './../components/ModalFun';
+import { deleteWiki, findNodeByFirstOrContrastName, findNodeByKey, findSameKeyByDel, treeToMd, updateSidebar } from '../api';
+const {DirectoryTree, TreeNode} = Tree;
+const Search = Input.Search;
+
+const TreeByWikiSidebar = (props)=>{
+ const {wikiParams, hasPermission, hasSearch=true, wikiPageInitDetail, clickNode, history, setEditMenu, reload} = props;
+ const {sidebar="", wikiPages=[]} = wikiPageInitDetail || {};
+ const searchParams = new URLSearchParams(window.location.search);
+ const wikiBySearch = searchParams.get("wiki") || '';
+
+ const [selectedKey, setSelectedKey] = useState([]);
+ const [expandedKeys, setExpandedKeys] = useState([]);
+ // 搜索
+ const [search, setSearch] = useState();
+ const [menuList, setMenuList] = useState(undefined);
+
+ useEffect(()=>{
+ const menuListByinit = wikiPageInitDetail.menuList || [];
+ if(menuListByinit.length){
+ // 设置选中的节点
+ const node = findNodeByFirstOrContrastName(menuListByinit, wikiBySearch);
+ if(!node) return
+ setSelectedKey([node.key])
+ // 通过分割key设置默认展开的key
+ const keys = expandedKeys;
+ const list = node.key.split('-');
+ list.map((item, index)=>{
+ keys.push(index > 0 ? `${keys[index-1]}-${item}` : item)
+ })
+ setExpandedKeys(Array.from(new Set(keys)));
+ }
+
+ }, [sidebar, wikiBySearch])
+
+ // 搜索
+ useEffect(()=>{
+ if(search && wikiPageInitDetail.menuList.length){
+ const initMenuList = wikiPageInitDetail.menuList
+ // 找到符合条件的子节点, 重新渲染页面
+ let keysMap = findNodesToKeys(initMenuList, search, [], []);
+ const newMenuList = [];
+ let openedKeysMap = [];
+ const oneNodeKeys = new Set();
+ keysMap.map((item, index)=>{
+ const {path=[], isFile, title} = item;
+ // 把所有的一级目录key筛选出来
+ oneNodeKeys.add(path[0]);
+ openedKeysMap = openedKeysMap.concat(path);
+ if(!index && isFile){
+ wikiClick(item)
+ }
+ })
+ Array.from(oneNodeKeys).map(item=>loop(initMenuList, item, (i)=>{
+ newMenuList.push(i);
+ }))
+ const openedKeys = Array.from(new Set(openedKeysMap));
+ setExpandedKeys(openedKeys);
+ setMenuList(newMenuList);
+ }else{
+ setMenuList(undefined)
+ }
+
+ function findNodesToKeys(arr, value, path, nodes) {
+ arr.map(item=>{
+ const {children, key, titleStr=""} = item;
+ if (titleStr.match(new RegExp(value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i'))) {
+ nodes.push({path: path.concat([key]), ...item});
+ } else {
+ findNodesToKeys(children, value, path.concat([key]), nodes);
+ }
+ })
+ return nodes;
+ }
+ }, [search])
+
+ function wikiClick(node){
+ clickNode(node)
+ }
+
+ // 收起展开
+ function onExpand(keys, obj){
+
+ const keySet = new Set(expandedKeys);
+ const {expanded} = obj;
+ let {key} = obj.node.props.dataRef;
+ if(expanded){
+ keySet.add(key);
+ }else{
+ keySet.delete(key);
+ }
+ setExpandedKeys(Array.from(keySet));
+ }
+
+ // 遍历list,找到相同的key callback
+ const loop = (data, key, callback) => {
+ data.forEach((item, index, arr) => {
+ if (item.key === key) {
+ return callback(item, index, arr);
+ }
+ if (item.children) {
+ return loop(item.children, key, callback);
+ }
+ });
+ };
+
+ function splicingTabs(count) {
+ var tabs = "";
+ for (var i = 0; i < count; i++) {
+ tabs += "\t";
+ }
+ return tabs;
+ }
+
+ function onDrop(info){
+
+ // dragNode: 拖拽的节点 node: 放入的节点
+ const dropKey = info.node.props.dataRef.key;
+ const dragKey = info.dragNode.props.dataRef.key;
+ const dropPos = info.node.props.pos.split('-');
+ //0元素之上 1元素之下 -1元素之上
+ const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);
+
+ function upTitle(list, title){
+ const kongGe = title.substring(0, title.indexOf('- ') === -1 ? title.indexOf('[[') : title.indexOf('- '));
+ list.map(item=>{
+ item.title = `\t${kongGe}${item.title.trim()}`;
+ if(item.children){
+ return upTitle(item.children, item.title);
+ }
+ })
+ }
+
+ const data = JSON.parse(JSON.stringify(wikiPageInitDetail.menuList));
+
+ // Find dragObject
+ let dragObj;
+ loop(data, dragKey, (item, index, arr) => {
+ arr.splice(index, 1);
+ dragObj = item;
+ });
+ // 如果拖拽的是目录,那么需要遍历所有的子节点,改变\t个数
+ if(!dragObj.isFile){
+ // 放入的节点标题
+ const title = info.node.props.dataRef.title;
+ const addBool = !info.dropToGap
+ upTitle(dragObj.children, addBool ? `\t${title}` : title);
+ }
+
+ // 是否要保存sidebar文件
+ let bool = false;
+
+ // dropToGap: true拖拽在节点中间 false拖拽到节点之上
+ if (!info.dropToGap) {
+ // 拖拽到节点之上->追加到尾部
+ loop(data, dropKey, (item) => {
+ const {title, key} = item;
+ if(title.indexOf('- ') === -1){
+ message.error('不能拖拽到页面上');
+ return;
+ }
+ const childrenName = item.children.map(item=>item.titleStr);
+ if(childrenName.includes(dragObj.titleStr)){
+ message.error('不能与同级目录名称相同');
+ return;
+ }
+ dragObj.title = `${splicingTabs(key.split('-').length)}${dragObj.title.trim()}`;
+ item.children = item.children || [];
+ item.children.push(dragObj);
+ bool = true;
+ });
+ } else {
+ let ar;
+ let i;
+ loop(data, dropKey, (item, index, arr) => {
+ ar = arr;
+ i = index;
+ });
+ const childrenName = ar.map((item)=>item.titleStr)
+ if(childrenName.includes(dragObj.titleStr)){
+ message.error('不能与同级目录名称相同');
+ return;
+ }
+
+ dragObj.title = `${splicingTabs(ar[i].key.split('-').length-1)}${dragObj.title.trim()}`;
+ if (dropPosition === -1) {
+ ar.splice(i, 0, dragObj);
+ } else {
+ ar.splice(i + 1, 0, dragObj);
+ }
+ bool = true;
+ }
+ if(!bool) return
+ updateSidebar(wikiParams, treeToMd(data)).then(res=>{
+ if(res && res.code === 200){
+ message.success('操作成功')
+ reload && reload();
+ }
+ })
+ }
+
+ // 新增子目录/重命名
+ function menuClick(e, key, typeMenuModal){
+ e.stopPropagation();
+ onExpand([], {expanded: true, node: {props: {dataRef: {key}}}})
+ setEditMenu && setEditMenu(typeMenuModal);
+ }
+
+ // 展开收起全部节点
+ function expandAll(){
+ if(expandedKeys.length > 0){
+ setExpandedKeys([]);
+ return;
+ }
+ const allKeys = [];
+ findMenuKey(allKeys, wikiPageInitDetail.menuList);
+ setExpandedKeys(allKeys);
+
+ function findMenuKey(keys, list){
+ list && list.map(item=>{
+ if(!item.isFile){
+ keys.push(item.key);
+ }
+ if(item && item.children.length){
+ findMenuKey(keys, item.children);
+ }
+ })
+ }
+ }
+
+ // 删除wiki模态框
+ function deleteFileModal(e, item) {
+ const {key, isFile, titleStr, title_sub} = item;
+ e.stopPropagation();
+ DelModal({
+ title: `删除${isFile ? '页面' : '目录'}`,
+ contentTitle: `您确定要删除“${titleStr}”吗?`,
+ content: `此操作将删除此${isFile ? '页面' : '目录'},请进行确认以防文件的丢失`,
+ onOk: () => {
+ if (isFile) {
+ // 删除页面
+ deleteWiki({ ...wikiParams, pageName: title_sub }).then(res => {
+ if (res && res.code === 204) {
+ handle()
+ }
+ });
+ } else {
+ // 删除目录(递归找到所有的[[页面]],遍历删除)
+ if (wikiPageInitDetail && !wikiPageInitDetail.menuList || !key) return
+ // needDelNode: 被删除的子节点
+ const needDelNode = findNodeByKey(wikiPageInitDetail.menuList, key);
+ // needDelWikis:所有需要删除的子目录列表
+ const needDelWikis = [];
+ findDelNode(needDelNode.children || [], needDelWikis);
+ if (needDelWikis.length) {
+ // 有需要删除的子目录
+ const promiseList = []
+ // 删除wiki
+ function deleteWikiFun(pageName){
+ return new Promise((resolve, reject)=>{
+ deleteWiki({ ...wikiParams, pageName: pageName }).then(res => {
+ resolve(res)
+ })
+ })
+ }
+ needDelWikis.map(item => {
+ promiseList.push(deleteWikiFun(item.title_sub))
+ })
+ Promise.all(promiseList).then((values) => {
+ if (values.filter(item => item.code === 204 || item.code === 404).length === needDelWikis.length) {
+ handle()
+ } else {
+ message.error('发生未知错误,请联系系统管理员')
+ }
+ });
+ } else {
+ // 没有需要删除的子目录,直接修改sidebar文件即可
+ handle()
+ }
+ }
+ function handle() {
+ if (wikiPageInitDetail && !wikiPageInitDetail.menuList || !key) return
+ // 递归过滤相同key值的节点,执行删除操作
+ const menuListByDel = findSameKeyByDel(wikiPageInitDetail.menuList, key);
+ const sidebarContent = treeToMd(menuListByDel);
+ if(!sidebarContent){
+ // 删除最后一个wiki的时候,同时删除sidebar
+ deleteWiki({...wikiParams, pageName: "_Sidebar"}).then(res => {
+ if(res && res.code === 204){
+ success();
+ }
+ });
+ return
+ }
+ updateSidebar(wikiParams, sidebarContent).then(res=>{
+ if(res && res.code === 200){
+ success();
+ }
+ });
+
+ }
+ // 删除目录:递归找到需要删除的子目录
+ function findDelNode(list, nodes){
+ //利用foreach循环遍历
+ list.forEach(item => {
+ //判断递归结束条件
+ if (item.isFile) {
+ // 存储数据到空数组
+ nodes.push(item);
+ }
+ if (item.children.length){
+ //递归调用
+ const result = findDelNode(item.children, nodes);
+ if(result) return result
+ }else{
+ return true
+ }
+ })
+ return nodes;
+ }
+
+ function success(){
+ reload && reload();
+ message.success('删除成功');
+ history.push(`/${wikiParams.owner}/${wikiParams.repo}/wiki`);
+ }
+ }
+ });
+ }
+
+ function renderTreeNodes(data) {
+ return data && data.map((item) => {
+ const {titleStr, isFile, key} = item;
+ return (
+
+
+
+ {titleStr}
+
+ {hasPermission &&
+ {!isFile &&
+ 添加子页面
+ }
+ {!isFile &&
+ { menuClick(e, key, `addMenuBy${key}`)}}>
+ 添加子目录
+
+ }
+
+ { menuClick(e, key, isFile ? `editWiki${key}` : `editMenu${key}`) }}>
+ 重命名
+
+
+
+ { deleteFileModal(e, item) }}>删除
+
+
+ } placement="bottomRight">
+
+ }
+ } key={item.key+""} isLeaf={isFile} dataRef={item}>
+ {renderTreeNodes(item.children)}
+
+ );
+ });
+ }
+
+ return
+ {/* draggable={permission} onDrop={onDrop} */}
+ {hasSearch &&
+
+ {setSearch(value)}}
+ />
+
+
{expandedKeys.length > 0 ? '收起' : '展开'}节点
+
}
+
{
+ const {dataRef} = event.node.props;
+ dataRef.isFile && wikiClick(dataRef);
+ }}
+ draggable={hasPermission}
+ onDrop={onDrop}
+ >
+ {renderTreeNodes(menuList || wikiPageInitDetail.menuList)}
+
+
+}
+export default TreeByWikiSidebar
\ No newline at end of file
diff --git a/src/forge/Wiki/components/uploadWiki.jsx b/src/forge/Wiki/components/uploadWiki.jsx
new file mode 100644
index 000000000..e794351c8
--- /dev/null
+++ b/src/forge/Wiki/components/uploadWiki.jsx
@@ -0,0 +1,70 @@
+import React, { useState } from 'react';
+import { Button, Dropdown, Icon, Input, Menu, Tooltip, Select, Upload, message, Spin, Modal } from 'antd';
+import cookie from 'react-cookies';
+import { Base64 } from 'js-base64';
+import { httpUrl, TokenKey } from '../fetch';
+import { findSamaNameWiki, updateSidebar } from '../api';
+
+export default function UploadWiki(props) {
+ const { sidebar, wikiParams, wikiPages=[], refush } = props;
+ const {owner, repo, projectId} = wikiParams;
+
+ const uploadProps = {
+ name: 'multipartFile',
+ withCredentials: true,
+ action: `${httpUrl}/api/wiki/open/uploadWiki/${owner}/${repo}/${projectId}`,
+ accept: ".md, .txt",
+ showUploadList: false,
+ headers: {
+ Authorization: cookie.load(TokenKey),
+ },
+ beforeUpload(file) {
+ const {name} = file;
+ const fileSuffix = name.split('.').pop() || ""
+ const fileName = name.split('.').shift() || ""
+ if (!['md', 'txt', 'markdown'].includes(fileSuffix)) {
+ message.error('只能上传md、txt文件');
+ return false;
+ }
+ if (/^-/.test(file.name)) {
+ message.error('文件名不能以-开头');
+ return false;
+ }
+ if (!(file.size / 1024 / 1024 < 100)) {
+ message.error(`文件大小必须小于${100}MB!`);
+ return false;
+ }
+ const sameNameWiki = findSamaNameWiki(wikiPages, fileName)
+ if(sameNameWiki){
+ message.error('不能上传与已有文件相同文件名的文件');
+ return false
+ }
+ return true
+ },
+ onChange(info) {
+ const {status, response, name} = info.file;
+ const fileName = name.split('.').shift() || "";
+ if(!status || status === "uploading") return
+ if(status === "done" && response && response.code === 201){
+ // 上传成功
+ const sidebarContent = `${sidebar}[[${fileName}]]`
+ updateSidebar(wikiParams, sidebarContent).then(resByUpdateSidebar=>{
+ if(resByUpdateSidebar && resByUpdateSidebar.code === 200){
+ message.success("上传成功")
+ refush();
+ }
+ })
+ return;
+ }
+ message.error(response && response.msg || '文件上传失败')
+ },
+ }
+
+ return
+
+
+
+
+}
\ No newline at end of file
diff --git a/src/forge/Wiki/config.js b/src/forge/Wiki/config.js
new file mode 100644
index 000000000..bbe125f62
--- /dev/null
+++ b/src/forge/Wiki/config.js
@@ -0,0 +1,10 @@
+export const weekModal="| 工作项目 | 本周工作计划 | 本周完成情况 |下周计划 | 待协同事项 |\n| ------------ | ------------ | ------------ | ------------ | ------------ |\n| | | | | |\n| | | | | |\n| | | | | |\n| | | | | |\n\n 备注:";
+export const monthModal="|工作项目 | 工作内容 | 项目进度情况 | 问题列表及解决方案| 下月工作计划 | 遗留未解决的问题 |\n| ------------ | ------------ | ------------ | ------------ | ------------ | ------------ |\n| | | | | | |\n| | | | | | |\n| | | | | | |\n| | | | | | |\n\n 月度总结:";
+
+export const template = [{
+ name: "周报",
+ value: weekModal
+}, {
+ name: "月报",
+ value: monthModal
+}]
\ No newline at end of file
diff --git a/src/forge/Wiki/page/edit.jsx b/src/forge/Wiki/page/edit.jsx
new file mode 100644
index 000000000..c32ba535b
--- /dev/null
+++ b/src/forge/Wiki/page/edit.jsx
@@ -0,0 +1,215 @@
+import React, { useEffect, useState } from "react";
+import { Form, Icon, Input, Button, Spin, message, Radio } from "antd";
+import './index.scss';
+import MdEditor from '../../../modules/tpm/challengesnew/tpm-md-editor';
+import { addChildrenByKey, addWiki, editMenuTitleByKey, findSamaNameWiki, getMenuListAndSidebarData, getWiki, treeToMd, updateSidebar, updateWiki } from "../api";
+import { template } from "../config";
+import DelModal from "../components/ModalFun";
+import { Base64 } from "js-base64";
+
+// 新增/编辑wiki
+export default Form.create()((props) => {
+ const titleByEditType = {
+ "add": "新增",
+ "edit": "编辑",
+ "copy": "复制"
+ }
+ const {form, history, project_id, match:{params:{owner, projectsId: repoIdentifier}}, location:{pathname, search}, projectDetail} = props;
+ const { author: projectAuthor, name: projectName} = projectDetail || {};
+ const searchParams = new URLSearchParams(search);
+ const {getFieldDecorator, validateFields, getFieldValue} = form;
+ const wikiParams = {owner, repo: repoIdentifier, projectId: project_id};
+ let editType = pathname.split("/").pop(); //编辑wiki(addWiki addWikiBy${key} edit)
+
+ const [loading, setLoading] = useState(false);
+ const [wikiPageInitDetail, setWikiPageInitDetail] = useState({})
+ const {menuList=[], sidebar="", wikiPages=[]} = wikiPageInitDetail;
+ const [wikiDetail, setWikiDetail] = useState();
+ const [templateBySelect, setTemplateBySelect] = useState();
+
+ useEffect(()=>{
+ if(!project_id) return
+ // 获取wiki 目录树、sidebar内容
+ getMenuListAndSidebarData(wikiParams).then(res=>{
+ setWikiPageInitDetail(res);
+ })
+ }, [project_id])
+
+ useEffect(()=>{
+ if(editType !== "add" && wikiPages.length){
+ setLoading(true);
+ // 根据wiki名称获取wiki内容
+ const wikiName = searchParams.get("wiki")
+ const sameNameWiki = findSamaNameWiki(wikiPages, wikiName)
+ document.title = `${titleByEditType[editType]}${sameNameWiki.title}-维基-${projectAuthor && projectAuthor.name}/${projectName}`;
+ getWiki({
+ ...wikiParams,
+ pageName: sameNameWiki.sub_url
+ }).then(res=>{
+ if(res && res.code === 200){
+ res.data.content = Base64.decode(res.data.content_base64)
+ setWikiDetail({
+ ...res.data,
+ sub_url: sameNameWiki.sub_url
+ });
+ form.setFieldsValue({
+ title: `${sameNameWiki.title}${editType === "copy" ? "(复制)" : ""}`,
+ md_content: res.data.content
+ })
+ }
+ setLoading(false);
+ })
+ }else{
+ document.title = `${titleByEditType[editType]}-维基-${projectAuthor && projectAuthor.name}/${projectName}`;
+ }
+ }, [editType, sidebar])
+
+ function submit(e){
+ e.preventDefault();
+ validateFields(async (err, values)=>{
+ if(!err){
+ setLoading(true);
+ const {title, md_content} = values;
+ const sameNameWiki = findSamaNameWiki(wikiPages, title)
+ if(editType === "edit"){
+ // 编辑wiki
+ if(sameNameWiki && sameNameWiki.title !== wikiDetail.title){
+ message.error('不能与已有文件标题相同');
+ setLoading(false);
+ return
+ }
+ await updateWiki({
+ ...wikiParams,
+ pageName: wikiDetail.sub_url,
+ title,
+ message: '',
+ content_base64: Base64.encode(md_content)
+ }).then(async res => {
+ if(res && res.code === 200){
+ if(wikiDetail.title === title){
+ // 只修改了wiki内容,重新加载wiki详情即可
+ message.success('修改成功');
+ reload();
+ return
+ }
+ // 修改了wiki标题,需要修改sidebar文件,重新加载目录树、wiki详情
+ const key = searchParams.get("key")
+ editMenuTitleByKey(menuList, key, `${'\t'.repeat(key.split('-').length-1)}[[${title}]]`);
+ updateSidebar(wikiParams, treeToMd(menuList)).then(response=>{
+ if(response && response.code === 200){
+ message.success('修改成功');
+ reload();
+ }
+ })
+ }
+ });
+ }else{
+ // 新增wiki:先新增,再更新sidebar
+ if(sameNameWiki){
+ message.error('不能与已有文件标题相同');
+ setLoading(false);
+ return
+ }
+ await addWiki(wikiParams, title, md_content).then(async res=>{
+ if(res && res.code === 201){
+ // 构建sidebar内容,新增一级页面(/add)、新增子级页面(/add?key=xx)、复制页面(/copy?key=xx)
+ let sidebarContent = "";
+ const key = searchParams.get("key")
+ if((editType === "add" && !key) || (editType === "copy" && !key.includes("-"))){
+ // 新增/复制一级wiki
+ sidebarContent = sidebar ? `${sidebar}\n[[${title}]]` : `[[${title}]]`
+ }else if(editType === "add"){
+ // 新增子级页面, 加到key的子页面
+ addChildrenByKey(menuList, key, `[[${title}]]`)
+ sidebarContent = treeToMd(menuList)
+ }else{
+ // 复制子级页面页面,加到key的同级位置
+ const supKey = key.split("-");
+ supKey.pop();
+ addChildrenByKey(menuList, supKey.join('-'), `[[${title}]]`)
+ sidebarContent = treeToMd(menuList)
+ }
+ // 新增/修改sidebar wiki文件
+ if(!sidebar){
+ // 第一次创建wiki
+ await addWiki(wikiParams,"_Sidebar", sidebarContent)
+ }else{
+ await updateSidebar(wikiParams, sidebarContent)
+ }
+ message.success("新增成功");
+ reload();
+ }
+ });
+ }
+ setLoading(false);
+ function reload(){
+ // 修改路由
+ history.push(`/${owner}/${repoIdentifier}/wiki?wiki=${encodeURIComponent(title)}`)
+ }
+ }
+ })
+ }
+
+ return
+
+
+
+ {getFieldDecorator('title', {
+ rules: [
+ { required: true, message: '请输入页面标题内容!' },
+ { pattern: /^(?!-).*$/, message: '不能以-开头' }
+ ],
+ })()}
+
+
+
+ {getFieldDecorator('md_content', {
+ rules: [{ required: true, message: "请输入wiki内容" }],
+ })()}
+
+
+ 添加模版
+
+ {template.map(item=>{
+ return {
+ DelModal({
+ title: '添加模版',
+ contentTitle: `您确定要添加“${item.name}”模板吗`,
+ content: `此操作会将“${item.name}”模板替换编辑栏内所有内容,请确认以防文件的丢失`,
+ okText: '确认添加',
+ onOk: () => {
+ setTemplateBySelect(item.name);
+ form.setFieldsValue({
+ md_content: item.value
+ })
+ }
+ })
+ }}>{item.name}
+ })}
+
+
+
+
+
+
+
+
+
+})
\ No newline at end of file
diff --git a/src/forge/Wiki/page/index.jsx b/src/forge/Wiki/page/index.jsx
new file mode 100644
index 000000000..7ac799686
--- /dev/null
+++ b/src/forge/Wiki/page/index.jsx
@@ -0,0 +1,146 @@
+import React, { useEffect, useState } from "react";
+import { Button, Divider, Icon, Spin } from "antd";
+import { getImageUrl, timeAgo } from 'educoder';
+import { findNodeByFirstOrContrastName, getMenuListAndSidebarData, getWiki } from "../api";
+import Welcome from './welcome';
+import RenderHtml from "../../../components/render-html";
+import { Link } from "react-router-dom";
+import Sidebar from '../components/treeByWikiSidebar';
+import EditMenu from '../components/editMenuModal';
+import Clone from '../components/clone';
+import { Base64 } from "js-base64";
+import Download from "../components/download";
+import UploadWiki from "../components/uploadWiki";
+import './index.scss';
+
+export default (props) => {
+ const {project_id, match:{params:{owner, projectsId: repoIdentifier}}, projectDetail, history, location} = props;
+ const wikiParams = {owner, repo: repoIdentifier, projectId: project_id};
+ const permission = projectDetail && projectDetail.permission && projectDetail.permission !== "Reporter";
+ const { author: projectAuthor, name: projectName} = projectDetail || {};
+ const search = new URLSearchParams(location.search);
+ const wikiBySearch = search.get("wiki") || '';
+
+ const [spinning, setSpinning] = useState(false);
+ const [reload, setReload] = useState();
+ const [wikiPageInitDetail, setWikiPageInitDetail] = useState({})
+ const {menuList=[], sidebar="", wikiPages=[]} = wikiPageInitDetail;
+ const [selectNodeDetail, setSelectNodeDetail] = useState({});
+ const [loading, setLoading] = useState(false);
+ const [wikiDetail, setWikiDetail] = useState({});
+
+ // 弹框编辑目录
+ const [typeMenuModal, setTypeMenuModal] = useState();
+
+ useEffect(()=>{
+ setSpinning(true);
+ if(!project_id) return
+ setWikiPageInitDetail({})
+ // 获取wiki 目录树、sidebar内容
+ getMenuListAndSidebarData(wikiParams).then(res=>{
+ setSpinning(false);
+ setWikiPageInitDetail(res);
+ })
+ }, [project_id, reload])
+
+ useEffect(()=>{
+ if(!menuList.length) return
+ // 通过路由直接访问
+ let node = findNodeByFirstOrContrastName(menuList, wikiBySearch)
+ // 有可能wikiBySearch是错误的值,导致右侧显示为空
+ if(!node){
+ history.push(`/${owner}/${repoIdentifier}/wiki`)
+ return
+ }
+ setSelectNodeDetail(node);
+ }, [menuList, wikiBySearch])
+
+ useEffect(()=>{
+ document.title = `${selectNodeDetail.titleStr ? `${selectNodeDetail.titleStr}-` : ""}维基-${projectAuthor && projectAuthor.name}/${projectName}`;
+ if(selectNodeDetail.title_sub){
+ setLoading(true);
+ getWiki({
+ ...wikiParams,
+ pageName: selectNodeDetail.title_sub
+ }).then(res=>{
+ if(res && res.code === 200){
+ res.data.content = Base64.decode(res.data.content_base64);
+ setWikiDetail(res.data);
+ }
+ setLoading(false);
+ })
+ }
+ }, [selectNodeDetail.title_sub])
+
+ function refush(){
+ setReload(Math.random())
+ }
+
+ return
+ {/* 空数据页面 */}
+ {!spinning && !wikiPages.length && }
+ {/* wiki首页 */}
+ {!!wikiPages.length &&
+
+
+ {
+ permission ?
+
+
+
+
: "Wiki文档"
+ }
+
+
+ {
+ permission &&
+ }
+
+
+
+
+
+
+
+
+
+
+ {/* 读sidebar转换成目录树 */}
+ {history.push(`/${owner}/${repoIdentifier}/wiki?wiki=${encodeURIComponent(node.titleStr)}`)}} history={history} setEditMenu={setTypeMenuModal} reload={refush}/>
+
+
+
+
+
+
+ {wikiDetail &&
+
+
+
+
{wikiDetail.title}
+
+
+ {wikiDetail.image_url &&
})
}
+ {wikiDetail.userName}
+
+ 上次修改于{wikiDetail.last_commit ? timeAgo(wikiDetail.last_commit.author.date) : '刚刚'}
+
+
+ {permission &&
+
+
+
}
+
+
+
+ {wikiDetail.content_base64 && }
+
+
}
+
+
}
+ {/* 新建/编辑目录名称 */}
+ {setTypeMenuModal(undefined)}} history={history} reload={refush}/>
+
+}
\ No newline at end of file
diff --git a/src/forge/Wiki/page/index.scss b/src/forge/Wiki/page/index.scss
new file mode 100644
index 000000000..b5f9c1272
--- /dev/null
+++ b/src/forge/Wiki/page/index.scss
@@ -0,0 +1,123 @@
+.wiki-main {
+ width: 1200px;
+ min-height: 400px;
+ margin: 20px auto 60px;
+}
+.wiki-head {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 20px;
+ height: 64px;
+ background: #fafcff;
+ box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.13);
+ border-radius: 4px;
+}
+.primaryText{
+ color: $primary-color;
+}
+.welcome-main {
+ text-align: center;
+ background: rgba(250, 252, 255, 1);
+ border-radius: 4px;
+ border: 1px solid rgba(42, 97, 255, 0.23);
+}
+.wiki-home{
+ .wiki-nav-parent {
+ width: 280px;
+ flex: none;
+ }
+}
+
+.wiki-nav {
+ min-height: 500px;
+ background: #ffffff;
+ border: 1px solid rgba(153, 153, 153, 0.22);
+ overflow-y: scroll;
+ flex: none;
+ color: #333;
+ .expendedAllAction{
+ cursor: pointer;
+ text-align: right;
+ padding-right: 15px;
+ color: $primary-color;
+ border-bottom: 1px solid #d0d0d0;
+ }
+ .ant-tree.ant-tree-directory > li.ant-tree-treenode-selected > span.ant-tree-node-content-wrapper::before, .ant-tree.ant-tree-directory .ant-tree-child-tree > li.ant-tree-treenode-selected > span.ant-tree-node-content-wrapper::before{
+ background-color: #F4F6FF;
+ }
+ .ant-tree.ant-tree-directory > li span.ant-tree-node-content-wrapper.ant-tree-node-selected, .ant-tree.ant-tree-directory .ant-tree-child-tree > li span.ant-tree-node-content-wrapper.ant-tree-node-selected{
+ color: $primary-color;
+ }
+ .ant-tree.ant-tree-directory > li.ant-tree-treenode-selected > span.ant-tree-switcher, .ant-tree.ant-tree-directory .ant-tree-child-tree > li.ant-tree-treenode-selected > span.ant-tree-switcher{
+ color: $primary-color;
+ }
+}
+.wikiSidebar{
+ // .ant-tree li span.ant-tree-switcher{
+ // display: none;
+ // }
+ .nodeBox{
+ display: flex;
+ align-items: flex-end;
+ justify-content: space-between;
+ padding-top: 2px;
+ .action {
+ display: none;
+ }
+ &:hover .action, .action.ant-dropdown-open{
+ display: block;
+ }
+ }
+ .sidebarByWiki{
+ .ant-tree-node-content-wrapper {
+ overflow: hidden;
+ }
+ }
+
+}
+
+.wiki-body {
+ display: flex;
+ .wiki-content {
+ flex: 1;
+ width: 0;
+ }
+ .commit-user-avator {
+ width: 1.5rem;
+ height: 1.5rem;
+ margin-right: 0.35rem;
+ border-radius: 50%;
+ }
+}
+
+.wiki-preview {
+ overflow-y: scroll;
+ height: 100%;
+ .previewWiki{
+ overflow-y: auto;
+ width: 20vw;
+ }
+ .wiki-nav {
+ min-height: 92vh;
+ border: none;
+ border-right: 1px solid rgba(153, 153, 153, 0.22);
+ }
+ .preview-head {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 12rem 0 2rem;
+ width: 100%;
+ height: 8vh;
+ background: rgb(39, 47, 76);
+ color: #fff;
+ }
+
+ .preview-head-right {
+ display: flex;
+ .copy-desc {
+ flex:none
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/forge/Wiki/page/preview.jsx b/src/forge/Wiki/page/preview.jsx
new file mode 100644
index 000000000..ef859e248
--- /dev/null
+++ b/src/forge/Wiki/page/preview.jsx
@@ -0,0 +1,99 @@
+import React, { useEffect, useState } from 'react';
+import { Link } from 'react-router-dom';
+import { Base64 } from 'js-base64';
+import { Divider } from 'antd';
+import { getWiki, getMenuListAndSidebarData, findNodeByFirstOrContrastName, } from '../api';
+import RenderHtml from '../../../components/render-html';
+import TreeByWikiSidebar from '../components/treeByWikiSidebar';
+import Clone from '../components/clone';
+import Download from '../components/download';
+import './index.scss';
+
+export default (props) => {
+ const { match: {params: {owner, proIdentity, projectId}}, history, showNotification, location } = props;
+ const wikiParams = {owner, repo: proIdentity, projectId: projectId};
+ const search = new URLSearchParams(location.search);
+ const projectName = search.get("name") || '';
+ const wikiBySearch = search.get("wiki") || '';
+
+ const [wikiPageInitDetail, setWikiPageInitDetail] = useState({})
+ const [checkItem, setCheckItem] = useState({});
+ const [itemDetail, setItemDetail] = useState({});
+
+ const {wikiPages=[], menuList=[]} = wikiPageInitDetail;
+
+ useEffect(()=>{
+ if(checkItem && checkItem.name){
+ document.title = `${checkItem.name}-维基预览`
+ }
+ }, [checkItem])
+
+
+ useEffect(()=>{
+ // 获取wiki 目录树、sidebar内容
+ getMenuListAndSidebarData(wikiParams).then(res=>{
+ setWikiPageInitDetail(res);
+ })
+ }, [])
+
+ useEffect(()=>{
+ if(!menuList.length) return
+ // 通过路由直接访问
+ let node = findNodeByFirstOrContrastName(menuList, wikiBySearch)
+ // 有可能wikiBySearch是错误的值,导致右侧显示为空
+ if(!node){
+ search.delete('wiki');
+ history.push(`${window.location.pathname}?${search.toString()}`)
+ return
+ }
+ setCheckItem(node);
+ }, [menuList, wikiBySearch])
+
+ useEffect(() => {
+ document.title = `${checkItem && checkItem.titleStr}-维基预览`
+ checkItem.title_sub && getWiki({
+ ...wikiParams,
+ pageName: checkItem.title_sub
+ }).then(res => {
+ if(res && res.code === 200){
+ setItemDetail(res.data);
+ } else {
+ showNotification("加载失败")
+ }
+ });
+ }, [checkItem]);
+
+ return (
+
+
+
+
+
{projectName}
+
+
+
+
+
+
+
+ {/* 读sidebar转换成目录树 */}
+ {
+ history.push(`${location.pathname}?name=${projectName}&wiki=${encodeURIComponent(node.titleStr)}`)
+ }}/>
+
+
+
+
{checkItem.titleStr}
+
+ {itemDetail && itemDetail.content_base64 &&
}
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/forge/Wiki/page/welcome.jsx b/src/forge/Wiki/page/welcome.jsx
new file mode 100644
index 000000000..8d0d2ce68
--- /dev/null
+++ b/src/forge/Wiki/page/welcome.jsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import { Button, Divider } from 'antd';
+import UploadWiki from '../components/uploadWiki';
+import './index.scss';
+
+export default (props) => {
+ const { project, isManager, match: {params: {projectsId, owner}}, refush, wikiParams} = props;
+
+ return (
+
+
+
欢迎使用
+
+ {project && project.name}
+
+ Wiki
+
Wiki主要是您项目的产品设计、文档描述、注释等等
+
+ {
+ isManager ?
+
+
+
:
该项目暂时没有创建Wiki
+ }
+
+ )
+}
\ No newline at end of file
diff --git a/src/forge/Wiki/utils.js b/src/forge/Wiki/utils.js
deleted file mode 100644
index 8eede2e38..000000000
--- a/src/forge/Wiki/utils.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// 拼接\t
-export function splicingTabs(count) {
- var tabs = "";
- for (var i = 0; i < count; i++) {
- tabs += "\t";
- }
- return tabs;
-}
-
-// 输入:'2-2-2-1' 返回:['2', '2-2', '2-2-2', '2-2-2-1']
-export function splitAndCombine(str) {
- if(!str) return []
- var parts = str.split('-');
- var result = parts.reduce(function(acc, curr) {
- if (acc.length === 0) {
- acc.push(curr);
- } else {
- var lastItem = acc[acc.length - 1];
- acc.push(lastItem + '-' + curr);
- }
- return acc;
- }, []);
- return result;
-}
\ No newline at end of file
diff --git a/src/forge/users/Index.jsx b/src/forge/users/Index.jsx
index bdd2db132..c031ba1e8 100644
--- a/src/forge/users/Index.jsx
+++ b/src/forge/users/Index.jsx
@@ -6,7 +6,7 @@ import { withRouter } from "react-router";
import { SnackbarHOC } from "educoder";
import { CNotificationHOC } from "../../modules/courses/common/CNotificationHOC";
import { TPMIndexHOC } from "../../modules/tpm/TPMIndexHOC";
-import ProjectDetail from '../Main/Detail'
+import ProjectDetail from '../Main/Detail';
const Infos = Loadable({
loader: () => import("./Infos"),
@@ -26,7 +26,7 @@ class DetailTop extends Component {
getProject = (num) => {
const { projectsId, owner } = this.props.match.params;
- const url = `https://www.gitlink.org.cn/${owner}/${projectsId}/simple.json`;
+ const url = `/${owner}/${projectsId}/simple.json`;
axios.get(url).then((result) => {
if (result && result.data) {
this.setState({
diff --git a/src/forge/users/Material/Index.jsx b/src/forge/users/Material/Index.jsx
index c15036842..edd9066ee 100644
--- a/src/forge/users/Material/Index.jsx
+++ b/src/forge/users/Material/Index.jsx
@@ -21,10 +21,6 @@ function Index(props){
}else{
setKey("1");
switch(pathname){
- case '/settings/phone':
- documentTitle = "手机号管理";
- setType('3');
- break;
case '/settings/emails':
setType('0');
documentTitle = "邮箱管理";
@@ -37,9 +33,12 @@ function Index(props){
setType('4');
documentTitle = "实名认证";
break;
- default:
- setType('2');
- documentTitle = "账号注销";
+ default:// '/settings/phone'
+ documentTitle = "手机号管理";
+ setType('3');
+ // default:
+ // setType('2');
+ // documentTitle = "账号注销";
}
}
document.title = documentTitle;
@@ -56,7 +55,7 @@ function Index(props){
{props.history.push('/settings/emails')}}>邮箱管理
{props.history.push('/settings/password')}}>密码管理
{props.history.push('/settings/verification')}}>实名认证
- {props.history.push('/settings/cancel')}}>账号注销
+ {/* {props.history.push('/settings/cancel')}}>账号注销 */}
}
diff --git a/src/forge/users/Material/Password.jsx b/src/forge/users/Material/Password.jsx
index c2dda19c4..c33bb5311 100644
--- a/src/forge/users/Material/Password.jsx
+++ b/src/forge/users/Material/Password.jsx
@@ -331,19 +331,20 @@ export default Form.create()(
- : type === '2' ?
-
-

请您谨慎操作,注销后帐号内所有数据都会被清空,且无法恢复帐号!
-
- GitLink目前提供邮件渠道帐号注销服务。如需注销帐号,请通过发送邮件注销申请邮件到 gitlink@ccf.org.cn。
- 相关注意事项如下:
- 必须使用要注销的 GitLink 帐号所绑定的邮箱地址发送邮件。
- 发送注销申请邮件之前确认帐号下无创建/加入组织,帐号名下无仓库信息。
- 邮件标题: 注销 GitLink 帐号,邮件正文请注明要注销帐号的邮箱和昵称。
- 发送邮件后,我们会积极处理,请耐心等候我们的邮件回复。
-
-
- :
+ :
+ // type === '2' ?
+ //
+ //

请您谨慎操作,注销后帐号内所有数据都会被清空,且无法恢复帐号!
+ //
+ // GitLink目前提供邮件渠道帐号注销服务。如需注销帐号,请通过发送邮件注销申请邮件到 gitlink@ccf.org.cn。
+ // 相关注意事项如下:
+ // 必须使用要注销的 GitLink 帐号所绑定的邮箱地址发送邮件。
+ // 发送注销申请邮件之前确认帐号下无创建/加入组织,帐号名下无仓库信息。
+ // 邮件标题: 注销 GitLink 帐号,邮件正文请注明要注销帐号的邮箱和昵称。
+ // 发送邮件后,我们会积极处理,请耐心等候我们的邮件回复。
+ //
+ //
:
+
}
5 && Axios.post(`/v1/${current_user.login}/check_phone_verify_code.json`,{
- code_type: 4,
- phone: phoneValue,
- code: value
- }).then(res=>{
- if(res && !res.data.status){
- map.mescode = value;
- setPassMap(map);
- callback();
- }else{
- map.mescode = undefined;
- setPassMap(map);
- callback(res.data.message);
- }
- })
- }else{
- map.mescode = undefined;
- setPassMap(map);
- callback();
- }
- }
+ // function checkCode(rule, value, callback){
+ // const map = passMap;
+ // const {phone, logpassword} = getFieldsValue();
+ // if(!phone){
+ // callback("请先输入手机号");
+ // }
+ // if(!logpassword){
+ // callback("请先输入登录密码");
+ // }
+ // if(value){
+ // current_user && value && value.length > 5 && Axios.post(`/v1/${current_user.login}/check_phone_verify_code.json`,{
+ // code_type: 4,
+ // phone: phoneValue,
+ // code: value
+ // }).then(res=>{
+ // if(res && !res.data.status){
+ // map.mescode = value;
+ // setPassMap(map);
+ // callback();
+ // }else{
+ // map.mescode = undefined;
+ // setPassMap(map);
+ // callback(res.data.message);
+ // }
+ // })
+ // }else{
+ // map.mescode = undefined;
+ // setPassMap(map);
+ // callback();
+ // }
+ // }
// 校验用户手机号是否正确
function checkPhone(rule, value, callback){
const map = passMap;
@@ -144,10 +144,10 @@ export default Form.create()(
}
function updateEmailOrPsd(){
- const {mescode, phone, logpassword} = getFieldsValue();
- if(mescode && phone && logpassword){
+ const { phone, logpassword} = getFieldsValue();
+ if( phone && logpassword){
current_user && Axios.patch(`/v1/${current_user.login}/update_phone.json`,{
- code:mescode, phone, password:logpassword
+ phone, password:logpassword
}).then(res=>{
if(res && !res.data.status){
setPassMap({logpassword: undefined, phone: undefined, code: undefined});
@@ -208,7 +208,7 @@ export default Form.create()(
)}
-
+ {/*
{getFieldDecorator("mescode",{
rules:[
@@ -221,10 +221,10 @@ export default Form.create()(
)}
{countDown ? : }
-
+
*/}
-
+
diff --git a/src/home/Img/com-1.png b/src/home/Img/com-1.png
new file mode 100644
index 000000000..53dad32ae
Binary files /dev/null and b/src/home/Img/com-1.png differ
diff --git a/src/home/Img/com-2.png b/src/home/Img/com-2.png
new file mode 100644
index 000000000..bef3734fa
Binary files /dev/null and b/src/home/Img/com-2.png differ
diff --git a/src/home/Img/com-3.png b/src/home/Img/com-3.png
new file mode 100644
index 000000000..e96968745
Binary files /dev/null and b/src/home/Img/com-3.png differ
diff --git a/src/home/Img/com-back.png b/src/home/Img/com-back.png
new file mode 100644
index 000000000..33775c206
Binary files /dev/null and b/src/home/Img/com-back.png differ
diff --git a/src/home/Img/xing-threeEdition.png b/src/home/Img/xing-threeEdition.png
new file mode 100644
index 000000000..cef261418
Binary files /dev/null and b/src/home/Img/xing-threeEdition.png differ
diff --git a/src/home/Index.jsx b/src/home/Index.jsx
index 06393aa2d..7b2672657 100644
--- a/src/home/Index.jsx
+++ b/src/home/Index.jsx
@@ -1,7 +1,8 @@
import React , { useEffect , useState } from 'react';
import "./Index.scss";
import TopEdition from './TopEdition';
-import ThirdEdition from './ThirdEdition';
+// import ThirdEdition from './ThirdEdition';
+import ThirdeditionXing from './ThirdEditionXing';
import { Anchor } from 'antd';
import F41 from './Img/4-1.png';
import F42 from './Img/4-2.png';
@@ -10,7 +11,6 @@ import F44 from './Img/4-4.png';
import SecondEdition from './SecondEdition';
import FifthEdition from './FifthEdition';
import { TPMIndexHOC } from '../modules/tpm/TPMIndexHOC';
-import Axios from 'axios';
function Index(props) {
const [ value , setValue ] = useState("");
@@ -18,12 +18,12 @@ function Index(props) {
const [ bannerTab , setBannerTab ] = useState(undefined);
const register = props && props.mygetHelmetapi && props.mygetHelmetapi.common && props.mygetHelmetapi.common.register;
- const name = props && props.mygetHelmetapi && props.mygetHelmetapi.name ;
+ const name = props && props.mygetHelmetapi && props.mygetHelmetapi.name;
const { current_user } = props;
useEffect(()=>{
window.addEventListener("scroll",scrollListener);
- getTab();
+ // getTab();
return ComponentWillUnmount;
},[])
@@ -35,18 +35,18 @@ function Index(props) {
window.removeEventListener("scroll",scrollListener);
}
- function getTab() {
- const url = `/topics.json?topic_type=card`;
- Axios.get(url,{
- params:{
- limit:3
- }
- }).then(result=>{
- if(result){
- setBannerTab(result.data.topics);
- }
- }).catch(error=>{})
- }
+ // function getTab() {
+ // const url = `/topics.json?topic_type=card`;
+ // Axios.get(url,{
+ // params:{
+ // limit:3
+ // }
+ // }).then(result=>{
+ // if(result){
+ // setBannerTab(result.data.topics);
+ // }
+ // }).catch(error=>{})
+ // }
function scrollListener(event) {
@@ -93,47 +93,32 @@ function Index(props) {
}
:
-
+ ""
}
-
GitLink,新一代开源创新服务平台
+
星云协同开发平台
{
flag &&
changeActive("#hadoop")} className={value === "#hadoop"?"active":""}>分布式协作开发
changeActive("#oneStop")} className={value === "#oneStop"?"active":""}>一站式过程管理
changeActive("#highDevops")} className={value === "#highDevops"?"active":""}>高效流水线运维
- changeActive("#multipleAnalyse")} className={value === "#multipleAnalyse"?"active":""}>多层次代码分析
+ {/* changeActive("#multipleAnalyse")} className={value === "#multipleAnalyse"?"active":""}>多层次代码分析 */}
changeActive("#multidimensional")} className={value === "#multidimensional"?"active":""}>多维度用户画像
}
-
+ {/* */}
+
-
加入GitLink,和社区伙伴们一起踏上开源创新的辉煌旅程!
+
加入星云协同开发平台,和社区伙伴们一起踏上开源创新的辉煌旅程!
{ !(current_user && current_user.login) &&
立即注册 }
@@ -161,11 +146,11 @@ function Index(props) {
-
+ {/*
开源生态
GitLink与各大企业、高校、科研机构开展广泛的技术合作,推动我国开源软件生态的快速构建与发展
-
+
*/}
)
}
diff --git a/src/home/Index.scss b/src/home/Index.scss
index 399c2394c..476e81f02 100644
--- a/src/home/Index.scss
+++ b/src/home/Index.scss
@@ -1,4 +1,3 @@
-
body{
overflow: auto!important;
background-color: #fff!important;
@@ -9,7 +8,7 @@ body{
.topEdition{
position: relative;
background-image: linear-gradient(to right,#081843,#000A1D);
- margin-bottom: 159px;
+ margin-bottom: 70px;
.headNav{
position: absolute;
width: 100%;
@@ -54,7 +53,7 @@ body{
}
}
.slick-track{
- height: 679px;
+ height: 560px;
display: flex;
.slick-slide{
position: relative;
@@ -659,7 +658,7 @@ body{
flex-direction: column;
align-items: center;
justify-content: center;
- .titleInHome{
+ .title{
height: 53px;
font-size: 38px;
font-weight: 500;
@@ -812,13 +811,8 @@ body{
text-decoration: underline;
}
}
- span.listboxcount{
- margin-left: 20px;
- }
- span.listboxtime{
+ span{
margin-left: 40px;
- width: 97px;
- text-align: right;
}
.listboxcount{
min-width: 60px;
@@ -1115,4 +1109,72 @@ body{
a{
color: #BDC2D1!important;
}
+}
+.xingEdition{
+ background-image: url('./Img/xing-threeEdition.png');
+ background-size: 100% 100%;
+ position: relative;
+ padding-top: 56px;
+ .theTitle{
+ font-size: 34px;
+ font-weight: 500;
+ margin:0px auto;
+ text-align: center;
+ position: absolute;
+ width: 100%;
+ top:79px;
+ }
+ .xingBanner{
+ width: 965px;
+ height: 708px;
+ background-image: url('./Img/com-back.png');
+ background-size: 100% 100%;
+ margin:0px auto;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ .slick-dots{
+ position: absolute;
+ bottom: 70px;
+ display: flex!important;
+ align-items: center;
+ width: 100%;
+ justify-content: center;
+ li{
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ margin:0px 3px;
+ background-color: #eee;
+ button{
+ display: none;
+ }
+ &.slick-active{
+ background-color: #466AFF;
+ }
+ }
+ }
+ .slick-list{
+ display: flex;
+ align-items: center;
+ height: 380px;
+ width: 616px;
+ overflow: hidden;
+ margin-top: -35px;
+ border-radius: 10px 10px 0px 0px;
+ .slick-track{
+ display: flex;
+ .regform{
+ position: relative;
+ height: 100%;
+ text-align: center;
+ img{
+ height: 380px;
+ width: 626px;
+ }
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/home/SecondEdition.jsx b/src/home/SecondEdition.jsx
index 7a8061462..a675bd79f 100644
--- a/src/home/SecondEdition.jsx
+++ b/src/home/SecondEdition.jsx
@@ -182,11 +182,11 @@ function SecondEdition({setValue}) {