dark
4 months ago
11 changed files with 364 additions and 27 deletions
-
53src/App.css
-
96src/pages/websites/domain/components/NameServer.tsx
-
15src/pages/websites/domain/components/style.ts
-
8src/service/website/domain_group.ts
-
23src/service/websites.ts
-
2src/store/websites/dns_account.ts
-
82src/store/websites/domain.ts
-
90src/store/websites/domain_groups.ts
-
6src/theme/index.ts
-
7src/types/website/domain.d.ts
-
9src/types/website/domain_group.d.ts
@ -0,0 +1,96 @@ |
|||||
|
import { INameServer, IWebsiteDomain } from '@/types/website/domain' |
||||
|
import { Typography, Popover, Table } from 'antd' |
||||
|
import { memo, useCallback, useMemo } from 'react' |
||||
|
import { useAtomValue } from 'jotai' |
||||
|
import { describeDomainNSAtom } from '@/store/websites/domain.ts' |
||||
|
import { |
||||
|
CheckCircleFilled, |
||||
|
CheckCircleOutlined, |
||||
|
ExclamationCircleFilled, |
||||
|
ExclamationCircleOutlined, |
||||
|
LoadingOutlined |
||||
|
} from '@ant-design/icons' |
||||
|
|
||||
|
export interface NameServerProps { |
||||
|
data: IWebsiteDomain |
||||
|
} |
||||
|
|
||||
|
interface FormattedDnsData { |
||||
|
expectDnsServers: string; |
||||
|
dnsServers: string; |
||||
|
} |
||||
|
|
||||
|
function formatNameServerData(data?: INameServer) { |
||||
|
|
||||
|
if (!data) { |
||||
|
return [] |
||||
|
} |
||||
|
|
||||
|
const formattedData: FormattedDnsData[] = [] |
||||
|
const maxLength = Math.max(data.expectDnsServers.length, data.dnsServers.length) |
||||
|
|
||||
|
for (let i = 0; i < maxLength; i++) { |
||||
|
formattedData.push({ |
||||
|
expectDnsServers: data.expectDnsServers[i] || '', |
||||
|
dnsServers: data.dnsServers[i] || '', |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
return formattedData |
||||
|
} |
||||
|
|
||||
|
const NameServer = memo(({ data }: NameServerProps) => { |
||||
|
|
||||
|
const { data: result, isFetching } = useAtomValue(useMemo(() => describeDomainNSAtom(data?.id), [])) |
||||
|
|
||||
|
const columns = [ |
||||
|
{ |
||||
|
title: '当前DNS', |
||||
|
dataIndex: 'dnsServers' |
||||
|
}, |
||||
|
{ |
||||
|
title: '系统分配DNS', |
||||
|
dataIndex: 'expectDnsServers', |
||||
|
render: (text: string) => { |
||||
|
return <Typography.Text copyable={{ text }}>{text}</Typography.Text> |
||||
|
} |
||||
|
}, |
||||
|
] |
||||
|
|
||||
|
const content = useCallback(() => { |
||||
|
return ( |
||||
|
<Table columns={columns} |
||||
|
style={{ width: 300}} |
||||
|
dataSource={formatNameServerData(result)} |
||||
|
pagination={false} |
||||
|
bordered={true} |
||||
|
size={'small'} |
||||
|
/> |
||||
|
) |
||||
|
}, [ result ]) |
||||
|
|
||||
|
const title = useCallback(() => { |
||||
|
if (result?.success) |
||||
|
return <span><CheckCircleFilled className={'color-green'} style={{ paddingInlineEnd: 5 }}/>域名的DNS信息配置正确。</span> |
||||
|
|
||||
|
return <span><ExclamationCircleFilled className={'color-yellow'} style={{ paddingInlineEnd: 5 }}/>探测超时,请稍后查看。</span> |
||||
|
}, [ result ]) |
||||
|
|
||||
|
if (data?.nameservers?.length === 0) { |
||||
|
return null |
||||
|
} |
||||
|
|
||||
|
return ( |
||||
|
<Popover content={content()} title={title()} trigger="hover"> |
||||
|
{isFetching ? <LoadingOutlined/> : null} |
||||
|
{ |
||||
|
result?.success ? |
||||
|
<span className={'color-green'}><CheckCircleOutlined style={{ paddingInlineEnd: 5 }}/>正常</span> |
||||
|
: <span className={'color-yellow'}><ExclamationCircleOutlined |
||||
|
style={{ paddingInlineEnd: 5 }}/>{result?.message || '探测超时'}</span> |
||||
|
} |
||||
|
</Popover> |
||||
|
) |
||||
|
}) |
||||
|
|
||||
|
export default NameServer |
@ -0,0 +1,15 @@ |
|||||
|
import { createStyles } from '@/theme' |
||||
|
|
||||
|
export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any) => { |
||||
|
const prefix = `${prefixCls}-${token?.proPrefix}-name-server-component` |
||||
|
|
||||
|
const container = css`
|
||||
|
.green { |
||||
|
color: green; |
||||
|
} |
||||
|
`
|
||||
|
|
||||
|
return { |
||||
|
container: cx(prefix, props?.className, container), |
||||
|
} |
||||
|
}) |
@ -0,0 +1,8 @@ |
|||||
|
import { createCURD } from '@/service/base.ts' |
||||
|
import { WebSite } from '@/types/website/domain_group' |
||||
|
|
||||
|
const domain_group = { |
||||
|
...createCURD<any, WebSite.IDomainGroup >('/website/group'), |
||||
|
} |
||||
|
|
||||
|
export default domain_group |
@ -0,0 +1,90 @@ |
|||||
|
import { atom } from 'jotai' |
||||
|
import { IApiResult, IPage } from '@/global' |
||||
|
import { atomWithMutation, atomWithQuery, queryClientAtom } from 'jotai-tanstack-query' |
||||
|
import { message } from 'antd' |
||||
|
import { t } from 'i18next' |
||||
|
import { WebSite } from '@/types/website/domain_group' |
||||
|
import webSiteServ from '@/service/website/domain_group' |
||||
|
|
||||
|
type SearchParams = IPage & { |
||||
|
key?: string |
||||
|
|
||||
|
[key: string]: any |
||||
|
} |
||||
|
|
||||
|
export const domainGroupIdAtom = atom(0) |
||||
|
|
||||
|
export const domainGroupIdsAtom = atom<number[]>([]) |
||||
|
|
||||
|
export const domainGroupAtom = atom<WebSite.IDomainGroup>(undefined as unknown as WebSite.IDomainGroup ) |
||||
|
|
||||
|
export const domainGroupSearchAtom = atom<SearchParams>({ |
||||
|
key: '', |
||||
|
pageSize: 10, |
||||
|
page: 1, |
||||
|
} as SearchParams) |
||||
|
|
||||
|
export const domainGroupPageAtom = atom<IPage>({ |
||||
|
pageSize: 10, |
||||
|
page: 1, |
||||
|
}) |
||||
|
|
||||
|
export const domainGroupsAtom = atomWithQuery((get) => { |
||||
|
return { |
||||
|
queryKey: [ 'domainGroups', get(domainGroupSearchAtom) ], |
||||
|
queryFn: async ({ queryKey: [ , params ] }) => { |
||||
|
return await webSiteServ.list(params as SearchParams) |
||||
|
}, |
||||
|
select: res => { |
||||
|
const data = res.data |
||||
|
data.rows = data.rows?.map(row => { |
||||
|
return { |
||||
|
...row, |
||||
|
//status: convertToBool(row.status)
|
||||
|
} |
||||
|
}) |
||||
|
return data |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
//saveOrUpdateAtom
|
||||
|
export const saveOrUpdateDomainGroupAtom = atomWithMutation<IApiResult, WebSite.IDomainGroup>((get) => { |
||||
|
|
||||
|
return { |
||||
|
mutationKey: [ 'updateDomainGroup' ], |
||||
|
mutationFn: async (data) => { |
||||
|
//data.status = data.status ? '1' : '0'
|
||||
|
if (data.id === 0) { |
||||
|
return await webSiteServ.add(data) |
||||
|
} |
||||
|
return await webSiteServ.update(data) |
||||
|
}, |
||||
|
onSuccess: (res) => { |
||||
|
const isAdd = !!res.data?.id |
||||
|
message.success(t(isAdd ? 'message.saveSuccess' : 'message.editSuccess', '保存成功')) |
||||
|
|
||||
|
//更新列表
|
||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
|
// @ts-ignore fix
|
||||
|
get(queryClientAtom).invalidateQueries({ queryKey: [ 'domainGroups', get(domainGroupSearchAtom) ] }) |
||||
|
|
||||
|
return res |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
export const deleteDomainGroupAtom = atomWithMutation((get) => { |
||||
|
return { |
||||
|
mutationKey: [ 'deleteDomainGroup' ], |
||||
|
mutationFn: async (ids: number[]) => { |
||||
|
return await webSiteServ.batchDelete(ids ?? get(domainGroupIdsAtom)) |
||||
|
}, |
||||
|
onSuccess: (res) => { |
||||
|
message.success('message.deleteSuccess') |
||||
|
//更新列表
|
||||
|
get(queryClientAtom).invalidateQueries({ queryKey: [ 'domainGroups', get(domainGroupSearchAtom) ] }) |
||||
|
return res |
||||
|
} |
||||
|
} |
||||
|
}) |
@ -0,0 +1,9 @@ |
|||||
|
export namespace WebSite { |
||||
|
export interface IDomainGroup { |
||||
|
id: number; |
||||
|
user_id: number; |
||||
|
sort: number; |
||||
|
name: string; |
||||
|
created_at: string; |
||||
|
} |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue