1 changed files with 590 additions and 0 deletions
			
			
		@ -0,0 +1,590 @@ | 
				
			|||
import React, { useEffect, useMemo, useState } from "react"; | 
				
			|||
import { | 
				
			|||
  Table, | 
				
			|||
  Input, | 
				
			|||
  Button, | 
				
			|||
  Tag, | 
				
			|||
  Progress, | 
				
			|||
  Space, | 
				
			|||
  Drawer, | 
				
			|||
  Typography, | 
				
			|||
  Form, | 
				
			|||
  DatePicker, | 
				
			|||
  Tooltip, | 
				
			|||
  Modal, | 
				
			|||
  ProgressProps, | 
				
			|||
} from "antd"; | 
				
			|||
import { CheckCircleFilled, CheckCircleOutlined, CopyOutlined, SearchOutlined } from "@ant-design/icons"; | 
				
			|||
import { t } from "@/i18n.ts"; | 
				
			|||
import ListPageLayout from "@/layout/ListPageLayout.tsx"; | 
				
			|||
import TextArea from "antd/es/input/TextArea"; | 
				
			|||
import { useNavigate } from "@tanstack/react-router"; | 
				
			|||
import { | 
				
			|||
  certListAtom, | 
				
			|||
  checkDomainAtom, | 
				
			|||
  deletesCertificateAtom, | 
				
			|||
  downloadCertificateAtom, | 
				
			|||
  editCertificateAtom, | 
				
			|||
  getCertificateLogsAtom, | 
				
			|||
  Req_CertList, | 
				
			|||
  req_CertLogs, | 
				
			|||
  Req_DeletesCert, | 
				
			|||
  Req_DownloadCert, | 
				
			|||
  Req_UpdateCert, | 
				
			|||
  saveOrUpdateCertAtom, | 
				
			|||
} from "@/store/websites/cert.ts"; | 
				
			|||
import { useAtomValue } from "jotai/index"; | 
				
			|||
import { format } from "date-fns"; | 
				
			|||
import websitesServ from "@/service/websites.ts"; | 
				
			|||
import { useAtom } from "jotai"; | 
				
			|||
import { getToken } from "@/store/system.ts"; | 
				
			|||
 | 
				
			|||
const { confirm } = Modal; | 
				
			|||
const { Text, Link } = Typography; | 
				
			|||
const i18nPrefix = "cert.management"; | 
				
			|||
 | 
				
			|||
const CertApplyingDrawer = (props: { id: number; onCloseApplyingDrawer; applyingDrawerVisible }) => { | 
				
			|||
  const [dData, setDdata] = useState<req_CertLogs>({ | 
				
			|||
    log_id: props.id, | 
				
			|||
    log_type: "cert_apply", | 
				
			|||
    websocket: false, | 
				
			|||
    log_pos: 0, | 
				
			|||
    // 根据实际数据结构添加其他属性的初始值
 | 
				
			|||
  }); | 
				
			|||
  const [showTextInfo, setShowTextInfo] = useState(""); | 
				
			|||
  const [onChangeDT, setOnChangeDT] = useState(0); | 
				
			|||
  const { data: certLogsData, isFetching: certLogsFetching } = useAtomValue( | 
				
			|||
    useMemo(() => getCertificateLogsAtom(dData), [onChangeDT]), | 
				
			|||
  ); | 
				
			|||
 | 
				
			|||
  useEffect(() => { | 
				
			|||
    if (certLogsData && (certLogsData as any)?.log) { | 
				
			|||
      setShowTextInfo((prev) => prev + (certLogsData as any).log.toString()); | 
				
			|||
    } | 
				
			|||
  }, [certLogsData]); | 
				
			|||
 | 
				
			|||
  useEffect(() => { | 
				
			|||
    if (props.applyingDrawerVisible) { | 
				
			|||
      setShowTextInfo(""); | 
				
			|||
      setOnChangeDT((prev) => prev + 1); | 
				
			|||
    } | 
				
			|||
    let timer: number | undefined; | 
				
			|||
    if (props.applyingDrawerVisible) { | 
				
			|||
      timer = window.setInterval(() => { | 
				
			|||
        setDdata((prevState) => ({ | 
				
			|||
          ...prevState, | 
				
			|||
          log_id: props.id, | 
				
			|||
          log_pos: (certLogsData as any)?.log_pos || 0, | 
				
			|||
        })); | 
				
			|||
        // console.log("update drawer");
 | 
				
			|||
        setOnChangeDT((prev) => prev + 1); | 
				
			|||
      }, 5000); | 
				
			|||
    } else { | 
				
			|||
      setDdata((prevState) => ({ | 
				
			|||
        ...prevState, | 
				
			|||
        log_id: props.id, | 
				
			|||
        log_pos: 0, | 
				
			|||
      })); | 
				
			|||
      window.clearInterval(timer); | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    return () => window.clearInterval(timer); | 
				
			|||
  }, [props.applyingDrawerVisible]); | 
				
			|||
 | 
				
			|||
  return ( | 
				
			|||
    <Drawer | 
				
			|||
      title="证书申请中..." | 
				
			|||
      width={window.innerWidth / 2} | 
				
			|||
      placement="right" | 
				
			|||
      onClose={props.onCloseApplyingDrawer} | 
				
			|||
      visible={props.applyingDrawerVisible} | 
				
			|||
      bodyStyle={{ display: "flex", flexDirection: "column", height: "100%" }} | 
				
			|||
    > | 
				
			|||
      <TextArea value={showTextInfo} readOnly style={{ flex: 1 }} /> | 
				
			|||
    </Drawer> | 
				
			|||
  ); | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
const CertificateManagement: React.FC = () => { | 
				
			|||
  const [dlDrawerVisible, setDLDrawerVisible] = useState(false); | 
				
			|||
  const [editDrawerVisible, setEditDrawerVisible] = useState(false); | 
				
			|||
  const [detailsVisible, setDetailsVisible] = useState(false); | 
				
			|||
  const navigate = useNavigate(); | 
				
			|||
  const dData: Req_CertList = { order: "", prop: "", page: 1, pageSize: 10 }; | 
				
			|||
  const [updataList, setUpdataList] = useState(0); | 
				
			|||
  const { data: certListData, isFetching: certListFetching } = useAtomValue( | 
				
			|||
    useMemo(() => certListAtom(dData), [updataList]), | 
				
			|||
  ); | 
				
			|||
 | 
				
			|||
  const [applyingDrawerVisible, setApplyingDrawerVisible] = useState(false); | 
				
			|||
  const [certApplyingId, setCertApplyingId] = useState(0); | 
				
			|||
  const [currentDLInfo, setCurrentDLInfo] = useState({}); | 
				
			|||
  const { mutate: editCertUpdate } = useAtomValue(editCertificateAtom); | 
				
			|||
  const [remakeTextInfo, setRemakeTextInfo] = useState(""); | 
				
			|||
 | 
				
			|||
  useEffect(() => { | 
				
			|||
    window.setInterval(() => { | 
				
			|||
      // console.log("update drawer");
 | 
				
			|||
      setUpdataList((prev) => prev + 1); | 
				
			|||
    }, 5000); | 
				
			|||
  }, []); | 
				
			|||
 | 
				
			|||
  const showDLDrawer = (record) => { | 
				
			|||
    setCurrentDLInfo(record); | 
				
			|||
    setDLDrawerVisible(true); | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  const closeDLDrawer = () => { | 
				
			|||
    setDLDrawerVisible(false); | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  const showEditDrawer = (record) => { | 
				
			|||
    setCurrentDLInfo(record); | 
				
			|||
    setEditDrawerVisible(true); | 
				
			|||
  }; | 
				
			|||
  const enterEditDrawer = (record) => { | 
				
			|||
    const data: Req_UpdateCert = { | 
				
			|||
      id: record.id, | 
				
			|||
      remark: remakeTextInfo, | 
				
			|||
    }; | 
				
			|||
    editCertUpdate(data); | 
				
			|||
    setEditDrawerVisible(false); | 
				
			|||
  }; | 
				
			|||
  const closeEditDrawer = () => { | 
				
			|||
    setEditDrawerVisible(false); | 
				
			|||
  }; | 
				
			|||
  const openDetails = () => { | 
				
			|||
    setDetailsVisible(true); | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  const closeDetails = () => { | 
				
			|||
    setDetailsVisible(false); | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  const showApplyingDrawer = () => { | 
				
			|||
    setApplyingDrawerVisible(true); | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  const onCloseApplyingDrawer = () => { | 
				
			|||
    setApplyingDrawerVisible(false); | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  const applyCertClick = () => { | 
				
			|||
    navigate({ to: `/client/cert/apply` }); // 确保路径正确
 | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  const clickStateTag = (id: number) => { | 
				
			|||
    setCertApplyingId(id); | 
				
			|||
    showApplyingDrawer(); | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  const handleRemarkChange = (e) => { | 
				
			|||
    setRemakeTextInfo(e.target.value); | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  const clickDownLoad = (record: any) => { | 
				
			|||
    const cert_format: string = record.certificateFormat.toString().split("/")[0].replace(/\s+/g, ""); | 
				
			|||
    // const data: Req_DownloadCert = {
 | 
				
			|||
    //   id: (currentDLInfo as any)?.id,
 | 
				
			|||
    //   cert_format: cert_format,
 | 
				
			|||
    // };
 | 
				
			|||
    // websitesServ.cert.downloadCertificate(data);
 | 
				
			|||
    // eslint-disable-next-line react-hooks/rules-of-hooks
 | 
				
			|||
    const token = getToken(); | 
				
			|||
    const certUrl = "http://127.0.0.1:8000/api/v1/cert"; | 
				
			|||
    const url = `${certUrl}/apply/download?id=${(currentDLInfo as any)?.id}&cert_format=${cert_format}&token=${token}`; | 
				
			|||
    window.open(url, "_blank"); | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  const clickDelete = (id: number) => { | 
				
			|||
    confirm({ | 
				
			|||
      title: "提示", | 
				
			|||
      content: "是否要删除证书?", | 
				
			|||
      okText: "确定", | 
				
			|||
      okType: "danger", | 
				
			|||
      cancelText: "取消", | 
				
			|||
      onOk() { | 
				
			|||
        const data: Req_DeletesCert = { ids: [id] }; | 
				
			|||
        websitesServ.cert.deletesCertificate(data); | 
				
			|||
      }, | 
				
			|||
      onCancel() { | 
				
			|||
        console.log("取消删除证书"); | 
				
			|||
      }, | 
				
			|||
    }); | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  const drawerColumns = [ | 
				
			|||
    { | 
				
			|||
      title: "服务器类型", | 
				
			|||
      dataIndex: "serverType", | 
				
			|||
      key: "serverType", | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      title: "证书格式", | 
				
			|||
      dataIndex: "certificateFormat", | 
				
			|||
      key: "certificateFormat", | 
				
			|||
      render: (text: any) => ( | 
				
			|||
        <Space> | 
				
			|||
          {text.split("/").map((format: string) => ( | 
				
			|||
            <Button key={format} size="small" icon={<CopyOutlined />} iconPosition={"end"}> | 
				
			|||
              {format.trim()} | 
				
			|||
            </Button> | 
				
			|||
          ))} | 
				
			|||
        </Space> | 
				
			|||
      ), | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      title: "操作", | 
				
			|||
      key: "canDownLoad", | 
				
			|||
      render: (text: string, record: any) => ( | 
				
			|||
        <Space size="middle"> | 
				
			|||
          <Button type="link">帮助</Button> | 
				
			|||
          <Button type="link" disabled={!record.canDownLoad} onClick={() => clickDownLoad(record)}> | 
				
			|||
            下载 | 
				
			|||
          </Button> | 
				
			|||
        </Space> | 
				
			|||
      ), | 
				
			|||
    }, | 
				
			|||
  ]; | 
				
			|||
 | 
				
			|||
  const drawerDataSource = [ | 
				
			|||
    { | 
				
			|||
      key: "1", | 
				
			|||
      serverType: "Nginx", | 
				
			|||
      certificateFormat: "pem / key", | 
				
			|||
      canDownLoad: true, | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      key: "2", | 
				
			|||
      serverType: "Tomcat", | 
				
			|||
      certificateFormat: "pfx", | 
				
			|||
      canDownLoad: false, | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      key: "3", | 
				
			|||
      serverType: "Apache", | 
				
			|||
      certificateFormat: "crt / key", | 
				
			|||
      canDownLoad: true, | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      key: "4", | 
				
			|||
      serverType: "IIS", | 
				
			|||
      certificateFormat: "pfx", | 
				
			|||
      canDownLoad: false, | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      key: "5", | 
				
			|||
      serverType: "JKS", | 
				
			|||
      certificateFormat: "jks", | 
				
			|||
      canDownLoad: true, | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      key: "6", | 
				
			|||
      serverType: "宝塔", | 
				
			|||
      certificateFormat: "pem / key", | 
				
			|||
      canDownLoad: true, | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      key: "7", | 
				
			|||
      serverType: "其他", | 
				
			|||
      certificateFormat: "pem / key", | 
				
			|||
      canDownLoad: true, | 
				
			|||
    }, | 
				
			|||
  ]; | 
				
			|||
 | 
				
			|||
  const columns = [ | 
				
			|||
    { | 
				
			|||
      title: "域名", | 
				
			|||
      dataIndex: "primary_domain", | 
				
			|||
      key: "primary_domain", | 
				
			|||
      render: (text: string) => ( | 
				
			|||
        <Tooltip title={`点击查看详情`} color={"orange"}> | 
				
			|||
          <Button type="link" onClick={openDetails}> | 
				
			|||
            {text} | 
				
			|||
          </Button> | 
				
			|||
        </Tooltip> | 
				
			|||
      ), | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      title: "域名验证", | 
				
			|||
      dataIndex: "domainVerification", | 
				
			|||
      key: "domainVerification", | 
				
			|||
      render: () => <CheckCircleFilled style={{ color: "green" }} />, | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      title: "证书品牌", | 
				
			|||
      dataIndex: "acme_type", | 
				
			|||
      key: "acme_type", | 
				
			|||
      render: (text) => ( | 
				
			|||
        <Tooltip title={`证书名字`}> | 
				
			|||
          <span>{text}</span> | 
				
			|||
          {/*<img src="https://placehold.co/20x20?text=Logo" alt="Let's Encrypt Logo" />{" "}*/} | 
				
			|||
        </Tooltip> | 
				
			|||
      ), | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      /* | 
				
			|||
      const ( | 
				
			|||
      SSLSuccess    CertStatus = "success"    // 成功
 | 
				
			|||
      SSLInit       CertStatus = "init"    // 初始化
 | 
				
			|||
      SSLError      CertStatus = "error"   // 错误
 | 
				
			|||
      SSLReady      CertStatus = "ready"      // 准备中
 | 
				
			|||
      SSLApply      CertStatus = "applying"   // 申请中
 | 
				
			|||
      SSLApplyError CertStatus = "applyError" // 申请失败
 | 
				
			|||
      ) | 
				
			|||
       */ | 
				
			|||
      title: "有效期(天)", | 
				
			|||
      dataIndex: "validityDays", | 
				
			|||
      key: "validityDays", | 
				
			|||
      render: (text, record: { created_at: string; updated_at: string; expiredate: string }) => { | 
				
			|||
        if (record) { | 
				
			|||
          // const twoColors: ProgressProps["strokeColor"] = {
 | 
				
			|||
          //   "0%": "#00ff59",
 | 
				
			|||
          //   "100%": "#ff0000",
 | 
				
			|||
          // };
 | 
				
			|||
          record.created_at = !record?.created_at ? format(new Date(), "yyyy-MM-dd HH:mm:ss") : record.created_at; | 
				
			|||
          record.expiredate = !record?.expiredate ? format(new Date(), "yyyy-MM-dd HH:mm:ss") : record.expiredate; | 
				
			|||
          const createdDate = new Date(record.created_at.replace(/-/g, "/")); | 
				
			|||
          const expireDateObj = new Date(record.expiredate.replace(/-/g, "/")); | 
				
			|||
          const currentDate = new Date(); | 
				
			|||
          const totalValidTime = expireDateObj.getTime() - createdDate.getTime(); | 
				
			|||
          const remainingTime = expireDateObj.getTime() - currentDate.getTime(); | 
				
			|||
          const percentage = (remainingTime / totalValidTime) * 100; | 
				
			|||
          //const percentage = 60;
 | 
				
			|||
          let cColor = "#000000"; | 
				
			|||
 | 
				
			|||
          if (percentage < 50) { | 
				
			|||
            cColor = "#00ff59"; | 
				
			|||
          } else if (percentage >= 50 && percentage <= 75) { | 
				
			|||
            cColor = "#00641a"; | 
				
			|||
          } else if (percentage >= 75 && percentage <= 90) { | 
				
			|||
            cColor = "#ffdd00"; | 
				
			|||
          } else { | 
				
			|||
            cColor = "#ff0000"; | 
				
			|||
          } | 
				
			|||
          return ( | 
				
			|||
            <Space> | 
				
			|||
              <Tooltip | 
				
			|||
                title={ | 
				
			|||
                  <div> | 
				
			|||
                    创建时间:{record.created_at} | 
				
			|||
                    <br /> | 
				
			|||
                    到期时间:{record.expiredate} | 
				
			|||
                  </div> | 
				
			|||
                } | 
				
			|||
              > | 
				
			|||
                <Progress | 
				
			|||
                  style={{ width: 200 }} | 
				
			|||
                  percent={percentage} | 
				
			|||
                  strokeColor={cColor} | 
				
			|||
                  size="small" | 
				
			|||
                  showInfo={false} | 
				
			|||
                /> | 
				
			|||
                <span>{Math.round(percentage)}/100</span> | 
				
			|||
              </Tooltip> | 
				
			|||
            </Space> | 
				
			|||
          ); | 
				
			|||
        } | 
				
			|||
      }, | 
				
			|||
    }, | 
				
			|||
 | 
				
			|||
    { | 
				
			|||
      title: "加密方式", | 
				
			|||
      dataIndex: "keytype", | 
				
			|||
      key: "keytype", | 
				
			|||
      render: (encryptionMethod: string) => <Tag color="green">{encryptionMethod}</Tag>, | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      title: "状态", | 
				
			|||
      dataIndex: "cert_status", | 
				
			|||
      key: "cert_status", | 
				
			|||
      render: (state, record: any) => { | 
				
			|||
        const { id } = record; | 
				
			|||
        if (state === "applying") { | 
				
			|||
          return ( | 
				
			|||
            <Tag color="blue" onClick={() => clickStateTag(id)} style={{ cursor: "pointer" }}> | 
				
			|||
              {state} | 
				
			|||
            </Tag> | 
				
			|||
          ); | 
				
			|||
        } else { | 
				
			|||
          return ( | 
				
			|||
            <Tag color="green" onClick={() => clickStateTag(id)} style={{ cursor: "pointer" }}> | 
				
			|||
              {state} | 
				
			|||
            </Tag> | 
				
			|||
          ); | 
				
			|||
        } | 
				
			|||
      }, | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      title: "备注", | 
				
			|||
      dataIndex: "remark", | 
				
			|||
      key: "remark", | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      title: "操作", | 
				
			|||
      key: "action", | 
				
			|||
      render: (record: any) => ( | 
				
			|||
        <Space size="middle"> | 
				
			|||
          <a onClick={() => showEditDrawer(record)}>编辑</a> | 
				
			|||
          <a onClick={() => showDLDrawer(record)}>下载</a> | 
				
			|||
          <a onClick={() => clickDelete(record.id)}>删除</a> | 
				
			|||
        </Space> | 
				
			|||
      ), | 
				
			|||
    }, | 
				
			|||
  ]; | 
				
			|||
 | 
				
			|||
  const detailsColumns = [ | 
				
			|||
    { | 
				
			|||
      title: "状态", | 
				
			|||
      dataIndex: "status", | 
				
			|||
      key: "status", | 
				
			|||
      render: (text: string) => <span style={{ color: "#52c41a" }}>{text}</span>, | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      title: "域名", | 
				
			|||
      dataIndex: "domain", | 
				
			|||
      key: "domain", | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      title: "服务商", | 
				
			|||
      dataIndex: "provider", | 
				
			|||
      key: "provider", | 
				
			|||
      render: (text: string) => <span style={{ color: "#1890ff" }}>{text}</span>, | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      title: "主机记录", | 
				
			|||
      dataIndex: "hostRecord", | 
				
			|||
      key: "hostRecord", | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      title: "记录类型", | 
				
			|||
      dataIndex: "recordType", | 
				
			|||
      key: "recordType", | 
				
			|||
      render: (text: string) => <span style={{ color: "red" }}>{text}</span>, | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      title: "记录值", | 
				
			|||
      dataIndex: "recordValue", | 
				
			|||
      key: "recordValue", | 
				
			|||
    }, | 
				
			|||
    { | 
				
			|||
      title: "操作", | 
				
			|||
      dataIndex: "action", | 
				
			|||
      key: "action", | 
				
			|||
      render: (text: string) => <Link href="#">{text}</Link>, | 
				
			|||
    }, | 
				
			|||
  ]; | 
				
			|||
 | 
				
			|||
  const detailsData = [ | 
				
			|||
    { | 
				
			|||
      key: "1", | 
				
			|||
      status: "通过", | 
				
			|||
      domain: "*.bidiy2.com", | 
				
			|||
      provider: "Cloudflare", | 
				
			|||
      hostRecord: "_acme-challenge", | 
				
			|||
      recordType: "CNAME", | 
				
			|||
      recordValue: "8cb0d498cecabd92.httpsok.com", | 
				
			|||
      action: "检测命令", | 
				
			|||
    }, | 
				
			|||
  ]; | 
				
			|||
 | 
				
			|||
  return ( | 
				
			|||
    <div> | 
				
			|||
      <ListPageLayout title={t(`${i18nPrefix}.apply.title`, "证书申请")}> | 
				
			|||
        <Space style={{ marginBottom: 16 }}> | 
				
			|||
          <Input addonBefore={<SearchOutlined />} placeholder="域名 | 备注" style={{ width: 200 }} /> | 
				
			|||
          <Button>搜索</Button> | 
				
			|||
          <Button type="primary" onClick={applyCertClick}> | 
				
			|||
            免费申请证书 | 
				
			|||
          </Button> | 
				
			|||
        </Space> | 
				
			|||
        <Table columns={columns} dataSource={(certListData as any)?.rows} pagination={false} /> | 
				
			|||
      </ListPageLayout> | 
				
			|||
 | 
				
			|||
      <CertApplyingDrawer | 
				
			|||
        id={certApplyingId} | 
				
			|||
        onCloseApplyingDrawer={onCloseApplyingDrawer} | 
				
			|||
        applyingDrawerVisible={applyingDrawerVisible} | 
				
			|||
      /> | 
				
			|||
 | 
				
			|||
      <Drawer title="下载证书" placement="right" onClose={closeDLDrawer} visible={dlDrawerVisible} width={600}> | 
				
			|||
        <Text>请根据您的服务器类型选择证书下载:</Text> | 
				
			|||
        <Table dataSource={drawerDataSource} columns={drawerColumns} pagination={false} style={{ marginTop: 16 }} /> | 
				
			|||
        <div style={{ backgroundColor: "#f6ffed", padding: 16, marginTop: 16 }}> | 
				
			|||
          <Text>加入SSL证书交流群</Text> | 
				
			|||
          <br /> | 
				
			|||
          <Text>产品咨询 问题反馈</Text> | 
				
			|||
          <br /> | 
				
			|||
          <Link href="https://httpsok">请备注 httpsok</Link> | 
				
			|||
        </div> | 
				
			|||
      </Drawer> | 
				
			|||
 | 
				
			|||
      <Drawer | 
				
			|||
        title="编辑" | 
				
			|||
        placement="right" | 
				
			|||
        closable={false} | 
				
			|||
        onClose={closeEditDrawer} | 
				
			|||
        visible={editDrawerVisible} | 
				
			|||
        style={{ textAlign: "center" }} | 
				
			|||
        bodyStyle={{ display: "flex", justifyContent: "center", alignItems: "center" }} | 
				
			|||
      > | 
				
			|||
        <Form layout="vertical" style={{ maxWidth: "400px", width: "100%" }}> | 
				
			|||
          <Form.Item label="域名"> | 
				
			|||
            <span>{(currentDLInfo as any)?.primary_domain}</span> | 
				
			|||
          </Form.Item> | 
				
			|||
          <Form.Item label="证书品牌"> | 
				
			|||
            <span>{(currentDLInfo as any)?.acme_type}</span> | 
				
			|||
          </Form.Item> | 
				
			|||
          <Form.Item label="失效时间"> | 
				
			|||
            <span>{(currentDLInfo as any)?.expiredate}</span> | 
				
			|||
          </Form.Item> | 
				
			|||
          <Form.Item label="创建时间"> | 
				
			|||
            <span>{(currentDLInfo as any)?.created_at}</span> | 
				
			|||
          </Form.Item> | 
				
			|||
          <Form.Item label="备注"> | 
				
			|||
            <TextArea | 
				
			|||
              rows={4} | 
				
			|||
              maxLength={100} | 
				
			|||
              defaultValue={(currentDLInfo as any)?.remark} | 
				
			|||
              onChange={handleRemarkChange} | 
				
			|||
            /> | 
				
			|||
          </Form.Item> | 
				
			|||
          <Form.Item> | 
				
			|||
            <Button onClick={closeEditDrawer} style={{ marginRight: 8 }}> | 
				
			|||
              取消 | 
				
			|||
            </Button> | 
				
			|||
            <Button type="primary" onClick={() => enterEditDrawer(currentDLInfo)}> | 
				
			|||
              确定 | 
				
			|||
            </Button> | 
				
			|||
          </Form.Item> | 
				
			|||
        </Form> | 
				
			|||
      </Drawer> | 
				
			|||
 | 
				
			|||
      <Modal | 
				
			|||
        title="域名验证" | 
				
			|||
        visible={detailsVisible} | 
				
			|||
        onOk={openDetails} | 
				
			|||
        onCancel={closeDetails} | 
				
			|||
        width={1200} // 设置宽度为800px
 | 
				
			|||
        footer={[ | 
				
			|||
          <Button key="ok" type="primary" onClick={openDetails}> | 
				
			|||
            确定 | 
				
			|||
          </Button>, | 
				
			|||
        ]} | 
				
			|||
      > | 
				
			|||
        <Text> | 
				
			|||
          请您添加以下DNS解析记录 <Link href="#">参考文档</Link> | 
				
			|||
        </Text> | 
				
			|||
        <br /> | 
				
			|||
        <Text>1. 只需要添加一次即可,添加后请勿删除记录。</Text> | 
				
			|||
        <br /> | 
				
			|||
        <Text> | 
				
			|||
          2. 需等待1-2分钟。(<Text type="danger">如果长时间没通过,请联系客服解决</Text>) | 
				
			|||
        </Text> | 
				
			|||
        <Table columns={detailsColumns} dataSource={detailsData} pagination={false} /> | 
				
			|||
      </Modal> | 
				
			|||
    </div> | 
				
			|||
  ); | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
export default CertificateManagement; | 
				
			|||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue