From 9c0b41ba511052650a9ace2199d985d30dd866c9 Mon Sep 17 00:00:00 2001 From: vapao Date: Tue, 27 Feb 2024 00:09:33 +0800 Subject: [PATCH] update --- spug_api/requirements.txt | 3 +- spug_web2/package.json | 4 +- spug_web2/src/App.jsx | 18 +-- spug_web2/src/components/STable/Setting.jsx | 28 ++-- spug_web2/src/components/STable/index.jsx | 123 +++++++++++++++--- .../src/components/STable/index.module.scss | 23 ++++ spug_web2/src/libs/app.js | 5 +- spug_web2/src/pages/host/Form.jsx | 0 spug_web2/src/pages/host/Group.jsx | 61 +++++++++ spug_web2/src/pages/host/index.module.scss | 14 ++ 10 files changed, 235 insertions(+), 44 deletions(-) create mode 100644 spug_web2/src/pages/host/Form.jsx create mode 100644 spug_web2/src/pages/host/Group.jsx create mode 100644 spug_web2/src/pages/host/index.module.scss diff --git a/spug_api/requirements.txt b/spug_api/requirements.txt index 9206711..333134f 100644 --- a/spug_api/requirements.txt +++ b/spug_api/requirements.txt @@ -1,8 +1,9 @@ apscheduler==3.10.4 Django >= 4.2.0, < 4.3.0 -paramiko==3.3.1 +paramiko==3.4.0 channels >= 4.0.0, < 5.0.0 channels-redis >= 4.1.0, < 5.0.0 +django_redis >= 5.4.0, < 6.0.0 asgiref==3.7.2 requests >= 2.31.0, < 3.0.0 python-ldap==3.4.3 diff --git a/spug_web2/package.json b/spug_web2/package.json index e773461..cec8806 100644 --- a/spug_web2/package.json +++ b/spug_web2/package.json @@ -13,6 +13,8 @@ "antd": "^5.12.4", "dayjs": "^1.11.10", "i18next": "^23.7.7", + "mobx": "^6.12.0", + "mobx-react-lite": "^4.0.5", "react": "^18.2.0", "react-dom": "^18.2.0", "react-i18next": "^13.5.0", @@ -32,4 +34,4 @@ "sass": "^1.69.5", "vite": "^5.0.2" } -} +} \ No newline at end of file diff --git a/spug_web2/src/App.jsx b/spug_web2/src/App.jsx index 4321343..209590d 100644 --- a/spug_web2/src/App.jsx +++ b/spug_web2/src/App.jsx @@ -1,12 +1,12 @@ -import {createBrowserRouter, RouterProvider} from 'react-router-dom' -import {ConfigProvider, App as AntdApp, theme} from 'antd' -import {IconContext} from 'react-icons' +import { createBrowserRouter, RouterProvider } from 'react-router-dom' +import { ConfigProvider, App as AntdApp, theme } from 'antd' +import { IconContext } from 'react-icons' import zhCN from 'antd/locale/zh_CN' import enUS from 'antd/locale/en_US' import dayjs from 'dayjs' import routes from './routes.jsx' -import {app, SContext} from '@/libs' -import {useImmer} from 'use-immer' +import { app, SContext } from '@/libs' +import { useImmer } from 'use-immer' import './i18n.js' dayjs.locale(app.lang) @@ -14,10 +14,10 @@ dayjs.locale(app.lang) const router = createBrowserRouter(routes) function App() { - const [S, updateS] = useImmer({theme: app.theme}) + const [S, updateS] = useImmer({ theme: app.theme }) return ( - + - + - + diff --git a/spug_web2/src/components/STable/Setting.jsx b/spug_web2/src/components/STable/Setting.jsx index 9b53d99..3c5fa7e 100644 --- a/spug_web2/src/components/STable/Setting.jsx +++ b/spug_web2/src/components/STable/Setting.jsx @@ -1,33 +1,33 @@ -import {useState, useEffect} from 'react' -import {Button, Checkbox, Flex, Popover} from 'antd' -import {IoSettingsOutline} from 'react-icons/io5' -import {app, clsNames} from '@/libs' +import { useState, useEffect } from 'react' +import { Button, Checkbox, Flex, Popover } from 'antd' +import { IoSettingsOutline } from 'react-icons/io5' +import { app, clsNames } from '@/libs' function Setting(props) { - const {skey, columns, setCols} = props + const { skey, columns, setCols } = props const [state, setState] = useState(app.getStable(skey)) useEffect(() => { const newColumns = [] for (const item of columns) { - if (state[item.key] ?? !item.hidden) { + if (state[item.title] ?? !item.hidden) { newColumns.push(item) } } setCols(newColumns) - }, [state]); + }, [columns, state]); function handleChange(e) { - const {value, checked} = e.target - const newState = {...state, [value]: checked} + const { value, checked } = e.target + const newState = { ...state, [value]: checked } setState(newState) app.updateStable(skey, newState) } function handleReset() { setState({}) - app.updateStable(skey, {}) + app.updateStable(skey, null) } return ( @@ -35,7 +35,7 @@ function Setting(props) { title={(
{t('展示字段')}
- +
)} trigger="click" placement="bottomRight" @@ -43,9 +43,9 @@ function Setting(props) { {columns.map((item, index) => ( {item.title} @@ -53,7 +53,7 @@ function Setting(props) { )}>
- +
) diff --git a/spug_web2/src/components/STable/index.jsx b/spug_web2/src/components/STable/index.jsx index a5fa2f1..0b9357e 100644 --- a/spug_web2/src/components/STable/index.jsx +++ b/spug_web2/src/components/STable/index.jsx @@ -1,18 +1,87 @@ -import {useRef, useState} from 'react' -import {Card, Table, Flex, Divider} from 'antd' -import {IoExpand, IoContract, IoReloadOutline} from 'react-icons/io5' -import {clsNames} from '@/libs' +import { useRef, useState, useEffect } from 'react' +import { Card, Table, Flex, Divider, Checkbox, Button, Input, Tag } from 'antd' +import { IoExpand, IoContract, IoReloadOutline } from 'react-icons/io5' +import { useImmer } from 'use-immer' +import { clsNames, includes } from '@/libs' import Setting from './Setting.jsx' import css from './index.module.scss' -function Stable(props) { - const {skey, loading, columns, dataSource, actions, pagination} = props - const ref = useRef(); +function STable(props) { + const { skey, loading, columns, dataSource, actions, pagination } = props + const ref = useRef() + const sMap = useRef({}) + const [sColumns, setSColumns] = useState([]) const [cols, setCols] = useState([]) const [isFull, setIsFull] = useState(false) + const [filters, updateFilters] = useImmer({}) if (!skey) throw new Error('skey is required') + useEffect(() => { + const newColumns = [] + for (const item of columns) { + const key = item.dataIndex + if (item.filterKey) { + let inputRef = null + item.onFilter = (value, record) => includes(record[key], value) + item.filterDropdown = (x) => { + sMap.current[key] = x + return ( +
+ inputRef = ref} + onChange={e => x.setSelectedKeys(e.target.value ? [e.target.value] : [])} + onSearch={v => handleSearch(key, v)} + /> +
+ ) + } + item.onFilterDropdownOpenChange = (visible) => { + if (visible) { + setTimeout(() => inputRef.focus(), 100) + } + } + } else if (item.filterItems) { + item.onFilter = (value, record) => record[key] === value + item.filterDropdown = (x) => { + sMap.current[key] = x + return ( +
+ + + + + + +
+ ) + } + } + newColumns.push(item) + } + setSColumns(newColumns) + }, [columns]) + + function handleSearch(key, v) { + const x = sMap.current[key] + updateFilters(draft => { + if (Array.isArray(v)) { + v.length ? draft[key] = v : delete draft[key] + } else { + v ? draft[key] = v : delete draft[key] + } + }) + if (!v) x.setSelectedKeys([]) + x.confirm() + } + function handleFullscreen() { if (ref.current && document.fullscreenEnabled) { if (document.fullscreenElement) { @@ -25,27 +94,47 @@ function Stable(props) { } } + function SearchItem(props) { + const { cKey, value } = props + const column = columns.find(item => item.dataIndex === cKey) + + return ( + handleSearch(cKey, '')} className={css.search}> + {column.title}: {Array.isArray(value) ? value.join(' | ') : value} + + ) + } + return ( - + + {Object.keys(filters).length ? ( + + {Object.entries(filters).map(([key, value]) => ( + + ))} + + ) : ( +
{props.title}
+ )} {actions} - {actions.length ? : null} - - + {actions.length ? : null} + + {isFull ? ( - + ) : ( - + )}
- +
) } -Stable.defaultProps = { +STable.defaultProps = { sKey: null, loading: false, actions: [], @@ -53,11 +142,11 @@ Stable.defaultProps = { pagination: { showSizeChanger: true, showLessItems: true, - showTotal: total => t('page', {total}), + showTotal: total => t('page', { total }), pageSizeOptions: ['10', '20', '50', '100'] }, onReload: () => { }, } -export default Stable \ No newline at end of file +export default STable \ No newline at end of file diff --git a/spug_web2/src/components/STable/index.module.scss b/spug_web2/src/components/STable/index.module.scss index a7b411c..1acf433 100644 --- a/spug_web2/src/components/STable/index.module.scss +++ b/spug_web2/src/components/STable/index.module.scss @@ -4,12 +4,35 @@ } } +.search { + height: 28px; + line-height: 28px; +} + .toolbar { margin-bottom: 12px; + .title { + font-size: 16px; + font-weight: bold; + } + .icon { font-size: 18px; cursor: pointer; } } +.filterItems { + min-width: 150px; + + :global(.ant-checkbox-group) { + display: flex; + flex-direction: column; + padding: 8px 16px; + } + + .action { + padding: 8px 16px 8px 8px; + } +} \ No newline at end of file diff --git a/spug_web2/src/libs/app.js b/spug_web2/src/libs/app.js index ce191a6..802d103 100644 --- a/spug_web2/src/libs/app.js +++ b/spug_web2/src/libs/app.js @@ -1,4 +1,4 @@ -import {isSubArray, loadJSONStorage} from "@/libs/utils.js"; +import { isSubArray, loadJSONStorage } from "@/libs/utils.js"; class App { constructor() { @@ -17,7 +17,7 @@ class App { } hasPermission(code) { - const {isSuper, permissions} = this.session; + const { isSuper, permissions } = this.session; if (!code || isSuper) return true; for (let item of code.split('|')) { if (isSubArray(permissions, item.split('&'))) { @@ -38,6 +38,7 @@ class App { updateStable(key, data) { this.stable[key] = data; + if (data === null) delete this.stable[key]; localStorage.setItem('stable', JSON.stringify(this.stable)); } } diff --git a/spug_web2/src/pages/host/Form.jsx b/spug_web2/src/pages/host/Form.jsx new file mode 100644 index 0000000..e69de29 diff --git a/spug_web2/src/pages/host/Group.jsx b/spug_web2/src/pages/host/Group.jsx new file mode 100644 index 0000000..a0489e7 --- /dev/null +++ b/spug_web2/src/pages/host/Group.jsx @@ -0,0 +1,61 @@ +import {} from 'react' +import {Card, Tree} from 'antd' +import css from './index.module.scss' + + +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', + }, + ], + }, + ] + + return ( + + + + ) +} + +export default Group \ No newline at end of file diff --git a/spug_web2/src/pages/host/index.module.scss b/spug_web2/src/pages/host/index.module.scss new file mode 100644 index 0000000..56454c5 --- /dev/null +++ b/spug_web2/src/pages/host/index.module.scss @@ -0,0 +1,14 @@ +.group { + flex: 1; + min-width: 200px; + max-width: 300px; + margin-right: -1px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.table { + flex: 3; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} \ No newline at end of file