diff --git a/src/forge/Wiki/Index.jsx b/src/forge/Wiki/Index.jsx index 96772549e..587060276 100644 --- a/src/forge/Wiki/Index.jsx +++ b/src/forge/Wiki/Index.jsx @@ -14,7 +14,6 @@ import { isArray } from 'lodash'; import { Base64 } from 'js-base64'; import Sidebar from './components/sidebar'; import UploadWiki from './components/uploadWiki'; -const Search = Input.Search; const InputGroup = Input.Group; const { Option } = Select; @@ -31,7 +30,6 @@ export default (props) => { const [fileArr, setFileArr] = useState([]); const [fileList, setFileList] = useState([]); - const [fileListInit, setFileListInit] = useState([]); const [reload, setReload] = useState(); const [urlType, setUrlType] = useState('HTTPS'); @@ -76,11 +74,7 @@ export default (props) => { const {menuList, sidebar} = info; setSidebar(sidebar) setFileList(menuList); - setFileListInit(menuList); let firstWikiNode = undefined; - // if(!pathname.endsWith('/wiki')){ - // firstWikiNode = findNodeByKey(menuList, pathname.split('/').pop()) - // } const arr = pathname.split('/'); if(!pathname.endsWith('/wiki')){ firstWikiNode = findNodeByName(menuList, arr[arr.length-2]); @@ -151,15 +145,6 @@ export default (props) => { } } - function changeSearchValue(value) { - if(value){ - // 过滤不包含wiki的内容, 重新渲染页面 - let filterList = filterTree(fileListInit, value); - setFileList(filterList); - }else{ - setFileList(JSON.parse(JSON.stringify(fileListInit))); - } - } function filterTree(list, value, arr = []){ if(!list.length) return [] @@ -173,15 +158,6 @@ export default (props) => { } } return arr - // return list.filter(item => { - // if (item.title.includes(value)) { - // return true - // } - // // if(item.children && item.children.length > 0){ - // // item.children = findUnHasValue(item.children , value); - // return findUnHasValue(item.children , value); - // // } - // }) } @@ -314,15 +290,9 @@ export default (props) => {
- {/* 读sidebar转换成目录树 */} - +
diff --git a/src/forge/Wiki/Index.scss b/src/forge/Wiki/Index.scss index 974bc4f75..e79567d69 100644 --- a/src/forge/Wiki/Index.scss +++ b/src/forge/Wiki/Index.scss @@ -236,6 +236,9 @@ body { .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 { @@ -411,4 +414,11 @@ body { } .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/api.js b/src/forge/Wiki/api.js index 48fc0d907..6b6ee58a1 100644 --- a/src/forge/Wiki/api.js +++ b/src/forge/Wiki/api.js @@ -111,7 +111,6 @@ export function markdownToTree(markdownText){ let root = { title: "root", children: [], - node: undefined, key: key++ } lines.map((item, index) =>{ @@ -119,18 +118,17 @@ export function markdownToTree(markdownText){ const node = { title: item, children: [], - node: undefined, - key: key++ + key: undefined } // level:空格的个数(层级) const level = item.search(/\S/); - // 下一个节点的空格个数(层级) - const nextNodeLevel = lines[index+1] && lines[index+1].search(/\S/); if(!level){ + node.key = key+""; + key++; // push根目录 - stack = [] - root.children.push(node); + stack = []; stack.push(node); + root.children.push(node); }else{ // 解析子目录 // 当前节点的父节点 @@ -139,12 +137,16 @@ export function markdownToTree(markdownText){ const rootNode = root.children.filter(i => i.key === stack[0].key)[0]; if(level === 1){ // 二级目录 + node.key = `${rootNode.key}-${rootNode.children.length}`; rootNode.children.push(node); }else{ // 更深的层级 找key = stack最后一个item的key const parentNodeByRoot = findNodeByKey(rootNode.children, parentNode.key); + node.key = `${parentNodeByRoot.key}-${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('* '))){ stack.push(node); }else if(nextNodeLevel{ - setSelectedKey(defaultSelectedKeys); + if(defaultSelectedKeys){ + // 设置选中wiki + setSelectedKey(defaultSelectedKeys); + // 第一次渲染,默认打开选中的页面所处目录 + const keys = []; + const list = defaultSelectedKeys[0].split('-'); + list.map((item, index)=>{ + keys.push(index > 0 ? `${keys[index-1]}-${item}` : item) + }) + setExpandedKeys(keys); + } }, [defaultSelectedKeys]) useEffect(()=>{ @@ -43,7 +58,7 @@ export default function Sidebar(props) { - { updateName(e, item) }}> + { updateName(e, item, 1) }}> 重命名 @@ -57,6 +72,11 @@ export default function Sidebar(props) { const fileMenu = (title, isFile, item) =>{ return + + { updateName(e, item, 2) }}> + 重命名 + + { deleteFileModal(e, title, isFile, item) }}> 删除 @@ -102,6 +122,7 @@ export default function Sidebar(props) { }); }; + // 选中节点 function selectTree(keys,event){ let {title, key} = event.node.props.dataRef; setSelectedKey([key+""]); @@ -113,6 +134,19 @@ export default function Sidebar(props) { } } + // 收起展开 + function onExpand(keys, obj){ + const oldKeys = new Set(keys); + const {expanded} = obj; + let {key} = obj.node.props.dataRef; + if(expanded){ + oldKeys.add(key); + }else{ + oldKeys.delete(key); + } + setExpandedKeys(Array.from(oldKeys)) + } + // 删除wiki模态框 function deleteFileModal(e, title, isFile, item) { e.stopPropagation(); @@ -257,11 +291,11 @@ export default function Sidebar(props) { history.push(`/${owner}/${projectsId}/wiki/add?key=${item.key}`) } - // 重命名目录文件 - function updateName(e, item){ + // 重命名目录文件 type:1 目录 2页面 + function updateName(e, item, type){ e.stopPropagation(); setVisible(item); - setIsEditName(true); + setIsEditName(type); let title = item.title.trim(); const isFile = title.startsWith('[[') && title.endsWith(']]'); title = isFile ? title.substring(2,title.length-2) : title.substring(2, title.length); @@ -284,7 +318,7 @@ export default function Sidebar(props) { return; } if(!isEditName){ - // 校验同级目录中是否有相同名称 + // 新增目录:校验同级目录中是否有相同名称 const {children, node, title, key} = visible; const mList = children.filter(item=>!item.title.trim().startsWith('[[')).map(i=>i.title.trim()) if(mList.includes(`- ${menuName}`)){ @@ -295,23 +329,52 @@ export default function Sidebar(props) { addChildrenByKey(newList, key, menuName); updateSidebar(treeToMd(newList), 3) }else{ - // 编辑sidebar + // isEditName 1 编辑目录名称 2编辑页面名称 + const titleToJudge = isEditName === 2 ? `[[${menuName}]]` : `- ${menuName}`; const {children, node, title, key} = visible; const list = findNodeByChildrenKey(menuList, key) || []; - if(title.trim() === `- ${menuName}`){ - setAddMenuError("请修改目录名称"); + if(title.trim() === titleToJudge){ + setAddMenuError("请修改名称"); return } - if(list.map(item=>item.title.trim()).includes(`- ${menuName}`)){ + if(list.map(item=>item.title.trim()).includes(titleToJudge)){ message.error("不能与同级目录名称相同"); - }else{ - const newMenuList = JSON.parse(JSON.stringify(menuList)) - loop(newMenuList, key, (item)=>{ - const {title} = item; - item.title = `${title.substring(0, title.indexOf('- '))}- ${menuName}` - }) - updateSidebar(treeToMd(newMenuList), 4) + return } + // wiki名称不可重复 + const sameNameWiki = fileArrInit.filter(item=>item.name === menuName) + if(isEditName === 2 && sameNameWiki.length){ + message.error("wiki名称不可重复"); + return + } + // 编辑sidebar + const newMenuList = JSON.parse(JSON.stringify(menuList)) + loop(newMenuList, key, (item)=>{ + const {key} = item; + item.title = `${'\t'.repeat(key.split('-').length-1)}${titleToJudge}` + }) + if(isEditName === 2){ + // 编辑页面名称-> 修改wiki + const oldTitle = title.substring(title.indexOf('[[')+2, title.indexOf(']]')) + updateWiki({ + owner, + repo: projectsId, + projectId: project.id, + // 原名称 + pageName: oldTitle, + // 现名称 + title: menuName, + commit_message: '', + }).then(res=>{ + if(res && res.message === '200'){ + // 修改wiki名称接口请求成功,更新sidebar + updateSidebar(treeToMd(newMenuList), 4); + history.push(`/${owner}/${projectsId}/wiki/${encodeURI(menuName)}/${key}`); + } + }) + return; + } + updateSidebar(treeToMd(newMenuList), 4) } } @@ -440,16 +503,99 @@ export default function Sidebar(props) { setMenuName(undefined); } + // 展开收起全部节点 + function expandAll(){ + setIsExpendedAll(!isExpendedAll); + if(isExpendedAll){ + setExpandedKeys([]); + return; + } + const allKeys = []; + findMenuKey(allKeys, menuList); + setExpandedKeys(allKeys); + } + + function findMenuKey(keys, list){ + list.map(item=>{ + if(item && !item.title.startsWith("[[")){ + keys.push(item.key); + } + if(item && item.children.length){ + findMenuKey(keys, item.children); + } + }) + } + + function changeSearchValue(value) { + if(value){ + // 找到符合条件的子节点, 重新渲染页面 + let keysMap = findNodesToKeys(initMenuList, value); + 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){ + setSelectedKey([path[path.length-1]]); + const titleSplit = title.substring(2,title.length-2); + changeitem({key: path[path.length-1], name: titleSplit}) + } + }) + 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(JSON.parse(JSON.stringify(initMenuList))); + } + } + + function findNodesToKeys(arr, value, path, nodes) { + path = path || []; + nodes = nodes || []; + if (Array.isArray(arr)) { + arr.forEach(function (obj, index) { + if (obj && typeof obj === 'object') { + const {children, key} = obj; + const title = obj.title.trim(); + const isFile = title.startsWith('[[') && title.endsWith(']]'); + if (title.match(new RegExp(value, 'i'))) { + nodes.push({path: path.concat([key]), isFile, title}); + } else { + findNodesToKeys(children, value, path.concat([key]), nodes); + } + } + }); + } + return nodes; + } + return( -
- {menuList && menuList.length ? +
+ + + {/* 目录是否全部展开 */} +
{isExpendedAll ? '收起' : '展开'}所有节点
+ + {/* wiki目录 */} + {menuList && menuList.length ? {renderTreeNodes(menuList)} : ''} {/* 新增子目录弹窗 */} - -
目录名称:
- {setMenuName(e.target.value);setAddMenuError(undefined)}} maxLength={50}> + +
{isEditName === 2 ? '页面' : '目录'}名称:
+ {setMenuName(e.target.value);setAddMenuError(undefined)}} maxLength={50}>
{addMenuError}