From bd58d5983c0d2f9c4686a1baf0c21baf0efbfbc9 Mon Sep 17 00:00:00 2001 From: xion Date: Fri, 28 Feb 2025 15:31:32 +0800 Subject: [PATCH] feat: add user manager --- package.json | 1 + pnpm-lock.yaml | 12 ++++ src/index.css | 1 + src/modules/layout/LayoutUser.tsx | 3 +- src/modules/layout/Menu.tsx | 3 +- src/modules/layout/store/index.ts | 4 +- src/modules/message.ts | 3 + src/modules/query.ts | 2 +- src/pages/app/edit/AppVersionList.tsx | 3 +- src/pages/app/edit/List.tsx | 3 +- src/pages/app/modules/FileUpload.tsx | 4 +- src/pages/app/store/app-version.ts | 5 +- src/pages/app/store/user-app.ts | 2 +- src/pages/container/edit/List.tsx | 3 +- src/pages/container/module/Select.tsx | 4 +- src/pages/container/preview/index.tsx | 2 +- src/pages/file/store/index.ts | 2 +- src/pages/org/edit/List.tsx | 5 +- src/pages/org/edit/UserList.tsx | 77 +++++++++++++++++--------- src/pages/org/store/index.ts | 46 ++++++++++++++- src/pages/user/edit/List.tsx | 4 +- src/pages/user/login/Login.tsx | 2 +- src/pages/user/module/AvatarUpload.tsx | 5 +- src/pages/user/module/FileUpload.tsx | 2 +- src/pages/user/store/index.ts | 2 +- src/pages/user/store/login.ts | 6 +- 26 files changed, 149 insertions(+), 57 deletions(-) create mode 100644 src/modules/message.ts diff --git a/package.json b/package.json index 72c0acb..15ab162 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@kevisual/codemirror": "^0.0.2", "@kevisual/container": "1.0.0", "@kevisual/query": "^0.0.6", + "@kevisual/system-ui": "^0.0.3", "@kevisual/ui": "^0.0.2", "@monaco-editor/react": "^4.7.0", "@tailwindcss/vite": "^4.0.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 798c914..c0f9fd6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,9 @@ importers: '@kevisual/query': specifier: ^0.0.6 version: 0.0.6 + '@kevisual/system-ui': + specifier: ^0.0.3 + version: 0.0.3 '@kevisual/ui': specifier: ^0.0.2 version: 0.0.2 @@ -631,6 +634,9 @@ packages: '@kevisual/query@0.0.6': resolution: {integrity: sha512-J+poZwIx4r956GDN5zI8zM0YyyxJqARZVVOFYplRThaQLqpsbRNYJoYiT5DekvBftxtFjs/OlI3RzcHDOv3Fjw==} + '@kevisual/system-ui@0.0.3': + resolution: {integrity: sha512-zRtUnL6wNe6R1W7X6eirDADZWeTmxZCNpLwxCLu30yeNuIhpFJdxHyOg0nX9aOZn6F0Kb6lB3Li2fZpKwdpk0w==} + '@kevisual/ui@0.0.2': resolution: {integrity: sha512-MDZDQTrYToLyj3WhiVJQLJ0PUHiN4D0Z5yJIyGzzPewPGpP2xwNgKO1BFX37J95cGZckzCdZwTKP0XKAOq0QtA==} @@ -3166,6 +3172,12 @@ snapshots: '@kevisual/query@0.0.6': {} + '@kevisual/system-ui@0.0.3': + dependencies: + dayjs: 1.11.13 + lodash-es: 4.17.21 + style-to-object: 1.0.8 + '@kevisual/ui@0.0.2': dependencies: dayjs: 1.11.13 diff --git a/src/index.css b/src/index.css index f23714c..e1bf7ee 100644 --- a/src/index.css +++ b/src/index.css @@ -4,6 +4,7 @@ body { height: 100%; font-size: 16px; font-family: 'Montserrat', sans-serif; + overflow: hidden; } #root { diff --git a/src/modules/layout/LayoutUser.tsx b/src/modules/layout/LayoutUser.tsx index b21e28f..a2b1652 100644 --- a/src/modules/layout/LayoutUser.tsx +++ b/src/modules/layout/LayoutUser.tsx @@ -1,7 +1,8 @@ import { useShallow } from 'zustand/react/shallow'; import { useLayoutStore } from './store'; import clsx from 'clsx'; -import { Button, Dropdown, message } from 'antd'; +import { Button, Dropdown } from 'antd'; +import { message } from '@/modules/message'; import { CloseOutlined, CodeOutlined, diff --git a/src/modules/layout/Menu.tsx b/src/modules/layout/Menu.tsx index ab20959..3aac0b3 100644 --- a/src/modules/layout/Menu.tsx +++ b/src/modules/layout/Menu.tsx @@ -1,7 +1,8 @@ import { useShallow } from 'zustand/react/shallow'; import { useLayoutStore } from './store'; import clsx from 'clsx'; -import { Button, message } from 'antd'; +import { Button } from 'antd'; +import { message } from '@/modules/message'; import { AppstoreOutlined, CloseOutlined, diff --git a/src/modules/layout/store/index.ts b/src/modules/layout/store/index.ts index cdfeffa..7df4cc6 100644 --- a/src/modules/layout/store/index.ts +++ b/src/modules/layout/store/index.ts @@ -1,6 +1,6 @@ import { query } from '@/modules/query'; -import { message } from 'antd'; import { create } from 'zustand'; +import { message } from '@/modules/message'; export const getIsMac = async () => { // @ts-ignore const userAgentData = navigator.userAgentData; @@ -37,7 +37,7 @@ export const usePlatformStore = create((set) => { init: async () => { const mac = await getIsMac(); // @ts-ignore - const isElectron = getIsElectron() + const isElectron = getIsElectron(); set({ isMac: isElectron && mac, isElectron: isElectron, mount: true }); }, }; diff --git a/src/modules/message.ts b/src/modules/message.ts new file mode 100644 index 0000000..f3cb669 --- /dev/null +++ b/src/modules/message.ts @@ -0,0 +1,3 @@ +import { message } from '@kevisual/system-ui/dist/message'; + +export { message }; diff --git a/src/modules/query.ts b/src/modules/query.ts index 01b90f2..32111c9 100644 --- a/src/modules/query.ts +++ b/src/modules/query.ts @@ -1,7 +1,7 @@ import { QueryClient } from '@kevisual/query'; import { modal } from './redirect-to-login'; import { create } from 'zustand'; -import { message } from 'antd'; +import { message } from './message'; export const query = new QueryClient(); query.beforeRequest = async (config) => { if (config.headers) { diff --git a/src/pages/app/edit/AppVersionList.tsx b/src/pages/app/edit/AppVersionList.tsx index 84f3497..22fa369 100644 --- a/src/pages/app/edit/AppVersionList.tsx +++ b/src/pages/app/edit/AppVersionList.tsx @@ -2,11 +2,12 @@ import { useNavigation, useParams } from 'react-router'; import { useAppVersionStore } from '../store'; import { useShallow } from 'zustand/react/shallow'; import { useCallback, useEffect, useMemo, useState } from 'react'; -import { Button, Form, Input, message, Modal, Space, Tooltip } from 'antd'; +import { Button, Form, Input, Modal, Space, Tooltip } from 'antd'; import { CloudUploadOutlined, DeleteOutlined, EditOutlined, FileOutlined, LeftOutlined, LinkOutlined, PlusOutlined } from '@ant-design/icons'; import { isObjectNull } from '@/utils/is-null'; import { FileUpload } from '../modules/FileUpload'; import clsx from 'clsx'; +import { message } from '@/modules/message'; import { useNewNavigate } from '@/modules'; const FormModal = () => { const [form] = Form.useForm(); diff --git a/src/pages/app/edit/List.tsx b/src/pages/app/edit/List.tsx index a9913b1..d9a1fa8 100644 --- a/src/pages/app/edit/List.tsx +++ b/src/pages/app/edit/List.tsx @@ -1,12 +1,13 @@ import { useShallow } from 'zustand/react/shallow'; import { useUserAppStore } from '../store'; import { useEffect } from 'react'; -import { Button, Form, Input, message, Space, Modal, Select, Tooltip } from 'antd'; +import { Button, Form, Input, Space, Modal, Select, Tooltip } from 'antd'; import { CodeOutlined, DeleteOutlined, EditOutlined, LinkOutlined, PlusOutlined, UnorderedListOutlined } from '@ant-design/icons'; import { isObjectNull } from '@/utils/is-null'; import { useNewNavigate } from '@/modules'; import { marked } from 'marked'; import clsx from 'clsx'; +import { message } from '@/modules/message'; const FormModal = () => { const [form] = Form.useForm(); const containerStore = useUserAppStore( diff --git a/src/pages/app/modules/FileUpload.tsx b/src/pages/app/modules/FileUpload.tsx index 46b19b7..da4c6e0 100644 --- a/src/pages/app/modules/FileUpload.tsx +++ b/src/pages/app/modules/FileUpload.tsx @@ -1,8 +1,8 @@ -import { Button, message } from 'antd'; +import { Button } from 'antd'; import { useCallback, useRef } from 'react'; import { useAppVersionStore } from '../store'; import { useShallow } from 'zustand/react/shallow'; - +import { message } from '@/modules/message'; export type FileType = { name: string; size: number; diff --git a/src/pages/app/store/app-version.ts b/src/pages/app/store/app-version.ts index a21bd05..76a31d4 100644 --- a/src/pages/app/store/app-version.ts +++ b/src/pages/app/store/app-version.ts @@ -1,8 +1,7 @@ import { create } from 'zustand'; import { query } from '@/modules'; -import { message } from 'antd'; import { isObjectNull } from '@/utils/is-null'; - +import { message } from '@/modules/message'; type AppVersionStore = { showEdit: boolean; setShowEdit: (showEdit: boolean) => void; @@ -117,7 +116,7 @@ export const useAppVersionStore = create((set, get) => { key: 'publish', data, }); - loaded(); + setTimeout(loaded, 200); if (res.code === 200) { message.success('Success'); // getList(); diff --git a/src/pages/app/store/user-app.ts b/src/pages/app/store/user-app.ts index 20b8ab3..8497431 100644 --- a/src/pages/app/store/user-app.ts +++ b/src/pages/app/store/user-app.ts @@ -1,6 +1,6 @@ import { create } from 'zustand'; import { query } from '@/modules'; -import { message } from 'antd'; +import { message } from '@/modules/message'; type UserAppStore = { showEdit: boolean; setShowEdit: (showEdit: boolean) => void; diff --git a/src/pages/container/edit/List.tsx b/src/pages/container/edit/List.tsx index 157c0ca..a031aa0 100644 --- a/src/pages/container/edit/List.tsx +++ b/src/pages/container/edit/List.tsx @@ -1,4 +1,4 @@ -import { Button, Input, message, Modal, Select, Space, Switch, Table, Tooltip } from 'antd'; +import { Button, Input, Modal, Select, Space, Switch, Table, Tooltip } from 'antd'; import { Fragment, useEffect, useState } from 'react'; import { TextArea } from '../components/TextArea'; import { useContainerStore } from '../store'; @@ -6,6 +6,7 @@ import { useShallow } from 'zustand/react/shallow'; import { Form } from 'antd'; import copy from 'copy-to-clipboard'; import { useNewNavigate } from '@/modules'; +import { message } from '@/modules/message'; import { EditOutlined, SettingOutlined, diff --git a/src/pages/container/module/Select.tsx b/src/pages/container/module/Select.tsx index f701d51..b916cec 100644 --- a/src/pages/container/module/Select.tsx +++ b/src/pages/container/module/Select.tsx @@ -1,7 +1,7 @@ import { query } from '@/modules'; -import { Select as AntSelect, message, SelectProps } from 'antd'; +import { Select as AntSelect, SelectProps } from 'antd'; import { useEffect, useState } from 'react'; - +import { message } from '@/modules/message'; export const Select = (props: SelectProps) => { const [options, setOptions] = useState<{ value: string; id: string }[]>([]); useEffect(() => { diff --git a/src/pages/container/preview/index.tsx b/src/pages/container/preview/index.tsx index b402927..525eb99 100644 --- a/src/pages/container/preview/index.tsx +++ b/src/pages/container/preview/index.tsx @@ -2,8 +2,8 @@ import { Container, RenderData, ContainerOne } from '@kevisual/container'; import { useEffect, useRef, useState } from 'react'; import { replace, useParams } from 'react-router'; import { query, ws, useStore } from '@/modules'; -import { message } from 'antd'; +import { message } from '@/modules/message'; export const useListener = (id?: string, opts?: any) => { const { refresh } = opts || {}; const connected = useStore((state) => state.connected); diff --git a/src/pages/file/store/index.ts b/src/pages/file/store/index.ts index ff6c747..003b01c 100644 --- a/src/pages/file/store/index.ts +++ b/src/pages/file/store/index.ts @@ -1,6 +1,6 @@ import { create } from 'zustand'; import { query } from '@/modules'; -import { message } from 'antd'; +import { message } from '@/modules/message'; import { sortBy } from 'lodash-es'; type FileStore = { showEdit: boolean; diff --git a/src/pages/org/edit/List.tsx b/src/pages/org/edit/List.tsx index 07c366b..6ee48b8 100644 --- a/src/pages/org/edit/List.tsx +++ b/src/pages/org/edit/List.tsx @@ -1,5 +1,6 @@ -import { Button, Input, message, Modal, Table, Tooltip } from 'antd'; +import { Button, Input, Modal, Table, Tooltip } from 'antd'; import { Fragment, useEffect, useMemo, useState } from 'react'; +import { message } from '@/modules/message'; import { useOrgStore } from '../store'; import { useShallow } from 'zustand/react/shallow'; import { Form } from 'antd'; @@ -204,7 +205,7 @@ export const List = () => { -
+
@@ -132,36 +147,47 @@ export const UserList = () => { icon={}>
-
+
{orgStore.users.map((item) => { const isOwner = item.role === 'owner'; return ( -
-
username: {item.username}
+
+
{ + copy(item.username); + }}> + username: {item.username} +
{item.role || '-'}
- - + + {/* - + */} - +
); @@ -171,6 +197,7 @@ export const UserList = () => {
+ {contextHolder}
); }; diff --git a/src/pages/org/store/index.ts b/src/pages/org/store/index.ts index fff2395..ac650ec 100644 --- a/src/pages/org/store/index.ts +++ b/src/pages/org/store/index.ts @@ -1,11 +1,15 @@ import { create } from 'zustand'; import { query } from '@/modules'; -import { message } from 'antd'; +import { message } from '@/modules/message'; type OrgStore = { showEdit: boolean; setShowEdit: (showEdit: boolean) => void; formData: any; setFormData: (formData: any) => void; + showUserEdit: boolean; + setShowUserEdit: (showUserEdit: boolean) => void; + userFormData: any; + setUserFormData: (userFormData: any) => void; loading: boolean; setLoading: (loading: boolean) => void; list: any[]; @@ -18,6 +22,8 @@ type OrgStore = { orgId: string; setOrgId: (orgId: string) => void; getOrg: () => Promise; + addUser: (data: { userId?: string; username?: string; role?: string }) => Promise; + removeUser: (userId: string) => Promise; }; export const useOrgStore = create((set, get) => { return { @@ -27,6 +33,10 @@ export const useOrgStore = create((set, get) => { setFormData: (formData) => set({ formData }), loading: false, setLoading: (loading) => set({ loading }), + showUserEdit: false, + setShowUserEdit: (showUserEdit) => set({ showUserEdit }), + userFormData: {}, + setUserFormData: (userFormData) => set({ userFormData }), list: [], getList: async () => { set({ loading: true }); @@ -84,7 +94,7 @@ export const useOrgStore = create((set, get) => { key: 'get', id: orgId, }); - loaded(); + setTimeout(loaded, 200); if (res.code === 200) { const { org, users } = res.data || {}; set({ org, users }); @@ -92,5 +102,37 @@ export const useOrgStore = create((set, get) => { message.error(res.message || 'Request failed'); } }, + addUser: async (data) => { + const { orgId } = get(); + const res = await query.post({ + path: 'org-user', + key: 'operate', + data: { orgId, ...data, action: 'add' }, + }); + if (res.code === 200) { + message.success('Success'); + get().getOrg(); + } else { + message.error(res.message || 'Request failed'); + } + }, + removeUser: async (userId: string) => { + const { orgId } = get(); + const res = await query.post({ + path: 'org-user', + key: 'operate', + data: { + orgId, + userId, + action: 'remove', + }, + }); + if (res.code === 200) { + message.success('Success'); + get().getOrg(); + } else { + message.error(res.message || 'Request failed'); + } + }, }; }); diff --git a/src/pages/user/edit/List.tsx b/src/pages/user/edit/List.tsx index 9392686..7280022 100644 --- a/src/pages/user/edit/List.tsx +++ b/src/pages/user/edit/List.tsx @@ -1,4 +1,4 @@ -import { Button, Input, message, Modal, Space, Table } from 'antd'; +import { Button, Input, Modal, Space, Table } from 'antd'; import { Fragment, useEffect, useMemo, useState } from 'react'; import { useUserStore } from '../store'; import { useShallow } from 'zustand/react/shallow'; @@ -8,7 +8,7 @@ import { EditOutlined, SettingOutlined, LinkOutlined, SaveOutlined, DeleteOutlin import clsx from 'clsx'; import { isObjectNull } from '@/utils/is-null'; import { CardBlank } from '@/components/card/CardBlank'; - +import { message } from '@/modules/message'; const FormModal = () => { const [form] = Form.useForm(); const userStore = useUserStore( diff --git a/src/pages/user/login/Login.tsx b/src/pages/user/login/Login.tsx index 04b2154..b70821d 100644 --- a/src/pages/user/login/Login.tsx +++ b/src/pages/user/login/Login.tsx @@ -32,7 +32,7 @@ export const Login = () => {

Login

-
+
>[0]; @@ -53,7 +54,7 @@ export const AvatarUpload = () => { }; const customAction = (file) => { console.log('file', file); - } + }; return ( >[0]; diff --git a/src/pages/user/store/index.ts b/src/pages/user/store/index.ts index 2eb44c8..b379b3c 100644 --- a/src/pages/user/store/index.ts +++ b/src/pages/user/store/index.ts @@ -1,6 +1,6 @@ import { create } from 'zustand'; import { query } from '@/modules'; -import { message } from 'antd'; +import { message } from '@/modules/message'; type UserStore = { showEdit: boolean; setShowEdit: (showEdit: boolean) => void; diff --git a/src/pages/user/store/login.ts b/src/pages/user/store/login.ts index bbb175e..87e4808 100644 --- a/src/pages/user/store/login.ts +++ b/src/pages/user/store/login.ts @@ -1,6 +1,6 @@ import { query } from '@/modules'; import { basename } from '@/modules/basename'; -import { message } from 'antd'; +import { message } from '@/modules/message'; import { create } from 'zustand'; // 如果自己是在iframe中登录,需要调用这个方法 export const postLoginInIframe = (token: string) => { @@ -55,7 +55,7 @@ export const useLoginStore = create((set, get) => { set({ loading: true }); const loaded = message.loading('loading...', 0); const res = await query.post({ path: 'user', key: 'login', username, password }); - loaded(); + setTimeout(loaded, 200); if (res.code === 200) { const { token } = res.data; message.success('Success'); @@ -81,7 +81,7 @@ export const useLoginStore = create((set, get) => { set({ loading: true }); const loaded = message.loading('loading...', 0); const res = await query.post({ path: 'user', key: 'register' }); - loaded(); + setTimeout(loaded, 200); if (res.code === 200) { message.success('Success'); // 跳到某一个页面