From 756599e2e283c960ef97747a7fff7b49ed614537 Mon Sep 17 00:00:00 2001 From: vapao Date: Tue, 27 Feb 2024 18:16:43 +0800 Subject: [PATCH] update --- spug_web2/package.json | 2 +- spug_web2/src/App.jsx | 3 + .../src/components/STable/index.module.scss | 1 - spug_web2/src/libs/http.js | 6 +- spug_web2/src/libs/utils.js | 11 ++ spug_web2/src/pages/host/Group.jsx | 164 +++++++++++++----- spug_web2/src/pages/host/index.module.scss | 20 +++ spug_web2/src/pages/login/index.jsx | 6 +- 8 files changed, 159 insertions(+), 54 deletions(-) diff --git a/spug_web2/package.json b/spug_web2/package.json index cec8806..fe441d5 100644 --- a/spug_web2/package.json +++ b/spug_web2/package.json @@ -10,7 +10,7 @@ "preview": "vite preview" }, "dependencies": { - "antd": "^5.12.4", + "antd": "^5.14.1", "dayjs": "^1.11.10", "i18next": "^23.7.7", "mobx": "^6.12.0", diff --git a/spug_web2/src/App.jsx b/spug_web2/src/App.jsx index 209590d..2754fe4 100644 --- a/spug_web2/src/App.jsx +++ b/spug_web2/src/App.jsx @@ -35,6 +35,9 @@ function App() { headerHeight: 48, footerPadding: 16 }, + Tree: { + titleHeight: 30 + } }, }}> diff --git a/spug_web2/src/components/STable/index.module.scss b/spug_web2/src/components/STable/index.module.scss index 1acf433..85f4ee6 100644 --- a/spug_web2/src/components/STable/index.module.scss +++ b/spug_web2/src/components/STable/index.module.scss @@ -5,7 +5,6 @@ } .search { - height: 28px; line-height: 28px; } diff --git a/spug_web2/src/libs/http.js b/spug_web2/src/libs/http.js index efc9665..3b31fb2 100644 --- a/spug_web2/src/libs/http.js +++ b/spug_web2/src/libs/http.js @@ -1,7 +1,7 @@ import useSWR from 'swr' -import {message} from 'antd' +import { message } from 'antd' import app from '@/libs/app.js' -import {redirect} from 'react-router-dom' +import { redirect } from 'react-router-dom' function fetcher(resource, init) { return fetch(resource, init) @@ -33,7 +33,7 @@ function SWRGet(url, params) { } function request(method, url, params) { - const init = {method, headers: {'X-Token': app.accessToken}} + const init = { method, headers: { 'X-Token': app.access_token } } if (['GET', 'DELETE'].includes(method)) { if (params) url = `${url}?${new URLSearchParams(params).toString()}` return fetcher(url, init) diff --git a/spug_web2/src/libs/utils.js b/spug_web2/src/libs/utils.js index 384e9d6..522b843 100644 --- a/spug_web2/src/libs/utils.js +++ b/spug_web2/src/libs/utils.js @@ -54,4 +54,15 @@ export function loadJSONStorage(key, defaultValue = null) { } } return defaultValue +} + +// 递归查找树节点 +export function findNodeByKey(array, key) { + for (let item of array) { + if (item.key === key) return item + if (item.children) { + let tmp = findNodeByKey(item.children, key) + if (tmp) return tmp + } + } } \ No newline at end of file diff --git a/spug_web2/src/pages/host/Group.jsx b/spug_web2/src/pages/host/Group.jsx index a0489e7..0796fd1 100644 --- a/spug_web2/src/pages/host/Group.jsx +++ b/spug_web2/src/pages/host/Group.jsx @@ -1,58 +1,130 @@ -import {} from 'react' -import {Card, Tree} from 'antd' +import { useRef, useState, useEffect } from 'react' +import { Card, Tree, Dropdown, Input } from 'antd' +import { FaServer } from 'react-icons/fa6' +import { IoMdMore } from 'react-icons/io' +import { AiOutlineFolder, AiOutlineFolderAdd, AiOutlineEdit, AiOutlineFileAdd, AiOutlineScissor, AiOutlineClose, AiOutlineDelete } from 'react-icons/ai' +import { useImmer } from 'use-immer' +import { http, findNodeByKey } from '@/libs' import css from './index.module.scss' +let clickNode = null function Group() { - const dataSource = [ - { - title: 'parent 1-0', - key: '0-0-0', - children: [ - { - title: 'leaf', - key: '0-0-0-0', - }, - { - title: 'leaf', - key: '0-0-0-1', - }, - { - title: 'leaf', - key: '0-0-0-2', - }, - ], - }, - { - title: 'parent 1-1', - key: '0-0-1', - children: [ - { - title: 'leaf', - key: '0-0-1-0', - }, - ], - }, - { - title: 'parent 1-2', - key: '0-0-2', - children: [ - { - title: 'leaf', - key: '0-0-2-0', - }, - { - title: 'leaf', - key: '0-0-2-1', - }, - ], - }, + const inputRef = useRef(null) + const [expandedKeys, setExpandedKeys] = useState([]) + const [treeData, updateTreeData] = useImmer([]) + + const menuItems = [ + { label: '新建根分组', key: 'newRoot', icon: }, + { label: '新建子分组', key: 'newChild', icon: }, + { label: '重命名', key: 'rename', icon: }, + { type: 'divider' }, + { label: '添加主机', key: 'addHost', icon: }, + { label: '移动主机', key: 'moveHost', icon: }, + { label: '删除主机', key: 'deleteHost', icon: }, + { type: 'divider' }, + { label: '删除此分组', key: 'deleteGroup', danger: true, icon: }, ] + useEffect(() => { + fetchData() + // eslint-disable-next-line + }, []) + + function fetchData() { + http.get('/api/host/group/') + .then(res => { + updateTreeData(res.treeData) + }) + } + + function handleNodeClick(e, node) { + e.stopPropagation() + clickNode = node + } + + function handleMenuClick({ key, domEvent }) { + domEvent.stopPropagation() + console.log(key, clickNode.key) + switch (key) { + case 'newRoot': + updateTreeData(draft => { + draft.unshift({ key, action: key, selectable: false }) + }) + break + case 'newChild': + updateTreeData(draft => { + const node = findNodeByKey(draft, clickNode.key) + if (!node) return + if (!node.children) node.children = [] + node.children.unshift({ key, action: key, selectable: false }) + }) + if (![expandedKeys].includes(clickNode.key)) { + setExpandedKeys([...expandedKeys, clickNode.key]) + } + break + case 'rename': + updateTreeData(draft => { + const node = findNodeByKey(draft, clickNode.key) + if (!node) return + node.action = key + node.selectable = false + }) + break + case 'addHost': + console.log('添加主机') + break + case 'moveHost': + console.log('移动主机') + break + case 'deleteHost': + console.log('删除主机') + break + case 'deleteGroup': + console.log('删除此分组') + break + default: + break + } + if (['newRoot', 'newChild', 'rename'].includes(key)) { + setTimeout(() => { + inputRef.current.focus() + }, 300) + } + } + + function handleInputSubmit(e) { + console.log('提交: ', e.target.value) + } + + function titleRender(node) { + return ['newRoot', 'newChild', 'rename'].includes(node.action) ? ( + + ) : ( +
+ +
{node.title}
+
handleNodeClick(e, node)}> + +
+ +
+
+
+
+ ) + } + return ( setExpandedKeys(keys)} /> ) diff --git a/spug_web2/src/pages/host/index.module.scss b/spug_web2/src/pages/host/index.module.scss index 56454c5..5883978 100644 --- a/spug_web2/src/pages/host/index.module.scss +++ b/spug_web2/src/pages/host/index.module.scss @@ -5,6 +5,26 @@ margin-right: -1px; border-top-right-radius: 0; border-bottom-right-radius: 0; + + .treeTitle { + display: flex; + flex-direction: row; + align-items: center; + + .title { + flex: 1; + margin-left: 6px; + } + + .more { + width: 30px; + height: 30px; + display: flex; + justify-content: center; + align-items: center; + margin-right: -4px; + } + } } .table { diff --git a/spug_web2/src/pages/login/index.jsx b/spug_web2/src/pages/login/index.jsx index 05ea8c9..ee59da8 100644 --- a/spug_web2/src/pages/login/index.jsx +++ b/spug_web2/src/pages/login/index.jsx @@ -8,8 +8,8 @@ import {useNavigate} from 'react-router-dom' import {Form, Input, Button, Tabs, Modal, message} from 'antd'; import {AiOutlineUser, AiOutlineLock, AiOutlineCopyright, AiOutlineGithub, AiOutlineMail} from 'react-icons/ai' import styles from './login.module.css'; -import {http, session} from '@/libs'; -import logo from '@/assets/logo-spug-txt.png'; +import {http, app} from '@/libs'; +import logo from '@/assets/spug-default.png'; export default function Login() { const navigate = useNavigate(); @@ -59,7 +59,7 @@ export default function Login() { function doLogin(data) { localStorage.setItem('login_type', loginType); - session.update(data) + app.updateSession(data) navigate('/home', {replace: true}) }