diff --git a/src/components/breadcrumb/index.tsx b/src/components/breadcrumb/index.tsx index 6bf3cf0..4f9c4d9 100644 --- a/src/components/breadcrumb/index.tsx +++ b/src/components/breadcrumb/index.tsx @@ -4,6 +4,8 @@ import { DownOutlined } from '@ant-design/icons' import { getIcon } from '@/components/icon' import { memo, useCallback } from 'react' import { useStyle } from './style.ts' +import { useSetAtom } from 'jotai' +import { currentMenuAtom } from '@/store/system.ts' export const PageBreadcrumb = memo((props: BreadcrumbProps & { showIcon?: boolean; @@ -12,6 +14,7 @@ export const PageBreadcrumb = memo((props: BreadcrumbProps & { const { styles } = useStyle() const nav = useNavigate() + const setCurrent = useSetAtom(currentMenuAtom) const { items = [], showIcon = true, ...other } = props const renderIcon = useCallback((icon: any) => { @@ -26,7 +29,7 @@ export const PageBreadcrumb = memo((props: BreadcrumbProps & { const isLast = route?.path === items[items.length - 1]?.path if (route.children) { - const items = route.children.map((item) => { + const items = route.children.filter(item => !(item.hidden || item.hidden_breadcrumb)).map((item) => { return { ...item, key: item.path || item.name, @@ -41,9 +44,12 @@ export const PageBreadcrumb = memo((props: BreadcrumbProps & { onClick: (menu) => { const info = props.menusFlatten.current?.find(item => item.path === menu.key) if (info) { + setCurrent(info) // setOpenKeys([ info.path as string ]) nav({ to: info.path, + }).then(() => { + }) } } @@ -75,10 +81,9 @@ export const PageBreadcrumb = memo((props: BreadcrumbProps & { ) } - return (
- diff --git a/src/components/popconfirm/index.tsx b/src/components/popconfirm/index.tsx new file mode 100644 index 0000000..697d297 --- /dev/null +++ b/src/components/popconfirm/index.tsx @@ -0,0 +1,21 @@ +import { Popconfirm as AntPopconfirm, PopconfirmProps } from 'antd' + +const Popconfirm = (props: PopconfirmProps) => { + + const disabled = props.disabled + + let attr = {} + if (typeof disabled !== 'undefined') { + attr = { + disabled: disabled + } + } + + return ( + + {props.children} + + ) +} + +export default Popconfirm \ No newline at end of file diff --git a/src/components/table/style.ts b/src/components/table/style.ts index e6d24de..96e2cc9 100644 --- a/src/components/table/style.ts +++ b/src/components/table/style.ts @@ -34,6 +34,12 @@ export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any) margin: 0; align-content: center; } + + .ant-table-cell{ + .ant-divider-vertical{ + margin-inline: 0; + } + } ` return { diff --git a/src/global.d.ts b/src/global.d.ts index 26ae21c..2ce9442 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -77,6 +77,7 @@ export interface IRootContext { interface MenuItem extends IMenu { routes?: MenuItem[]; + parent?: IMenu } interface IAuth { diff --git a/src/layout/ListPageLayout.tsx b/src/layout/ListPageLayout.tsx index d1d1afd..aa36c84 100644 --- a/src/layout/ListPageLayout.tsx +++ b/src/layout/ListPageLayout.tsx @@ -1,10 +1,13 @@ import React from 'react' import { useStyle } from '@/layout/style.ts' import { PageContainer, PageContainerProps } from '@ant-design/pro-components' -import { useAtomValue } from 'jotai' +import { useAtom } from 'jotai' import { currentMenuAtom } from '@/store/system.ts' import useResizeObserver from '@/hooks/useResizeObserver.ts' import useInlineStyle from '@/hooks/useInlineStyle.ts' +import { Space } from 'antd' +import { ArrowLeftOutlined } from '@ant-design/icons' +import { useNavigate } from '@tanstack/react-router' interface IListPageLayoutProps extends PageContainerProps { children: React.ReactNode @@ -13,15 +16,17 @@ interface IListPageLayoutProps extends PageContainerProps { const ListPageLayout: React.FC = ( { - className, children, authHeight = true, ...props + className, children, authHeight = true, ...props }) => { + + const navigate = useNavigate() const { styles, cx } = useStyle({ className: 'one-col' }) - const currentMenu = useAtomValue(currentMenuAtom) + const [ currentMenu, setCurrentMenu ] = useAtom(currentMenuAtom) const [ , headerSize ] = useResizeObserver({ selector: '.ant-page-header', }) - useInlineStyle({ + useInlineStyle({ styles: { '--pageHeader': `${headerSize.blockSize}px`, }, @@ -33,7 +38,21 @@ const ListPageLayout: React.FC = ( + { + currentMenu?.parent && { + navigate({ + to: currentMenu?.parent?.path, + }).then(() => { + setCurrentMenu(currentMenu.parent!) + }) + }}> + } + {currentMenu?.title} + + } className={cx(styles.container, styles.pageCard, styles.layoutTable, className)} {...props} diff --git a/src/layout/RootLayout.tsx b/src/layout/RootLayout.tsx index 4fa11cd..0eb8c11 100644 --- a/src/layout/RootLayout.tsx +++ b/src/layout/RootLayout.tsx @@ -6,7 +6,7 @@ import { appAtom, currentMenuAtom } from '@/store/system.ts' import { currentStaticUserAtom, userMenuDataAtom } from '@/store/system/user.ts' import { MenuItem } from '@/global' import { ProConfigProvider, ProLayout, } from '@ant-design/pro-components' -import { zhCNIntl, enUSIntl } from '@ant-design/pro-provider/es/intl' +import { enUSIntl, zhCNIntl } from '@ant-design/pro-provider/es/intl' import { CatchBoundary, Link, Outlet, useNavigate } from '@tanstack/react-router' import { ConfigProvider } from '@/components/config-provider' import { useEffect, useRef, useState } from 'react' @@ -55,18 +55,24 @@ export default () => { const [ pathname, setPathname ] = useState(location.pathname) const [ openMenuKeys, setOpenKeys ] = useState([]) const [ collapsed, setCollapsed ] = useState(false) - + const [ childPath, setChildPath ] = useState('') const menusFlatten = useRef() if (!menusFlatten.current) { - menusFlatten.current = flattenTree(menuData, { key: 'id', title: 'name' }).filter(item => !item.hidden) + menusFlatten.current = flattenTree(menuData, { key: 'id', title: 'name' }) } const [ rootMenuKeys, setRootMenuKeys ] = useState(() => { - const item = menusFlatten.current?.find(item => item.path === location.pathname) + let item = menusFlatten.current?.find(item => item.path === location.pathname) + if (item && item.hidden && item.active) { + setCurrentMenu(item) + item = menusFlatten.current?.find(i => i.path === item?.active) + } + if (item?.meta.affix) { return [ item.meta.name ] } return item ? item.parentName : [] }) + const childMenuRef = useRef([]) const currentMenu = menuData.find(item => { return item.key === rootMenuKeys?.[0] @@ -74,17 +80,21 @@ export default () => { childMenuRef.current = currentMenu?.children || [] - useEffect(() => { const item = menusFlatten.current?.find(item => item.path === location.pathname) if (item && item.meta.name !== rootMenuKeys?.[0]) { setRootMenuKeys(item.parentName) } - }, [ location.pathname ]) - useEffect(() => { + setCurrentMenu(item!) - }, [location.pathname]) + if (item && item.hidden && item.active) { + item.parent = menusFlatten.current?.find(i => i.path === item?.active) + setChildPath(item.active) + } else { + setChildPath('') + } + }, [ location.pathname ]) return (
{ ...{ rotate: -31, content: currentUser?.nickname, - fontColor: 'rgba(0,0,0,.15)', - fontSize: 17, + font: { + color: '#00000012', + size: 17, + }, zIndex: 1009, - } - } style={{ width: '100vw', height: '100vh'}}> - { - return <> - - - }} - headerRender={false} - title="Crazy Pro" - // layout={'mix'} - fixSiderbar={true} - siderWidth={80} - collapsedButtonRender={false} - // collapsed={false} - postMenuData={() => { - return menuData.filter(item => !item.hidden).map(item => ({ - ...item, - children: [], - })) as any - }} - route={ - { - path: '/', - routes: menuData.map(item => ({ + } as any + } style={{ width: '100vw', height: '100vh' }}> + { + return <> + + + }} + headerRender={false} + title="Crazy Pro" + // layout={'mix'} + fixSiderbar={true} + siderWidth={80} + collapsedButtonRender={false} + // collapsed={false} + postMenuData={() => { + return menuData.filter(item => !item.hidden).map(item => ({ ...item, - // path: item.path ?? `/${item.key}`, children: [], - // routes: undefined - })) + })) as any + }} + route={ + { + path: '/', + routes: menuData.map(item => ({ + ...item, + // path: item.path ?? `/${item.key}`, + children: [], + // routes: undefined + })) + } } - } - location={ - { - pathname, + location={ + { + pathname, + } } - } - menu={{ - collapsedShowGroupTitle: true, + menu={{ + collapsedShowGroupTitle: true, - }} - menuItemRender={(item: MenuDataItem) => { - return ( { - setRootMenuKeys([ (item as any).key || 'dashboard' ]) - setPathname(item.path || '/dashboard') }} - > + menuItemRender={(item: MenuDataItem) => { + return ( { + setRootMenuKeys([ (item as any).key || 'dashboard' ]) + setPathname(item.path || '/dashboard') + }} + > {item.icon} {item.name} ) - }} - avatarProps={false} - actionsRender={false} - menuProps={{ - className: styles.mySiderMenu, - selectedKeys: rootMenuKeys, - theme: 'dark', - }} - loading={isLoading} - contentStyle={{ paddingBlock: 0, paddingInline: 0 }} - { - ...{ - // "fixSiderbar": true, - // "layout": "side", - 'splitMenus': false, - 'navTheme': 'realDark', - 'contentWidth': 'Fluid', - 'colorPrimary': '#1677FF', - // "menuHeaderRender": false + }} + avatarProps={false} + actionsRender={false} + menuProps={{ + className: styles.mySiderMenu, + selectedKeys: rootMenuKeys, + theme: 'dark', + }} + loading={isLoading} + contentStyle={{ paddingBlock: 0, paddingInline: 0 }} + { + ...{ + // "fixSiderbar": true, + // "layout": "side", + 'splitMenus': false, + 'navTheme': 'realDark', + 'contentWidth': 'Fluid', + 'colorPrimary': '#1677FF', + // "menuHeaderRender": false + } } - } - > + > - 0}> - - - { - !collapsed &&
-

{currentMenu?.title}

-
- } + 0}> + + + { + !collapsed &&
+

{currentMenu?.title}

+
+ } - { - setOpenKeys(keys) - }} - onClick={(menu) => { - const info = menusFlatten.current?.find(item => item.path === menu.key) - if (info) { - setCurrentMenu(info) - // setOpenKeys([ info.path as string ]) - navigate({ - to: info.path, - }) - } + { + setOpenKeys(keys) + }} + onClick={(menu) => { + const info = menusFlatten.current?.find(item => item.path === menu.key) + if (info) { + setCurrentMenu(info) + // setOpenKeys([ info.path as string ]) + navigate({ + to: info.path, + }) + } - }} - items={convertToMenu((childMenuRef.current || []), (item => { - return { - ...item, - key: item.path || item.meta.name, - label: item.title, - } - })) as any} - style={!collapsed ? { width: 210 } : {}} - /> -
{ - setCollapsed(!collapsed) - }}> - { - collapsed ? : - } -
- - - + }} + items={convertToMenu((childMenuRef.current || []), (item => { + return { + data: item, + key: item.path || item.meta.name, + label: item.title, + } + })) as any} + style={!collapsed ? { width: 210 } : {}} + /> +
{ + setCollapsed(!collapsed) + }}> + { + collapsed ? : + } +
+ + + - -
- - - <> - - - - - -
- -
- {/* +
+ + + <> + + + + + +
+ + + {/* { }} > */} -
+ diff --git a/src/layout/TwoColPageLayout.tsx b/src/layout/TwoColPageLayout.tsx index f602e59..dda5d44 100644 --- a/src/layout/TwoColPageLayout.tsx +++ b/src/layout/TwoColPageLayout.tsx @@ -3,10 +3,13 @@ import { PageContainer, PageContainerProps } from '@ant-design/pro-components' import { Flexbox } from 'react-layout-kit' import { DraggablePanel, DraggablePanelProps } from '@/components/draggable-panel' import { useStyle } from './style' -import { useAtomValue } from 'jotai/index' +import { useAtom } from 'jotai/index' import { currentMenuAtom } from '@/store/system.ts' import useResizeObserver from '@/hooks/useResizeObserver.ts' import useInlineStyle from '@/hooks/useInlineStyle.ts' +import { useNavigate } from '@tanstack/react-router' +import { Space } from 'antd' +import { ArrowLeftOutlined } from '@ant-design/icons' interface ITreePageLayoutProps { children?: React.ReactNode @@ -18,7 +21,8 @@ interface ITreePageLayoutProps { export const TwoColPageLayout: React.FC = ({ className, ...props }) => { const { styles, cx } = useStyle({ className: 'two-col' }) - const currentMenu = useAtomValue(currentMenuAtom) + const navigate = useNavigate() + const [ currentMenu, setCurrentMenu ] = useAtom(currentMenuAtom) const [ , headerSize ] = useResizeObserver({ selector: '.ant-page-header', }) @@ -33,7 +37,21 @@ export const TwoColPageLayout: React.FC = ({ className, .. return ( + { + currentMenu?.parent && { + navigate({ + to: currentMenu?.parent?.path, + }).then(() => { + setCurrentMenu(currentMenu.parent!) + }) + }}> + } + {currentMenu?.title} + + } className={cx(styles.container, styles.pageCard, styles.layoutTable, className)} {...props.pageProps} > diff --git a/src/layout/style.ts b/src/layout/style.ts index 6cb0c94..256b438 100644 --- a/src/layout/style.ts +++ b/src/layout/style.ts @@ -121,6 +121,7 @@ export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any) padding-block-end: 0; max-height: 50px; overflow: hidden; + justify-content: center; } .ant-pro-layout-content, .ant-pro-layout-container{ @@ -128,6 +129,23 @@ export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any) overflow: hidden; height: 100vh; } + + .ant-pro-page-container .ant-pro-page-container-warp-page-header{ + padding-inline: 30px; + + .black{ + cursor: pointer; + background-color: transparent; + outline: none; + transition: color 0.3s; + .anticon { + transition: all 0.2s; + &:hover { + transform: scale(1.3); + } + } + } + } ` diff --git a/src/pages/system/logs/login/index.tsx b/src/pages/system/logs/login/index.tsx index 30b8fe1..913abfe 100644 --- a/src/pages/system/logs/login/index.tsx +++ b/src/pages/system/logs/login/index.tsx @@ -9,9 +9,10 @@ import { useAtom, useAtomValue } from 'jotai' import { Table as ProTable } from '@/components/table' import { useTranslation } from '@/i18n.ts' -import { Button, Space, Table, Popconfirm } from 'antd' +import { Space, Table } from 'antd' import { deleteLoginLogAtom, loginLogPageAtom, loginLogsAtom, loginLogSearchAtom } from '@/store/system/logs.ts' import ListPageLayout from '@/layout/ListPageLayout.tsx' +import Popconfirm from '@/components/popconfirm' const LoginLog = memo(() => { @@ -97,9 +98,7 @@ const LoginLog = memo(() => { selectedRowKeys: ids, selections: [ Table.SELECTION_ALL, Table.SELECTION_INVERT ], }} - scroll={{ - - }} + scroll={{}} tableAlertOptionRender={() => { return ( @@ -107,9 +106,9 @@ const LoginLog = memo(() => { onConfirm={() => { deleteLog(ids) }} + disabled={isDeleting} title={t('message.batchDelete')}> - + <>{t('actions.batchDel')} ) diff --git a/src/pages/system/roles/index.tsx b/src/pages/system/roles/index.tsx index b559a4e..bb6b5f9 100644 --- a/src/pages/system/roles/index.tsx +++ b/src/pages/system/roles/index.tsx @@ -20,11 +20,12 @@ import { searchAtom } from '@/store/system/role.ts' import { useTranslation } from '@/i18n.ts' -import { Button, Form, Space, Spin, Table, Tree, Popconfirm } from 'antd' +import { Button, Divider, Form, Space, Spin, Table, Tree } from 'antd' import { PlusOutlined } from '@ant-design/icons' import { menuDataAtom } from '@/store/system/menu.ts' import { getTreeCheckedStatus } from '@/utils/tree.ts' import ListPageLayout from '@/layout/ListPageLayout.tsx' +import Popconfirm from '@/components/popconfirm' const MenuTree = (props: any) => { const { data: menuList, isLoading: menuLoading } = useAtomValue(menuDataAtom) @@ -122,15 +123,16 @@ const Roles = memo(() => { > {t('actions.edit', '编辑')} , + , { deleteRole([ record.id ]) }} title={t('message.deleteConfirm')}> - + <> {t('actions.delete', '删除')} - + , ], diff --git a/src/pages/system/users/index.tsx b/src/pages/system/users/index.tsx index 493c3c8..d2bbb3a 100644 --- a/src/pages/system/users/index.tsx +++ b/src/pages/system/users/index.tsx @@ -7,7 +7,7 @@ import { ProFormColumnsType, ProTable } from '@ant-design/pro-components' -import { Button, Form, Popconfirm } from 'antd' +import { Button, Divider, Form } from 'antd' import { PlusOutlined } from '@ant-design/icons' import { useTranslation } from '@/i18n.ts' import DepartmentTree from '@/components/department-tree/DepartmentTree.tsx' @@ -24,6 +24,7 @@ import { useMemo, useRef, useState } from 'react' import Switch from '@/components/switch' import { DepartmentCascader } from '@/components/department-tree' import RolePicker from '@/components/role-picker/RolePicker.tsx' +import Popconfirm from '@/components/popconfirm' const Users = () => { @@ -113,6 +114,7 @@ const Users = () => { > {t('actions.edit', '编辑')} , + , { }) }}> }> - + <> {t('actions.resetPass', '重置密码')} - + , + , { deleteUser([ record.id ]) }} title={t('message.deleteConfirm')}> - + <> {t('actions.delete', '删除')} - + , ], diff --git a/src/pages/websites/account/index.tsx b/src/pages/websites/account/index.tsx index 5b3b491..bfbdeed 100644 --- a/src/pages/websites/account/index.tsx +++ b/src/pages/websites/account/index.tsx @@ -1,5 +1,5 @@ import { useTranslation } from '../../../i18n.ts' -import { Button, Form, Popconfirm, Divider, Space, Tooltip, Badge } from 'antd' +import { Button, Form, Space, Tooltip, Badge, Divider } from 'antd' import { useAtom, useAtomValue } from 'jotai' import { deleteWebsiteDnsAccountAtom, @@ -17,8 +17,10 @@ import { useStyle } from './style.ts' import { FilterOutlined } from '@ant-design/icons' import { getValueCount } from '@/utils' import { Table as ProTable } from '@/components/table' -import {DNSTypeEnum, DNSTypes, syncDNSAtom} from "@/store/websites/dns.ts"; -import {WebSite} from "@/types"; +import { DNSTypeEnum, DNSTypes, syncDNSAtom } from '@/store/websites/dns.ts' +import { WebSite } from '@/types' +import Switch from '@/components/switch' +import Popconfirm from '@/components/popconfirm' const i18nPrefix = 'websiteDnsAccounts.list' const getKeyColumn = (type: string, t) => { @@ -28,14 +30,14 @@ const getKeyColumn = (type: string, t) => { columns.push(...[ { title: t('website.ssl.dns.columns.accessKey', 'Access Key'), - dataIndex: 'accessKey', + dataIndex: [ 'authorization', 'accessKey' ], formItemProps: { rules: [ { required: true, message: t('message.required') } ] } }, { title: t('website.ssl.dns.columns.secretKey', 'Secret Key'), - dataIndex: 'secretKey', + dataIndex: [ 'authorization', 'secretKey' ], formItemProps: { rules: [ { required: true, message: t('message.required') } ] } @@ -47,13 +49,13 @@ const getKeyColumn = (type: string, t) => { columns.push(...[ { title: t('website.ssl.dns.columns.secretID', 'Secret ID'), - dataIndex: 'secretID', + dataIndex: [ 'authorization', 'secretID' ], formItemProps: { rules: [ { required: true, message: t('message.required') } ] } }, { title: t('website.ssl.dns.columns.secretKey', 'Secret Key'), - dataIndex: 'secretKey', + dataIndex: [ 'authorization', 'secretKey' ], formItemProps: { rules: [ { required: true, message: t('message.required') } ] } @@ -65,13 +67,13 @@ const getKeyColumn = (type: string, t) => { columns.push(...[ { title: t('website.ssl.dns.columns.apiId', 'ID'), - dataIndex: 'apiId', + dataIndex: [ 'authorization', 'apiId' ], formItemProps: { rules: [ { required: true, message: t('message.required') } ] } }, { title: t('website.ssl.dns.columns.token', 'Token'), - dataIndex: 'token', + dataIndex: [ 'authorization', 'token' ], formItemProps: { rules: [ { required: true, message: t('message.required') } ] } @@ -83,13 +85,13 @@ const getKeyColumn = (type: string, t) => { columns.push(...[ { title: t('website.ssl.dns.columns.email', 'Email'), - dataIndex: 'email', + dataIndex: [ 'authorization', 'email' ], formItemProps: { rules: [ { required: true, message: t('message.required') } ] } }, { title: t('website.ssl.dns.columns.apiKey', 'API ToKen'), - dataIndex: 'apiKey', + dataIndex: [ 'authorization', 'apiKey' ], formItemProps: { rules: [ { required: true, message: t('message.required') } ] } @@ -103,7 +105,7 @@ const getKeyColumn = (type: string, t) => { case DNSTypeEnum.NameSilo: columns.push({ title: t('website.ssl.dns.columns.apiKey', 'API Key'), - dataIndex: 'apiKey', + dataIndex: [ 'authorization', 'apiKey' ], formItemProps: { rules: [ { required: true, message: t('message.required') } ] } @@ -112,7 +114,7 @@ const getKeyColumn = (type: string, t) => { if (type === DNSTypeEnum.NameCheap) { columns.push({ title: t('website.ssl.dns.columns.apiUser', 'API User'), - dataIndex: 'apiUser', + dataIndex: [ 'authorization', 'apiUser' ], formItemProps: { rules: [ { required: true, message: t('message.required') } ] } @@ -120,7 +122,7 @@ const getKeyColumn = (type: string, t) => { } else if (type === DNSTypeEnum.Godaddy) { columns.push({ title: t('website.ssl.dns.columns.apiSecret', 'API Secret'), - dataIndex: 'apiSecret', + dataIndex: [ 'authorization', 'apiSecret' ], formItemProps: { rules: [ { required: true, message: t('message.required') } ] } @@ -131,14 +133,14 @@ const getKeyColumn = (type: string, t) => { columns.push( { title: t('website.ssl.dns.columns.apiUser', 'UserName'), - dataIndex: 'apiUser', + dataIndex: [ 'authorization', 'apiUser' ], formItemProps: { rules: [ { required: true, message: t('message.required') } ] } }, { title: t('website.ssl.dns.columns.token', 'Token'), - dataIndex: 'token', + dataIndex: [ 'authorization', 'token' ], formItemProps: { rules: [ { required: true, message: t('message.required') } ] } @@ -177,29 +179,51 @@ const WebsiteDnsAccount = () => { hideInSearch: true, formItemProps: { hidden: true } }, - { - title: t(`${i18nPrefix}.columns.name`, '名称'), - dataIndex: 'name', - valueType: 'text', - formItemProps: { - rules: [ - { required: true, message: t('message.required', '请输入') } - ] - } - }, - { - title: t(`${i18nPrefix}.columns.type`, '类型'), - dataIndex: 'type', - valueType: 'select', - fieldProps: { - options: DNSTypes - }, - formItemProps: { - rules: [ - { required: true, message: t('message.required', '请选择') } - ] - }, - }, + { + title: t(`${i18nPrefix}.columns.name`, '名称'), + dataIndex: 'name', + valueType: 'text', + width: 250, + fieldProps: { + style: { + width: '100%' + } + }, + formItemProps: { + rules: [ + { required: true, message: t('message.required', '请输入') } + ] + } + }, + { + title: t(`${i18nPrefix}.columns.name`, '标签'), + dataIndex: 'tag', + valueType: 'text', + hideInForm: true, + width: 200, + fieldProps: { + style: { + width: '100%' + } + } + }, + { + title: t(`${i18nPrefix}.columns.type`, '类型'), + dataIndex: 'type', + valueType: 'select', + width: 200, + fieldProps: { + style: { + width: '100%' + }, + options: DNSTypes + }, + formItemProps: { + rules: [ + { required: true, message: t('message.required', '请选择') } + ] + }, + }, { name: [ 'type' ], valueType: 'dependency', @@ -209,13 +233,19 @@ const WebsiteDnsAccount = () => { return getKeyColumn(type, t) } }, - { - title: t(`${i18nPrefix}.columns.status`, '状态'), - dataIndex: 'status', - }, + { + title: t(`${i18nPrefix}.columns.status`, '状态'), + dataIndex: 'status', + valueType: 'switch', + width: 200, + render(_dom, record) { + return + } + }, { title: t(`${i18nPrefix}.columns.option`, '操作'), key: 'option', + width: 300, valueType: 'option', fixed: 'right', render: (_, record) => [ @@ -223,20 +253,24 @@ const WebsiteDnsAccount = () => { as={'a'} disabled={record.status === 2} onClick={() => { + record.status = record.status > 0 + if (typeof record.authorization === 'string') { + record.authorization = JSON.parse(record.authorization) + } form.setFieldsValue(record) setOpen(true) }}>{t('actions.edit')}, + , { asyncDNS(record) }} - title={t('message.deleteConfirm')}> - - {t('actions.sync', '同步')} - + title={t('message.syncConfirm', '您确定要同步吗?')}> + {t('actions.sync', '同步')} , + , { deleteWebsiteDnsAccount([ record.id ]) }} title={t('message.deleteConfirm')}> - - {t('actions.delete', '删除')} - + {t('actions.delete', '删除')} ] } @@ -270,7 +302,19 @@ const WebsiteDnsAccount = () => { + + + } toolbar={{ search: { loading: isFetching && !!search?.title, @@ -298,25 +342,17 @@ const WebsiteDnsAccount = () => { , , - ] }} scroll={{ - x: 2500, y: 'calc(100vh - 290px)' + // x: 2500, + y: 'calc(100vh - 290px)' }} search={false} onRow={(record) => { return { className: cx({ - 'ant-table-row-selected': currentWebsiteDnsAccount?.id === record.id + // 'ant-table-row-selected': currentWebsiteDnsAccount?.id === record.id }), onClick: () => { setWebsiteDnsAccount(record) @@ -375,9 +411,11 @@ const WebsiteDnsAccount = () => { // // }} onFinish={async (values) => { + values.status = values.status ? 1 : 0 saveOrUpdate(values) }} columns={columns as ProFormColumnsType[]}/> + { }} columns={columns.filter(item => !item.hideInSearch) as ProFormColumnsType[]}/> + ) } diff --git a/src/pages/websites/domain/index.tsx b/src/pages/websites/domain/index.tsx index 6be4440..7f513c6 100644 --- a/src/pages/websites/domain/index.tsx +++ b/src/pages/websites/domain/index.tsx @@ -1,5 +1,5 @@ import { useTranslation } from '@/i18n.ts' -import { Button, Form, Popconfirm, Divider, Space, Tooltip, Badge } from 'antd' +import { Button, Form, Divider, Space, Tooltip, Badge } from 'antd' import { useAtom, useAtomValue } from 'jotai' import { deleteWebsiteDomainAtom, @@ -14,10 +14,11 @@ import { } from '@ant-design/pro-components' import ListPageLayout from '@/layout/ListPageLayout.tsx' import { useStyle } from './style' -import { FilterOutlined } from '@ant-design/icons' +import { FilterOutlined } from '@ant-design/icons' import { getValueCount } from '@/utils' import { Table as ProTable } from '@/components/table' import { Link } from '@tanstack/react-router' +import Popconfirm from '@/components/popconfirm' const i18nPrefix = 'websiteDomains.list' @@ -46,25 +47,25 @@ const WebsiteDomain = () => { hideInSearch: true, formItemProps: { hidden: true } }, - { - title: t(`${i18nPrefix}.columns.name`, '域名'), - dataIndex: 'name', - render(_text, record){ - return {record.name} - } - }, - { - title: t(`${i18nPrefix}.columns.dns_account_id`, 'DNS账号'), - dataIndex: 'dns_account_id', - }, - { - title: t(`${i18nPrefix}.columns.status`, '状态'), - dataIndex: 'status', - }, - { - title: t(`${i18nPrefix}.columns.nameservers`, 'nameservers'), - dataIndex: 'nameservers', - }, + { + title: t(`${i18nPrefix}.columns.name`, '域名'), + dataIndex: 'name', + render(_text, record) { + return {record.name} + } + }, + { + title: t(`${i18nPrefix}.columns.dns_account_id`, 'DNS账号'), + dataIndex: 'dns_account_id', + }, + { + title: t(`${i18nPrefix}.columns.status`, '状态'), + dataIndex: 'status', + }, + { + title: t(`${i18nPrefix}.columns.nameservers`, 'nameservers'), + dataIndex: 'nameservers', + }, { title: t(`${i18nPrefix}.columns.created`, '创建时间'), dataIndex: 'created', @@ -85,6 +86,7 @@ const WebsiteDomain = () => { form.setFieldsValue(record) setOpen(true) }}>{t('actions.edit')}, + , { deleteWebsiteDomain([ record.id ]) }} title={t('message.deleteConfirm')}> - - {t('actions.delete', '删除')} - + {t('actions.delete', '删除')} ] } @@ -118,7 +118,19 @@ const WebsiteDomain = () => { + + + } toolbar={{ search: { loading: isFetching && !!search?.title, @@ -146,25 +158,18 @@ const WebsiteDomain = () => { , , - + ] }} scroll={{ - x: 2500, y: 'calc(100vh - 290px)' + // x: 2500, + y: 'calc(100vh - 290px)' }} search={false} onRow={(record) => { return { className: cx({ - 'ant-table-row-selected': currentWebsiteDomain?.id === record.id + // 'ant-table-row-selected': currentWebsiteDomain?.id === record.id }), onClick: () => { setWebsiteDomain(record) diff --git a/src/pages/websites/record/index.tsx b/src/pages/websites/record/index.tsx index 13c2d10..e77e438 100644 --- a/src/pages/websites/record/index.tsx +++ b/src/pages/websites/record/index.tsx @@ -1,5 +1,5 @@ import { useTranslation } from '@/i18n.ts' -import { Button, Form, Popconfirm, Divider, Space, Tooltip, Badge } from 'antd' +import { Button, Form, Divider, Space, Tooltip, Badge } from 'antd' import { useAtom, useAtomValue } from 'jotai' import { deleteWebsiteDnsRecordsAtom, @@ -17,6 +17,7 @@ import { useStyle } from './style' import { FilterOutlined } from '@ant-design/icons' import { getValueCount } from '@/utils' import { Table as ProTable } from '@/components/table' +import Popconfirm from '@/components/popconfirm' const i18nPrefix = 'websiteDnsRecordss.list' @@ -45,66 +46,66 @@ const WebsiteDnsRecords = () => { hideInSearch: true, formItemProps: { hidden: true } }, - { - title: t(`${i18nPrefix}.columns.record_id`, 'record_id'), - dataIndex: 'record_id', - }, - - { - title: t(`${i18nPrefix}.columns.domain_id`, 'domain_id'), - dataIndex: 'domain_id', - }, - - { - title: t(`${i18nPrefix}.columns.name`, 'name'), - dataIndex: 'name', - }, - - { - title: t(`${i18nPrefix}.columns.content`, 'content'), - dataIndex: 'content', - }, - - { - title: t(`${i18nPrefix}.columns.poxy`, 'poxy'), - dataIndex: 'poxy', - }, - - { - title: t(`${i18nPrefix}.columns.ttl`, 'ttl'), - dataIndex: 'ttl', - }, - - { - title: t(`${i18nPrefix}.columns.type`, 'type'), - dataIndex: 'type', - }, - - { - title: t(`${i18nPrefix}.columns.status`, 'status'), - dataIndex: 'status', - }, - - { - title: t(`${i18nPrefix}.columns.tag`, 'tag'), - dataIndex: 'tag', - }, - - { - title: t(`${i18nPrefix}.columns.remark`, 'remark'), - dataIndex: 'remark', - }, - - { - title: t(`${i18nPrefix}.columns.created`, 'created'), - dataIndex: 'created', - }, - - { - title: t(`${i18nPrefix}.columns.modified`, 'modified'), - dataIndex: 'modified', - }, - + { + title: t(`${i18nPrefix}.columns.record_id`, 'record_id'), + dataIndex: 'record_id', + }, + + { + title: t(`${i18nPrefix}.columns.domain_id`, 'domain_id'), + dataIndex: 'domain_id', + }, + + { + title: t(`${i18nPrefix}.columns.name`, 'name'), + dataIndex: 'name', + }, + + { + title: t(`${i18nPrefix}.columns.content`, 'content'), + dataIndex: 'content', + }, + + { + title: t(`${i18nPrefix}.columns.poxy`, 'poxy'), + dataIndex: 'poxy', + }, + + { + title: t(`${i18nPrefix}.columns.ttl`, 'ttl'), + dataIndex: 'ttl', + }, + + { + title: t(`${i18nPrefix}.columns.type`, 'type'), + dataIndex: 'type', + }, + + { + title: t(`${i18nPrefix}.columns.status`, 'status'), + dataIndex: 'status', + }, + + { + title: t(`${i18nPrefix}.columns.tag`, 'tag'), + dataIndex: 'tag', + }, + + { + title: t(`${i18nPrefix}.columns.remark`, 'remark'), + dataIndex: 'remark', + }, + + { + title: t(`${i18nPrefix}.columns.created`, 'created'), + dataIndex: 'created', + }, + + { + title: t(`${i18nPrefix}.columns.modified`, 'modified'), + dataIndex: 'modified', + }, + { title: t(`${i18nPrefix}.columns.option`, '操作'), key: 'option', @@ -117,6 +118,7 @@ const WebsiteDnsRecords = () => { form.setFieldsValue(record) setOpen(true) }}>{t('actions.edit')}, + , { deleteWebsiteDnsRecords([ record.id ]) }} title={t('message.deleteConfirm')}> - - {t('actions.delete', '删除')} - + {t('actions.delete', '删除')} ] } @@ -150,7 +150,19 @@ const WebsiteDnsRecords = () => { + + + } toolbar={{ search: { loading: isFetching && !!search?.title, @@ -178,25 +190,18 @@ const WebsiteDnsRecords = () => { , , - + ] }} scroll={{ - x: 2500, y: 'calc(100vh - 290px)' + x: 2000, + y: 'calc(100vh - 290px)' }} search={false} onRow={(record) => { return { className: cx({ - 'ant-table-row-selected': currentWebsiteDnsRecords?.id === record.id + // 'ant-table-row-selected': currentWebsiteDnsRecords?.id === record.id }), onClick: () => { setWebsiteDnsRecords(record) diff --git a/src/routes.tsx b/src/routes.tsx index d60395a..50d7955 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -334,7 +334,7 @@ export const RootProvider = memo((props: { context: Partial }) => // history: hashHistory, context: { queryClient, menuData: [] }, defaultPreload: 'intent', - defaultPendingComponent: () => + defaultPendingComponent: () => }) diff --git a/src/store/system.ts b/src/store/system.ts index e451325..3a1b4d0 100644 --- a/src/store/system.ts +++ b/src/store/system.ts @@ -1,9 +1,7 @@ -import { IAppData } from '@/global' -import { createStore } from 'jotai' +import { IAppData, MenuItem } from '@/global' +import { createStore, atom } from 'jotai' import { atomWithStorage } from 'jotai/utils' import { changeLanguage as setLang } from 'i18next' -import { atom } from 'jotai/index' -import { System } from '@/types' /** * app全局状态 @@ -26,7 +24,7 @@ export const getAppData = () => { return appStore.get(appAtom) } -export const currentMenuAtom = atom(null) +export const currentMenuAtom = atom(null) export const changeLanguage = (lang: string, reload?: boolean) => { diff --git a/src/types/system/menus.d.ts b/src/types/system/menus.d.ts index e33597d..9d55cda 100644 --- a/src/types/system/menus.d.ts +++ b/src/types/system/menus.d.ts @@ -28,6 +28,7 @@ export interface IMenu { status: string, parent_path: string, affix: boolean, + active: string, hidden: boolean, hidden_breadcrumb: boolean, redirect: string,