Browse Source

完善SSL模块

main
dark 6 months ago
parent
commit
1410a36ba4
  1. 17
      src/pages/websites/ssl/components/AcmeList.tsx
  2. 25
      src/pages/websites/ssl/components/CAList.tsx
  3. 295
      src/pages/websites/ssl/components/DNSList.tsx
  4. 19
      src/pages/websites/ssl/index.tsx
  5. 41
      src/store/websites/dns.ts

17
src/pages/websites/ssl/components/AcmeList.tsx

@ -4,8 +4,9 @@ import { IAcmeAccount } from '@/types/website/acme'
import { useTranslation } from '@/i18n.ts' import { useTranslation } from '@/i18n.ts'
import { AcmeAccountTypes, acmeListAtom, acmePageAtom, AcmeType, saveOrUpdateAcmeAtom } from '@/store/websites/acme.ts' import { AcmeAccountTypes, acmeListAtom, acmePageAtom, AcmeType, saveOrUpdateAcmeAtom } from '@/store/websites/acme.ts'
import { useAtom, useAtomValue } from 'jotai' import { useAtom, useAtomValue } from 'jotai'
import { Alert, Button, Form } from 'antd'
import { Alert, Button, Form, Popconfirm } from 'antd'
import { KeyTypeEnum, KeyTypes } from '@/store/websites/ssl.ts' import { KeyTypeEnum, KeyTypes } from '@/store/websites/ssl.ts'
import { deleteDNSAtom } from '@/store/websites/dns.ts'
const AcmeList = () => { const AcmeList = () => {
@ -14,6 +15,7 @@ const AcmeList = () => {
const [ page, setPage ] = useAtom(acmePageAtom) const [ page, setPage ] = useAtom(acmePageAtom)
const { data, isLoading, refetch } = useAtomValue(acmeListAtom) const { data, isLoading, refetch } = useAtomValue(acmeListAtom)
const { mutate: saveOrUpdate, isPending: isSubmitting, isSuccess } = useAtomValue(saveOrUpdateAcmeAtom) const { mutate: saveOrUpdate, isPending: isSubmitting, isSuccess } = useAtomValue(saveOrUpdateAcmeAtom)
const { mutate: deleteDNS, isPending: isDeleting } = useAtomValue(deleteDNSAtom)
const [ open, setOpen ] = useState(false) const [ open, setOpen ] = useState(false)
const columns = useMemo<ProColumns<IAcmeAccount>[]>(() => { const columns = useMemo<ProColumns<IAcmeAccount>[]>(() => {
@ -73,8 +75,17 @@ const AcmeList = () => {
valueType: 'option', valueType: 'option',
render: (_, record) => { render: (_, record) => {
return [ return [
<a key="delete" onClick={() => {
}}>{t('actions.delete', '删除')}</a>,
<Popconfirm
key={'del_confirm'}
disabled={isDeleting}
onConfirm={() => {
deleteDNS(record.id)
}}
title={t('message.deleteConfirm')}>
<a key="del">
{t('actions.delete', '删除')}
</a>
</Popconfirm>
] ]
} }
} }

25
src/pages/websites/ssl/components/CAList.tsx

@ -1,10 +1,10 @@
import { useMemo, useState } from 'react' import { useMemo, useState } from 'react'
import { BetaSchemaForm, ProColumns, ProFormColumnsType, ProTable } from '@ant-design/pro-components' import { BetaSchemaForm, ProColumns, ProFormColumnsType, ProTable } from '@ant-design/pro-components'
import { ICA, IcaAccount } from '@/types/website/ca'
import { ICA, } from '@/types/website/ca'
import { useTranslation } from '@/i18n.ts' import { useTranslation } from '@/i18n.ts'
import { caAccountTypes, caType } from '@/store/websites/ca.ts'
import { deleteCaAtom } from '@/store/websites/ca.ts'
import { useAtom, useAtomValue } from 'jotai' import { useAtom, useAtomValue } from 'jotai'
import { Alert, Button, Form } from 'antd'
import { Alert, Button, Form, Popconfirm } from 'antd'
import { KeyTypeEnum, KeyTypes } from '@/store/websites/ssl.ts' import { KeyTypeEnum, KeyTypes } from '@/store/websites/ssl.ts'
import { caListAtom, caPageAtom, saveOrUpdateCaAtom } from '@/store/websites/ca.ts' import { caListAtom, caPageAtom, saveOrUpdateCaAtom } from '@/store/websites/ca.ts'
@ -15,6 +15,7 @@ const CAList = () => {
const [ page, setPage ] = useAtom(caPageAtom) const [ page, setPage ] = useAtom(caPageAtom)
const { data, isLoading, refetch } = useAtomValue(caListAtom) const { data, isLoading, refetch } = useAtomValue(caListAtom)
const { mutate: saveOrUpdate, isPending: isSubmitting, isSuccess } = useAtomValue(saveOrUpdateCaAtom) const { mutate: saveOrUpdate, isPending: isSubmitting, isSuccess } = useAtomValue(saveOrUpdateCaAtom)
const { mutate: deleteCA, isPending: isDeleting } = useAtomValue(deleteCaAtom)
const [ open, setOpen ] = useState(false) const [ open, setOpen ] = useState(false)
const columns = useMemo<ProColumns<ICA>[]>(() => { const columns = useMemo<ProColumns<ICA>[]>(() => {
@ -63,8 +64,17 @@ const CAList = () => {
valueType: 'option', valueType: 'option',
render: (_, record) => { render: (_, record) => {
return [ return [
<a key="delete" onClick={() => {
}}>{t('actions.delete', '删除')}</a>,
<Popconfirm
key={'del_confirm'}
disabled={isDeleting}
onConfirm={() => {
deleteCA(record.id)
}}
title={t('message.deleteConfirm')}>
<a key="del">
{t('actions.delete', '删除')}
</a>
</Popconfirm>
] ]
} }
} }
@ -74,7 +84,7 @@ const CAList = () => {
return ( return (
<> <>
<Alert message={t('website.ssl.ca.tip', 'ca账户用于申请免费证书')}/> <Alert message={t('website.ssl.ca.tip', 'ca账户用于申请免费证书')}/>
<ProTable<IcaAccount>
<ProTable<ICA>
cardProps={{ cardProps={{
bodyStyle: { bodyStyle: {
padding: 0, padding: 0,
@ -86,7 +96,6 @@ const CAList = () => {
onClick={() => { onClick={() => {
form.setFieldsValue({ form.setFieldsValue({
id: 0, id: 0,
type: caType.LetsEncrypt,
keyType: KeyTypeEnum.EC256, keyType: KeyTypeEnum.EC256,
}) })
setOpen(true) setOpen(true)
@ -118,7 +127,7 @@ const CAList = () => {
}} }}
/> />
<BetaSchemaForm<IcaAccount>
<BetaSchemaForm<ICA>
shouldUpdate={false} shouldUpdate={false}
width={600} width={600}
form={form} form={form}

295
src/pages/websites/ssl/components/DNSList.tsx

@ -0,0 +1,295 @@
import { useMemo, useState } from 'react'
import { BetaSchemaForm, ProColumns, ProFormColumnsType, ProTable } from '@ant-design/pro-components'
import { useTranslation } from '@/i18n.ts'
import { useAtom, useAtomValue } from 'jotai'
import { Button, Form, Popconfirm } from 'antd'
import {
deleteDNSAtom,
dnsListAtom,
dnsPageAtom,
DNSTypeEnum,
DNSTypes,
saveOrUpdateDNSAtom
} from '@/store/websites/dns.ts'
import { IDnsAccount } from '@/types/website/dns'
const getKeyColumn = (type: string, t) => {
const columns: ProColumns<IDnsAccount>[] = []
switch (type) {
case DNSTypeEnum.AliYun: {
columns.push(...[
{
title: t('website.ssl.dns.columns.accessKey', 'Access Key'),
dataIndex: 'accessKey',
formItemProps: {
rules: [ { required: true, message: t('message.required') } ]
}
},
{
title: t('website.ssl.dns.columns.secretKey', 'Secret Key'),
dataIndex: 'secretKey',
formItemProps: {
rules: [ { required: true, message: t('message.required') } ]
}
},
])
}
break
case DNSTypeEnum.TencentCloud: {
columns.push(...[
{
title: t('website.ssl.dns.columns.secretID', 'Secret ID'),
dataIndex: 'secretID',
formItemProps: {
rules: [ { required: true, message: t('message.required') } ]
}
}, {
title: t('website.ssl.dns.columns.secretKey', 'Secret Key'),
dataIndex: 'secretKey',
formItemProps: {
rules: [ { required: true, message: t('message.required') } ]
}
},
])
break
}
case DNSTypeEnum.DnsPod: {
columns.push(...[
{
title: t('website.ssl.dns.columns.apiId', 'ID'),
dataIndex: 'apiId',
formItemProps: {
rules: [ { required: true, message: t('message.required') } ]
}
}, {
title: t('website.ssl.dns.columns.token', 'Token'),
dataIndex: 'token',
formItemProps: {
rules: [ { required: true, message: t('message.required') } ]
}
},
])
break
}
case DNSTypeEnum.CloudFlare: {
columns.push(...[
{
title: t('website.ssl.dns.columns.email', 'Email'),
dataIndex: 'email',
formItemProps: {
rules: [ { required: true, message: t('message.required') } ]
}
}, {
title: t('website.ssl.dns.columns.apiKey', 'API ToKen'),
dataIndex: 'apiKey',
formItemProps: {
rules: [ { required: true, message: t('message.required') } ]
}
},
]
)
break
}
case DNSTypeEnum.Godaddy:
case DNSTypeEnum.NameCheap:
case DNSTypeEnum.NameSilo:
columns.push({
title: t('website.ssl.dns.columns.apiKey', 'API Key'),
dataIndex: 'apiKey',
formItemProps: {
rules: [ { required: true, message: t('message.required') } ]
}
},
)
if (type === DNSTypeEnum.NameCheap) {
columns.push({
title: t('website.ssl.dns.columns.apiUser', 'API User'),
dataIndex: 'apiUser',
formItemProps: {
rules: [ { required: true, message: t('message.required') } ]
}
})
} else if (type === DNSTypeEnum.Godaddy) {
columns.push({
title: t('website.ssl.dns.columns.apiSecret', 'API Secret'),
dataIndex: 'apiSecret',
formItemProps: {
rules: [ { required: true, message: t('message.required') } ]
}
})
}
break
case DNSTypeEnum.NameCom: {
columns.push(
{
title: t('website.ssl.dns.columns.apiUser', 'UserName'),
dataIndex: 'apiUser',
formItemProps: {
rules: [ { required: true, message: t('message.required') } ]
}
},
{
title: t('website.ssl.dns.columns.token', 'Token'),
dataIndex: 'token',
formItemProps: {
rules: [ { required: true, message: t('message.required') } ]
}
}
)
break
}
default:
break
}
return columns
}
const DNSList = () => {
const { t } = useTranslation()
const [ form ] = Form.useForm()
const [ page, setPage ] = useAtom(dnsPageAtom)
const { data, isLoading, refetch } = useAtomValue(dnsListAtom)
const { mutate: saveOrUpdate, isPending: isSubmitting, isSuccess } = useAtomValue(saveOrUpdateDNSAtom)
const { mutate: deleteDNS, isPending: isDeleting } = useAtomValue(deleteDNSAtom)
const [ open, setOpen ] = useState(false)
const columns = useMemo<ProColumns<IDnsAccount>[]>(() => {
return [
{
title: 'ID',
dataIndex: 'id',
hideInTable: true,
formItemProps: {
hidden: true,
}
},
{
title: t('website.ssl.dns.columns.name', '名称'),
dataIndex: 'name',
valueType: 'text',
formItemProps: {
rules: [
{ required: true, message: t('message.required', '请输入') }
]
}
},
{
title: t('website.ssl.dns.columns.type', '类型'),
dataIndex: 'type',
valueType: 'select',
fieldProps: {
options: DNSTypes
},
formItemProps: {
rules: [
{ required: true, message: t('message.required', '请选择') }
]
},
},
{
name: [ 'type' ],
valueType: 'dependency',
columns: ({ type }) => {
return getKeyColumn(type, t)
}
},
{
title: '操作',
valueType: 'option',
render: (_, record) => {
return [
<Popconfirm
key={'del_confirm'}
disabled={isDeleting}
onConfirm={() => {
deleteDNS(record.id)
}}
title={t('message.deleteConfirm')}>
<a key="del">
{t('actions.delete', '删除')}
</a>
</Popconfirm>
]
}
}
]
}, [])
return (
<>
<ProTable<IDnsAccount>
cardProps={{
bodyStyle: {
padding: 0,
}
}}
rowKey="id"
headerTitle={
<Button
onClick={() => {
form.setFieldsValue({
id: 0,
type: DNSTypeEnum.DnsPod,
})
setOpen(true)
}}
type={'primary'}>{t('website.ssl.dns.add', '添加DNS帐户')}</Button>
}
loading={isLoading}
dataSource={data?.rows ?? []}
columns={columns}
search={false}
options={{
reload: () => {
refetch()
},
}}
pagination={{
total: data?.total,
pageSize: page.pageSize,
current: page.page,
onChange: (current, pageSize) => {
setPage(prev => {
return {
...prev,
page: current,
pageSize: pageSize,
}
})
},
}}
/>
<BetaSchemaForm<IDnsAccount>
shouldUpdate={false}
width={600}
form={form}
layout={'horizontal'}
scrollToFirstError={true}
title={t(`website.ssl.dns.title_${form.getFieldValue('id') !== 0 ? 'edit' : 'add'}`, form.getFieldValue('id') !== 0 ? 'DNS帐号编辑' : 'DNS帐号添加')}
// colProps={{ span: 24 }}
labelCol={{ span: 6 }}
wrapperCol={{ span: 14 }}
layoutType={'ModalForm'}
open={open}
modalProps={{
maskClosable: false,
}}
onOpenChange={(open) => {
setOpen(open)
}}
loading={isSubmitting}
onFinish={async (values) => {
// console.log('values', values)
saveOrUpdate(values)
return isSuccess
}}
columns={columns as ProFormColumnsType[]}/>
</>
)
}
export default DNSList

19
src/pages/websites/ssl/index.tsx

@ -1,5 +1,7 @@
import { useAtom, useAtomValue } from 'jotai' import { useAtom, useAtomValue } from 'jotai'
import { import {
deleteSslAtom,
KeyTypeEnum,
KeyTypes, KeyTypes,
ProviderTypeEnum, ProviderTypeEnum,
saveOrUpdateSslAtom, saveOrUpdateSslAtom,
@ -15,9 +17,10 @@ import { Button, Form, Popconfirm } from 'antd'
import { PlusOutlined } from '@ant-design/icons' import { PlusOutlined } from '@ant-design/icons'
import { ISSL } from '@/types/website/ssl' import { ISSL } from '@/types/website/ssl'
import DrawerPicker from '@/components/drawer-picker/DrawerPicker.tsx' import DrawerPicker from '@/components/drawer-picker/DrawerPicker.tsx'
import AcmeList from '@/pages/websites/ssl/components/AcmeList.tsx'
import AcmeList from './components/AcmeList.tsx'
import { acmeListAtom, AcmeType, getAcmeAccountTypeName } from '@/store/websites/acme.ts' import { acmeListAtom, AcmeType, getAcmeAccountTypeName } from '@/store/websites/acme.ts'
import { dnsListAtom, getDNSTypeName } from '@/store/websites/dns.ts' import { dnsListAtom, getDNSTypeName } from '@/store/websites/dns.ts'
import DNSList from './components/DNSList.tsx'
const SSL = () => { const SSL = () => {
@ -30,6 +33,7 @@ const SSL = () => {
const { data: dnsData, isLoading: dnsLoading } = useAtomValue(dnsListAtom) const { data: dnsData, isLoading: dnsLoading } = useAtomValue(dnsListAtom)
const { data, isLoading, isFetching, refetch } = useAtomValue(sslListAtom) const { data, isLoading, isFetching, refetch } = useAtomValue(sslListAtom)
const { mutate: saveOrUpdate, isSuccess, isPending: isSubmitting } = useAtomValue(saveOrUpdateSslAtom) const { mutate: saveOrUpdate, isSuccess, isPending: isSubmitting } = useAtomValue(saveOrUpdateSslAtom)
const { mutate: delateSSL, isPending: isDeleteing } = useAtomValue(deleteSslAtom)
const [ open, setOpen ] = useState(false) const [ open, setOpen ] = useState(false)
@ -194,9 +198,9 @@ const SSL = () => {
</a>, </a>,
<Popconfirm <Popconfirm
key={'del_confirm'} key={'del_confirm'}
// disabled={isPending}
disabled={isDeleteing}
onConfirm={() => { onConfirm={() => {
// deleteUser([ record.id ])
delateSSL(record.id)
}} }}
title={t('message.deleteConfirm')}> title={t('message.deleteConfirm')}>
<a key="del"> <a key="del">
@ -242,10 +246,14 @@ const SSL = () => {
> >
<AcmeList/> <AcmeList/>
</DrawerPicker>, </DrawerPicker>,
<DrawerPicker target={<Button>
<DrawerPicker
maskClosable={false}
title={t('website.ssl.actions.dns', 'DNS帐户')}
width={1000}
target={<Button>
{t('website.ssl.actions.dns', 'DNS帐户')} {t('website.ssl.actions.dns', 'DNS帐户')}
</Button>}> </Button>}>
<DNSList/>
</DrawerPicker>, </DrawerPicker>,
<Button <Button
key="button" key="button"
@ -254,6 +262,7 @@ const SSL = () => {
form.resetFields() form.resetFields()
form.setFieldsValue({ form.setFieldsValue({
id: 0, id: 0,
keyType: KeyTypeEnum.EC256,
}) })
setOpen(true) setOpen(true)
}} }}

41
src/store/websites/dns.ts

@ -1,43 +1,54 @@
import { t } from 'i18next' import { t } from 'i18next'
import { atom } from 'jotai/index' import { atom } from 'jotai/index'
import { IPage } from '@/global'
import { IApiResult, IPage } from '@/global'
import { atomWithMutation, atomWithQuery } from 'jotai-tanstack-query' import { atomWithMutation, atomWithQuery } from 'jotai-tanstack-query'
import websitesServ from '@/service/websites.ts' import websitesServ from '@/service/websites.ts'
import { message } from 'antd' import { message } from 'antd'
import { IDnsAccount } from '@/types/website/dns' import { IDnsAccount } from '@/types/website/dns'
export const DNSTypeEnum = {
AliYun: 'AliYun',
TencentCloud: 'TencentCloud',
DnsPod: 'DnsPod',
CloudFlare: 'CloudFlare',
NameSilo: 'NameSilo',
NameCheap: 'NameCheap',
NameCom: 'NameCom',
Godaddy: 'Godaddy'
}
export const DNSTypes = [ export const DNSTypes = [
{ {
label: t('website.dns.types.aliyun', '阿里云DNS'), label: t('website.dns.types.aliyun', '阿里云DNS'),
value: 'AliYun',
value: DNSTypeEnum.AliYun,
}, },
{ {
label: t('website.dns.types.tencentCloud', '腾讯云'), label: t('website.dns.types.tencentCloud', '腾讯云'),
value: 'TencentCloud',
value: DNSTypeEnum.TencentCloud,
}, },
{ {
label: t('website.dns.types.dnsPod', 'DNSPod'), label: t('website.dns.types.dnsPod', 'DNSPod'),
value: 'DnsPod',
value: DNSTypeEnum.DnsPod,
}, },
{ {
label: 'CloudFlare', label: 'CloudFlare',
value: 'CloudFlare',
value: DNSTypeEnum.CloudFlare,
}, },
{ {
label: 'NameSilo', label: 'NameSilo',
value: 'NameSilo',
value: DNSTypeEnum.NameSilo,
}, },
{ {
label: 'NameCheap', label: 'NameCheap',
value: 'NameCheap',
value: DNSTypeEnum.NameCheap,
}, },
{ {
label: 'Name.com', label: 'Name.com',
value: 'NameCom',
value: DNSTypeEnum.NameCom,
}, },
{ {
label: 'GoDaddy', label: 'GoDaddy',
value: 'Godaddy',
value: DNSTypeEnum.Godaddy,
}, },
] ]
@ -77,3 +88,15 @@ export const saveOrUpdateDNSAtom = atomWithMutation<any, IDnsAccount>(get => ({
return res return res
} }
})) }))
//delete
export const deleteDNSAtom = atomWithMutation<IApiResult, number>(get => ({
mutationKey: [ 'sslDelete' ],
mutationFn: async (id) => {
return await websitesServ.dns.delete(id)
},
onSuccess: () => {
message.success(t('message.deleteSuccess', '删除成功'))
get(dnsListAtom).refetch()
}
}))
Loading…
Cancel
Save