diff --git a/server/admin/api_cert.go b/server/admin/api_cert.go
index e9c2fea..7b0b162 100755
--- a/server/admin/api_cert.go
+++ b/server/admin/api_cert.go
@@ -22,6 +22,7 @@ import (
 	"github.com/go-acme/lego/v4/challenge/dns01"
 	"github.com/go-acme/lego/v4/lego"
 	"github.com/go-acme/lego/v4/providers/dns/alidns"
+	"github.com/go-acme/lego/v4/providers/dns/cloudflare"
 	"github.com/go-acme/lego/v4/providers/dns/tencentcloud"
 	"github.com/go-acme/lego/v4/registration"
 	"github.com/xenolf/lego/challenge"
@@ -84,8 +85,11 @@ func GetCertSetting(w http.ResponseWriter, r *http.Request) {
 	if err := dbdata.SettingGet(data); err != nil {
 		RespError(w, RespInternalErr, err)
 	}
-	data.AccessKeyID = Scrypt(data.AccessKeyID)
-	data.AccessKeySecret = Scrypt(data.AccessKeySecret)
+	data.AliYun.APIKey = Scrypt(data.AliYun.APIKey)
+	data.AliYun.SecretKey = Scrypt(data.AliYun.SecretKey)
+	data.TXCloud.SecretID = Scrypt(data.TXCloud.SecretID)
+	data.TXCloud.SecretKey = Scrypt(data.TXCloud.SecretKey)
+	data.CfCloud.AuthKey = Scrypt(data.CfCloud.AuthKey)
 	RespSucess(w, data)
 }
 func CreatCert(w http.ResponseWriter, r *http.Request) {
@@ -179,16 +183,17 @@ func NewLeGoClient(d *dbdata.SettingDnsProvider) (*LeGoClient, error) {
 		legoUser.Registration = reg
 	}
 	var Provider challenge.Provider
-	if d.Name == "" {
-		return nil, fmt.Errorf("%s", "DNS服务商名不允许为空")
-	}
 	switch d.Name {
 	case "aliyun":
-		if Provider, err = alidns.NewDNSProviderConfig(&alidns.Config{APIKey: d.AccessKeyID, SecretKey: d.AccessKeySecret, TTL: 600}); err != nil {
+		if Provider, err = alidns.NewDNSProviderConfig(&alidns.Config{APIKey: d.AliYun.APIKey, SecretKey: d.AliYun.SecretKey, TTL: 600}); err != nil {
 			return nil, err
 		}
-	case "txCloud":
-		if Provider, err = tencentcloud.NewDNSProviderConfig(&tencentcloud.Config{SecretID: d.AccessKeyID, SecretKey: d.AccessKeySecret, TTL: 600}); err != nil {
+	case "txcloud":
+		if Provider, err = tencentcloud.NewDNSProviderConfig(&tencentcloud.Config{SecretID: d.TXCloud.SecretID, SecretKey: d.TXCloud.SecretKey, TTL: 600}); err != nil {
+			return nil, err
+		}
+	case "cloudflare":
+		if Provider, err = cloudflare.NewDNSProviderConfig(&cloudflare.Config{AuthEmail: d.CfCloud.AuthEmail, AuthKey: d.CfCloud.AuthKey, TTL: 600}); err != nil {
 			return nil, err
 		}
 	}
diff --git a/server/dbdata/db.go b/server/dbdata/db.go
index 71e0e56..149534d 100644
--- a/server/dbdata/db.go
+++ b/server/dbdata/db.go
@@ -101,11 +101,22 @@ func addInitData() error {
 
 	// SettingDnsProvider
 	provider := &SettingDnsProvider{
-		Legomail:        "legomail",
-		Name:            "aliyun OR TXCloud",
-		AccessKeyID:     "AccessKeyID",
-		AccessKeySecret: "AccessKeySecret",
-		Domain:          "vpn.xxx.com",
+		Domain:   "vpn.xxx.com",
+		Legomail: "legomail",
+		Name:     "",
+		Renew:    false,
+		AliYun: struct {
+			APIKey    string `json:"apiKey"`
+			SecretKey string `json:"secretKey"`
+		}{APIKey: "", SecretKey: ""},
+		TXCloud: struct {
+			SecretID  string `json:"secretId"`
+			SecretKey string `json:"secretKey"`
+		}{SecretID: "", SecretKey: ""},
+		CfCloud: struct {
+			AuthEmail string `json:"authEmail"`
+			AuthKey   string `json:"authKey"`
+		}{AuthEmail: "", AuthKey: ""},
 	}
 	err = SettingSessAdd(sess, provider)
 	if err != nil {
diff --git a/server/dbdata/setting.go b/server/dbdata/setting.go
index a1b7cf9..4cba04f 100644
--- a/server/dbdata/setting.go
+++ b/server/dbdata/setting.go
@@ -34,12 +34,23 @@ type SettingOther struct {
 }
 
 type SettingDnsProvider struct {
-	Legomail        string `json:"legomail"`
-	Name            string `json:"name"`
-	AccessKeyID     string `json:"accessKeyId"`
-	AccessKeySecret string `json:"accessKeySecret"`
-	Domain          string `json:"domain"`
-	Renew           bool   `json:"renew"`
+	Domain   string `json:"domain"`
+	Legomail string `json:"legomail"`
+	Name     string `json:"name"`
+	Renew    bool   `json:"renew"`
+	AliYun   struct {
+		APIKey    string `json:"apiKey"`
+		SecretKey string `json:"secretKey"`
+	} `json:"aliyun"`
+
+	TXCloud struct {
+		SecretID  string `json:"secretId"`
+		SecretKey string `json:"secretKey"`
+	} `json:"txcloud"`
+	CfCloud struct {
+		AuthEmail string `json:"authEmail"`
+		AuthKey   string `json:"authKey"`
+	} `json:"cfcloud"`
 }
 
 func StructName(data interface{}) string {
diff --git a/server/go.mod b/server/go.mod
index a99056e..1f024e3 100644
--- a/server/go.mod
+++ b/server/go.mod
@@ -46,11 +46,16 @@ require (
 require (
 	github.com/aliyun/alibaba-cloud-sdk-go v1.61.1755 // indirect
 	github.com/cenkalti/backoff/v4 v4.2.0 // indirect
+	github.com/cloudflare/cloudflare-go v0.49.0 // indirect
 	github.com/felixge/httpsnoop v1.0.1 // indirect
 	github.com/go-acme/lego v2.7.2+incompatible // indirect
 	github.com/go-jose/go-jose/v3 v3.0.0 // indirect
+	github.com/google/go-querystring v1.1.0 // indirect
+	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
+	github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
 	github.com/jmespath/go-jmespath v0.4.0 // indirect
 	github.com/miekg/dns v1.1.50 // indirect
+	github.com/pkg/errors v0.9.1 // indirect
 	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.490 // indirect
 	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.490 // indirect
 	golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
diff --git a/server/go.sum b/server/go.sum
index 251d35a..5f6c4a1 100644
--- a/server/go.sum
+++ b/server/go.sum
@@ -84,6 +84,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cloudflare/cloudflare-go v0.49.0 h1:KqJYk/YQ5ZhmyYz1oa4kGDskfF1gVuZfqesaJ/XDLto=
+github.com/cloudflare/cloudflare-go v0.49.0/go.mod h1:h0QgcIZ3qEXwFiwfBO8sQxjVdYsLX+PfD7NFEnANaKg=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
 github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -124,6 +126,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
 github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
 github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
 github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
 github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
@@ -220,8 +223,10 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
+github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
+github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
 github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
@@ -267,9 +272,15 @@ github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyN
 github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
 github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
+github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
+github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
+github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM=
 github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
 github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
 github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ=
+github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
 github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
 github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
 github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
@@ -368,8 +379,8 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
 github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
-github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
 github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
@@ -391,6 +402,7 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO
 github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
 github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
 github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
@@ -473,6 +485,8 @@ github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Do
 github.com/pires/go-proxyproto v0.6.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
 github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -507,6 +521,7 @@ github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzG
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
 github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
 github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
 github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
@@ -1034,8 +1049,8 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
 gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=
 gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
diff --git a/web/src/pages/set/Other.vue b/web/src/pages/set/Other.vue
index e9520e8..118e864 100644
--- a/web/src/pages/set/Other.vue
+++ b/web/src/pages/set/Other.vue
@@ -2,7 +2,13 @@
   <el-card>
     <el-tabs v-model="activeName" @tab-click="handleClick">
       <el-tab-pane label="邮件配置" name="dataSmtp">
-        <el-form :model="dataSmtp" ref="dataSmtp" :rules="rules" label-width="100px" class="tab-one">
+        <el-form
+          :model="dataSmtp"
+          ref="dataSmtp"
+          :rules="rules"
+          label-width="100px"
+          class="tab-one"
+        >
           <el-form-item label="服务器地址" prop="host">
             <el-input v-model="dataSmtp.host"></el-input>
           </el-form-item>
@@ -13,7 +19,11 @@
             <el-input v-model="dataSmtp.username"></el-input>
           </el-form-item>
           <el-form-item label="密码" prop="password">
-            <el-input type="password" v-model="dataSmtp.password" placeholder="密码为空则不修改"></el-input>
+            <el-input
+              type="password"
+              v-model="dataSmtp.password"
+              placeholder="密码为空则不修改"
+            ></el-input>
           </el-form-item>
           <el-form-item label="加密类型" prop="encryption">
             <el-radio-group v-model="dataSmtp.encryption">
@@ -26,166 +36,252 @@
             <el-input v-model="dataSmtp.from"></el-input>
           </el-form-item>
           <el-form-item>
-            <el-button type="primary" @click="submitForm('dataSmtp')">保存</el-button>
+            <el-button type="primary" @click="submitForm('dataSmtp')"
+              >保存</el-button
+            >
             <el-button @click="resetForm('dataSmtp')">重置</el-button>
           </el-form-item>
         </el-form>
       </el-tab-pane>
 
       <el-tab-pane label="审计日志" name="dataAuditLog">
-        <el-form :model="dataAuditLog" ref="dataAuditLog" :rules="rules" label-width="100px" class="tab-one">
+        <el-form
+          :model="dataAuditLog"
+          ref="dataAuditLog"
+          :rules="rules"
+          label-width="100px"
+          class="tab-one"
+        >
           <el-form-item label="审计去重间隔" prop="audit_interval">
-                <el-input-number v-model="dataAuditLog.audit_interval" :min="-1" size="small" label="秒" :disabled="true"></el-input-number>  秒
-                <p class="input_tip">请手动修改配置文件中的 audit_interval 参数后,再重启服务, <strong style="color:#EA3323;">-1 代表关闭审计日志</strong></p>
-          </el-form-item>            
+            <el-input-number
+              v-model="dataAuditLog.audit_interval"
+              :min="-1"
+              size="small"
+              label="秒"
+              :disabled="true"
+            ></el-input-number>
+            秒
+            <p class="input_tip">
+              请手动修改配置文件中的 audit_interval 参数后,再重启服务,
+              <strong style="color: #ea3323">-1 代表关闭审计日志</strong>
+            </p>
+          </el-form-item>
           <el-form-item label="存储时长" prop="life_day">
-                <el-input-number v-model="dataAuditLog.life_day" :min="0" :max="365" size="small" label="天数"></el-input-number>  天
-                <p class="input_tip">范围: 0 ~ 365天 , <strong style="color:#EA3323;">0 代表永久保存</strong></p>
+            <el-input-number
+              v-model="dataAuditLog.life_day"
+              :min="0"
+              :max="365"
+              size="small"
+              label="天数"
+            ></el-input-number>
+            天
+            <p class="input_tip">
+              范围: 0 ~ 365天 ,
+              <strong style="color: #ea3323">0 代表永久保存</strong>
+            </p>
           </el-form-item>
           <el-form-item label="清理时间" prop="clear_time">
             <el-time-select
-                v-model="dataAuditLog.clear_time"
-                :picker-options="{
-                    start: '00:00',
-                    step: '01:00',
-                    end: '23:00'
-                }"
-                editable=false,
-                size="small"
-                placeholder="请选择"
-                style="width:130px;">
-                </el-time-select>  
-            </el-form-item>
+              v-model="dataAuditLog.clear_time"
+              :picker-options="{
+                start: '00:00',
+                step: '01:00',
+                end: '23:00',
+              }"
+              editable="false,"
+              size="small"
+              placeholder="请选择"
+              style="width: 130px"
+            >
+            </el-time-select>
+          </el-form-item>
           <el-form-item>
-            <el-button type="primary" @click="submitForm('dataAuditLog')">保存</el-button>
+            <el-button type="primary" @click="submitForm('dataAuditLog')"
+              >保存</el-button
+            >
             <el-button @click="resetForm('dataAuditLog')">重置</el-button>
-          </el-form-item>          
+          </el-form-item>
         </el-form>
       </el-tab-pane>
-      <el-tab-pane label="证书设置" name="dataCert">
-        <el-tabs tab-position="left">
-          <el-tab-pane label="自定义证书">
-            <el-form ref="customCert" :model="customCert" label-width="100px" size="small" class="tab-one">
-              <!-- <el-form-item> -->
+      <el-tab-pane label="证书设置" name="datacertManage">
+        <el-tabs
+          tab-position="left"
+          v-model="datacertManage"
+          @tab-click="handleClick"
+        >
+          <el-tab-pane label="自定义证书" name="customCert">
+            <el-form
+              ref="customCert"
+              :model="customCert"
+              label-width="100px"
+              size="small"
+              class="tab-one"
+            >
+              <el-form-item>
                 <el-upload
-                  class="upload-demo"
+                  class="uploadCert"
                   :before-upload="beforeCertUpload"
                   :action="certUpload"
-                  :file-list="certFileList"
-                  multiple>
-                  <el-button size="mini" icon="el-icon-plus" slot="trigger">证书文件</el-button>
-                  <el-tooltip class="item" effect="dark" content="请上传 .pem 格式的 cert 文件" placement="top">
+                  :limit="1"
+                >
+                  <el-button size="mini" icon="el-icon-plus" slot="trigger"
+                    >证书文件</el-button
+                  >
+                  <el-tooltip
+                    class="item"
+                    effect="dark"
+                    content="请上传 .pem 格式的 cert 文件"
+                    placement="top"
+                  >
                     <i class="el-icon-info"></i>
                   </el-tooltip>
                 </el-upload>
-              <!-- </el-form-item> -->
-              <!-- <el-form-item> -->
+              </el-form-item>
+              <el-form-item>
                 <el-upload
-                  class="upload-demo"
+                  class="uploadCert"
                   :before-upload="beforeKeyUpload"
                   :action="certUpload"
-                  :file-list="keyFileList"
-                  multiple>
-                  <el-button size="mini" icon="el-icon-plus" slot="trigger">私钥文件</el-button>
-                  <el-tooltip class="item" effect="dark" content="请上传 .pem 格式的 key 文件" placement="top">
+                  :limit="1"
+                >
+                  <el-button size="mini" icon="el-icon-plus" slot="trigger"
+                    >私钥文件</el-button
+                  >
+                  <el-tooltip
+                    class="item"
+                    effect="dark"
+                    content="请上传 .pem 格式的 key 文件"
+                    placement="top"
+                  >
                     <i class="el-icon-info"></i>
                   </el-tooltip>
                 </el-upload>
-              <!-- </el-form-item> -->
-              <!-- <el-form-item> -->
-                <el-button size="small" icon="el-icon-upload" type="primary" @click="submitForm('customCert')">上传</el-button>
-              <!-- </el-form-item> -->
+              </el-form-item>
+              <el-form-item>
+                <el-button
+                  size="small"
+                  icon="el-icon-upload"
+                  type="primary"
+                  @click="submitForm('customCert')"
+                  >上传</el-button
+                >
+              </el-form-item>
             </el-form>
           </el-tab-pane>
-          <el-tab-pane label="Let's Encrypt证书">
-            <el-form :model="dataCert" ref="dataCert" :rules="rules" label-width="120px" size="small" class="tab-one">
+          <el-tab-pane label="Let's Encrypt证书" name="letsCert">
+            <el-form
+              :model="letsCert"
+              ref="letsCert"
+              :rules="rules"
+              label-width="120px"
+              size="small"
+              class="tab-one"
+            >
               <el-form-item label="域名" prop="domain">
-                <el-input v-model="dataCert.domain"></el-input>
+                <el-input v-model="letsCert.domain"></el-input>
               </el-form-item>
               <el-form-item label="邮箱" prop="legomail">
-                <el-input v-model="dataCert.legomail"></el-input>
+                <el-input v-model="letsCert.legomail"></el-input>
               </el-form-item>
               <el-form-item label="域名服务商" prop="name">
-                <el-radio-group v-model="dataCert.name">
+                <el-radio-group v-model="letsCert.name">
                   <el-radio label="aliyun">阿里云</el-radio>
-                  <el-radio label="txCloud">腾讯云</el-radio>
+                  <el-radio label="txcloud">腾讯云</el-radio>
+                  <el-radio label="cfcloud">cloudflare</el-radio>
                 </el-radio-group>
               </el-form-item>
-              <el-form-item label="AccessKeyId" prop="accessKeyId">
-                <el-input type="password" v-model="dataCert.accessKeyId"></el-input>
-              </el-form-item>
-              <el-form-item label="AccessKeySecret" prop="accessKeySecret">
-                <el-input type="password" v-model="dataCert.accessKeySecret"></el-input>
+              <el-form-item
+                v-for="component in dnsProvider[letsCert.name]"
+                :key="component.prop"
+                :label="component.label"
+                :rules="component.rules"
+              >
+                <component
+                  :is="component.component"
+                  :type="component.type"
+                  v-model="letsCert[letsCert.name][component.prop]"
+                ></component>
               </el-form-item>
               <el-form-item>
                 <el-switch
                   style="display: block"
-                  v-model="dataCert.renew"
+                  v-model="letsCert.renew"
                   active-color="#13ce66"
                   inactive-color="#ff4949"
-                  inactive-text="自动续期">
+                  inactive-text="自动续期"
+                >
                 </el-switch>
               </el-form-item>
               <el-form-item>
-                <el-button type="primary" @click="submitForm('dataCert')">申请</el-button>
-                <el-button @click="resetForm('dataCert')">重置</el-button>
-              </el-form-item> 
+                <el-button type="primary" @click="submitForm('letsCert')"
+                  >申请</el-button
+                >
+                <el-button @click="resetForm('letsCert')">重置</el-button>
+              </el-form-item>
             </el-form>
           </el-tab-pane>
         </el-tabs>
-      </el-tab-pane>     
+      </el-tab-pane>
       <el-tab-pane label="其他设置" name="dataOther">
-        <el-form :model="dataOther" ref="dataOther" :rules="rules" label-width="100px" class="tab-one">
-
+        <el-form
+          :model="dataOther"
+          ref="dataOther"
+          :rules="rules"
+          label-width="100px"
+          class="tab-one"
+        >
           <el-form-item label="vpn对外地址" prop="link_addr">
-            <el-input
-                placeholder="请输入内容"
-                v-model="dataOther.link_addr">
+            <el-input placeholder="请输入内容" v-model="dataOther.link_addr">
             </el-input>
           </el-form-item>
 
           <el-form-item label="Banner信息" prop="banner">
             <el-input
-                type="textarea"
-                :rows="5"
-                placeholder="请输入内容"
-                v-model="dataOther.banner">
+              type="textarea"
+              :rows="5"
+              placeholder="请输入内容"
+              v-model="dataOther.banner"
+            >
             </el-input>
           </el-form-item>
-          
+
           <el-form-item label="自定义首页" prop="homeindex">
             <el-input
-                type="textarea"
-                :rows="5"
-                placeholder="请输入内容"
-                v-model="dataOther.homeindex">
+              type="textarea"
+              :rows="5"
+              placeholder="请输入内容"
+              v-model="dataOther.homeindex"
+            >
             </el-input>
           </el-form-item>
 
           <el-form-item label="账户开通邮件" prop="account_mail">
             <el-input
-                type="textarea"
-                :rows="10"
-                placeholder="请输入内容"
-                v-model="dataOther.account_mail">
+              type="textarea"
+              :rows="10"
+              placeholder="请输入内容"
+              v-model="dataOther.account_mail"
+            >
             </el-input>
           </el-form-item>
 
           <el-form-item label="邮件展示">
             <iframe
-                width="500px"
-                height="300px"
-                :srcdoc="dataOther.account_mail">
+              width="500px"
+              height="300px"
+              :srcdoc="dataOther.account_mail"
+            >
             </iframe>
           </el-form-item>
 
           <el-form-item>
-            <el-button type="primary" @click="submitForm('dataOther')">保存</el-button>
+            <el-button type="primary" @click="submitForm('dataOther')"
+              >保存</el-button
+            >
             <el-button @click="resetForm('dataOther')">重置</el-button>
           </el-form-item>
         </el-form>
       </el-tab-pane>
-
     </el-tabs>
   </el-card>
 </template>
@@ -196,36 +292,133 @@ import axios from "axios";
 export default {
   name: "Other",
   created() {
-    this.$emit('update:route_path', this.$route.path)
-    this.$emit('update:route_name', ['基础信息', '其他设置'])
+    this.$emit("update:route_path", this.$route.path);
+    this.$emit("update:route_name", ["基础信息", "其他设置"]);
   },
   mounted() {
-    this.getSmtp()
+    this.getSmtp();
   },
   data() {
     return {
-      activeName: 'dataSmtp',
+      activeName: "dataSmtp",
+      datacertManage: "customCert",
       dataSmtp: {},
       dataAuditLog: {},
-      dataCert: { renew: true },
-      customCert: {cert:'',key:''},
+      letsCert: {
+        domain: ``,
+        legomail: ``,
+        name: "",
+        renew: "",
+        aliyun: {
+          apiKey: "",
+          secretKey: "",
+        },
+        txcloud: {
+          secretId: "",
+          secretKey: "",
+        },
+        cfcloud: {
+          authEmail: "",
+          authKey: "",
+        },
+      },
+      customCert: { cert: "", key: "" },
       dataOther: {},
       rules: {
-        host: {required: true, message: '请输入服务器地址', trigger: 'blur'},
+        host: { required: true, message: "请输入服务器地址", trigger: "blur" },
         port: [
-          {required: true, message: '请输入服务器端口', trigger: 'blur'},
-          {type: 'number', message: '请输入正确的服务器端口', trigger: ['blur', 'change']}
+          { required: true, message: "请输入服务器端口", trigger: "blur" },
+          {
+            type: "number",
+            message: "请输入正确的服务器端口",
+            trigger: ["blur", "change"],
+          },
         ],
-        issuer: { required: true, message: '请输入系统名称', trigger: 'blur' },
-        domain: {required: true, message: '请输入需要申请证书的域名', trigger: 'blur'},
-        legomail: { required: true, message: '请输入申请证书的邮箱地址', trigger: 'blur' },
-        name: { required: true, message: '请选择域名服务商', trigger: 'blur' },
-        accessKeyId: { required: true, message: '请输入正确的AccessKeyId', trigger: 'blur' },
-        accessKeySecret: { required: true, message: '请输入正确的AccessKeySecret', trigger: 'blur' },
+        issuer: { required: true, message: "请输入系统名称", trigger: "blur" },
+        domain: {
+          required: true,
+          message: "请输入需要申请证书的域名",
+          trigger: "blur",
+        },
+        legomail: {
+          required: true,
+          message: "请输入申请证书的邮箱地址",
+          trigger: "blur",
+        },
+        name: { required: true, message: "请选择域名服务商", trigger: "blur" },
       },
       certUpload: "/set/other/customcert",
       certFileList: [],
       keyFileList: [],
+      dnsProvider: {
+        aliyun: [
+          {
+            label: "APIKey",
+            prop: "apiKey",
+            component: "el-input",
+            type: "password",
+            rules: {
+              required: true,
+              message: "请输入正确的APIKey",
+              trigger: "blur",
+            },
+          },
+          {
+            label: "SecretKey",
+            prop: "secretKey",
+            component: "el-input",
+            type: "password",
+            rules: {
+              required: true,
+              message: "请输入正确的SecretKey",
+              trigger: "blur",
+            },
+          },
+        ],
+        txcloud: [
+          {
+            label: "SecretID",
+            prop: "secretId",
+            component: "el-input",
+            type: "password",
+            rules: {
+              required: true,
+              message: "请输入正确的APIKey",
+              trigger: "blur",
+            },
+          },
+          {
+            label: "SecretKey",
+            prop: "secretKey",
+            component: "el-input",
+            type: "password",
+            rules: {
+              required: true,
+              message: "请输入正确的APIKey",
+              trigger: "blur",
+            },
+          },
+        ],
+        cfcloud: [
+          {
+            label: "Email",
+            prop: "email",
+            component: "el-input",
+            type: "text",
+          },
+          {
+            label: "AuthKey",
+            prop: "authKey",
+            component: "el-input",
+            type: "password",
+            rules: {
+              required: true,
+              message: "请输入正确的APIKey",
+              trigger: "blur",
+            },
+          },
+        ],
+      },
     };
   },
   methods: {
@@ -233,164 +426,176 @@ export default {
       window.console.log(tab.name, event);
       switch (tab.name) {
         case "dataSmtp":
-          this.getSmtp()
-          break
+          this.getSmtp();
+          break;
         case "dataAuditLog":
-          this.getAuditLog()
-          break    
-        case "dataCert":
-          this.getCert()
-          break        
+          this.getAuditLog();
+          break;
+        case "letsCert":
+          this.getletsCert();
+          break;
         case "dataOther":
-          this.getOther()
-          break          
+          this.getOther();
+          break;
       }
     },
     beforeCertUpload(file) {
-        // if (file.type !== 'application/x-pem-file') {
-        //   this.$message.error('只能上传 .pem 格式的证书文件')
-        //   return false
-        // }
-        this.customCert.cert = file
-      },
-      beforeKeyUpload(file) {
-        // if (file.type !== 'application/x-pem-file') {
-        //   this.$message.error('只能上传 .pem 格式的私钥文件')
-        //   return false
-        // }
-        this.customCert.key = file
-      },
+      // if (file.type !== 'application/x-pem-file') {
+      //   this.$message.error('只能上传 .pem 格式的证书文件')
+      //   return false
+      // }
+      this.customCert.cert = file;
+    },
+    beforeKeyUpload(file) {
+      // if (file.type !== 'application/x-pem-file') {
+      //   this.$message.error('只能上传 .pem 格式的私钥文件')
+      //   return false
+      // }
+      this.customCert.key = file;
+    },
     getSmtp() {
-      axios.get('/set/other/smtp').then(resp => {
-        let rdata = resp.data
-        console.log(rdata)
-        if (rdata.code !== 0) {
-          this.$message.error(rdata.msg);
-          return;
-        }
-        this.dataSmtp = rdata.data
-      }).catch(error => {
-        this.$message.error('哦,请求出错');
-        console.log(error);
-      });
+      axios
+        .get("/set/other/smtp")
+        .then((resp) => {
+          let rdata = resp.data;
+          console.log(rdata);
+          if (rdata.code !== 0) {
+            this.$message.error(rdata.msg);
+            return;
+          }
+          this.dataSmtp = rdata.data;
+        })
+        .catch((error) => {
+          this.$message.error("哦,请求出错");
+          console.log(error);
+        });
     },
     getAuditLog() {
-      axios.get('/set/other/audit_log').then(resp => {
-        let rdata = resp.data
-        console.log(rdata)
-        if (rdata.code !== 0) {
-          this.$message.error(rdata.msg);
-          return;
-        }
-        this.dataAuditLog = rdata.data
-      }).catch(error => {
-        this.$message.error('哦,请求出错');
-        console.log(error);
-      });
-    }, 
-    getCert() {
-      axios.get('/set/other/getcertset').then(resp => {
-        let rdata = resp.data
-        console.log(rdata)
-        if (rdata.code !== 0) {
-          this.$message.error(rdata.msg);
-          return;
-        }
-        this.dataCert = rdata.data
-      }).catch(error => {
-        this.$message.error('哦,请求出错');
-        console.log(error);
-      });
+      axios
+        .get("/set/other/audit_log")
+        .then((resp) => {
+          let rdata = resp.data;
+          console.log(rdata);
+          if (rdata.code !== 0) {
+            this.$message.error(rdata.msg);
+            return;
+          }
+          this.dataAuditLog = rdata.data;
+        })
+        .catch((error) => {
+          this.$message.error("哦,请求出错");
+          console.log(error);
+        });
+    },
+    getletsCert() {
+      axios
+        .get("/set/other/getcertset")
+        .then((resp) => {
+          let rdata = resp.data;
+          console.log(rdata);
+          if (rdata.code !== 0) {
+            this.$message.error(rdata.msg);
+            return;
+          }
+          this.letsCert = Object.assign({}, this.letsCert, rdata.data);
+        })
+        .catch((error) => {
+          this.$message.error("哦,请求出错");
+          console.log(error);
+        });
     },
     getOther() {
-      axios.get('/set/other').then(resp => {
-        let rdata = resp.data
-        console.log(rdata)
-        if (rdata.code !== 0) {
-          this.$message.error(rdata.msg);
-          return;
-        }
-        this.dataOther = rdata.data
-      }).catch(error => {
-        this.$message.error('哦,请求出错');
-        console.log(error);
-      });
+      axios
+        .get("/set/other")
+        .then((resp) => {
+          let rdata = resp.data;
+          console.log(rdata);
+          if (rdata.code !== 0) {
+            this.$message.error(rdata.msg);
+            return;
+          }
+          this.dataOther = rdata.data;
+        })
+        .catch((error) => {
+          this.$message.error("哦,请求出错");
+          console.log(error);
+        });
     },
     submitForm(formName) {
       this.$refs[formName].validate((valid) => {
         if (!valid) {
-          alert('error submit!');
+          alert("error submit!");
         }
 
         switch (formName) {
           case "dataSmtp":
-            axios.post('/set/other/smtp/edit', this.dataSmtp).then(resp => {
-              var rdata = resp.data
+            axios.post("/set/other/smtp/edit", this.dataSmtp).then((resp) => {
+              var rdata = resp.data;
               console.log(rdata);
               if (rdata.code === 0) {
                 this.$message.success(rdata.msg);
               } else {
                 this.$message.error(rdata.msg);
               }
-
-            })
+            });
             break;
           case "dataAuditLog":
-            axios.post('/set/other/audit_log/edit', this.dataAuditLog).then(resp => {
-              var rdata = resp.data
-              console.log(rdata);
-              if (rdata.code === 0) {
-                this.$message.success(rdata.msg);
-              } else {
-                this.$message.error(rdata.msg);
-              }
-            })
+            axios
+              .post("/set/other/audit_log/edit", this.dataAuditLog)
+              .then((resp) => {
+                var rdata = resp.data;
+                console.log(rdata);
+                if (rdata.code === 0) {
+                  this.$message.success(rdata.msg);
+                } else {
+                  this.$message.error(rdata.msg);
+                }
+              });
             break;
-          case "dataCert":
-            axios.post('/set/other/createcert', this.dataCert).then(resp => {
-              var rdata = resp.data
+          case "letsCert":
+            axios.post("/set/other/createcert", this.letsCert).then((resp) => {
+              var rdata = resp.data;
               console.log(rdata);
               if (rdata.code === 0) {
                 this.$message.success(rdata.msg);
               } else {
                 this.$message.error(rdata.msg);
               }
-            })
+            });
             break;
           case "customCert":
-            var formData = new FormData()
-            formData.append('cert', this.customCert.cert)
-            formData.append('key', this.customCert.key)
-            axios.post(this.certUpload, formData).then(resp => {
-              var rdata = resp.data
+            var formData = new FormData();
+            formData.append("cert", this.customCert.cert);
+            formData.append("key", this.customCert.key);
+            axios.post(this.certUpload, formData).then((resp) => {
+              var rdata = resp.data;
               console.log(rdata);
               if (rdata.code === 0) {
                 this.$message.success(rdata.msg);
               } else {
                 this.$message.error(rdata.msg);
               }
-            })
-            break;       
+            });
+            break;
           case "dataOther":
-            axios.post('/set/other/edit', this.dataOther).then(resp => {
-              var rdata = resp.data
+            axios.post("/set/other/edit", this.dataOther).then((resp) => {
+              var rdata = resp.data;
               console.log(rdata);
               if (rdata.code === 0) {
                 this.$message.success(rdata.msg);
               } else {
                 this.$message.error(rdata.msg);
               }
-            })
+            });
             break;
         }
-
       });
     },
     resetForm(formName) {
       this.$refs[formName].resetFields();
-    }
+    },
   },
-}
+};
 </script>
 
 <style scoped>
@@ -399,8 +604,7 @@ export default {
 }
 
 .input_tip {
-    line-height: 1.428;    
-    margin:2px 0 0 0;
+  line-height: 1.428;
+  margin: 2px 0 0 0;
 }
-
 </style>