feat: AutoSSL certificate management tool with Web UI

This commit is contained in:
2026-05-12 14:55:10 +08:00
commit 1775d4b4fc
28 changed files with 2357 additions and 0 deletions
+167
View File
@@ -0,0 +1,167 @@
<template>
<div class="cert-create">
<h2 class="page-title">申请新证书</h2>
<el-card>
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="140px"
style="max-width: 600px"
>
<el-form-item label="域名" prop="domain">
<el-input v-model="form.domain" placeholder="example.com" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="admin@example.com" />
</el-form-item>
<el-form-item label="ACME 提供商" prop="provider">
<el-radio-group v-model="form.provider">
<el-radio value="letsencrypt">Let's Encrypt</el-radio>
<el-radio value="zerossl">ZeroSSL</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="验证方式" prop="challenge_type">
<el-radio-group v-model="form.challenge_type" @change="onChallengeChange">
<el-radio value="http">HTTP-01(推荐)</el-radio>
<el-radio value="dns">DNS-01</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="DNS 提供商" v-if="form.challenge_type === 'dns'" prop="dns_provider">
<el-select v-model="form.dns_provider" placeholder="选择 DNS 提供商" style="width: 100%">
<el-option label="阿里云 DNS (Aliyun)" value="alidns" />
<el-option label="Cloudflare" value="cloudflare" />
<el-option label="DNSPod" value="dnspod" />
</el-select>
</el-form-item>
<!-- Aliyun DNS Config -->
<template v-if="form.challenge_type === 'dns' && form.dns_provider === 'alidns'">
<el-form-item label="AccessKey ID" prop="ali_key">
<el-input v-model="dnsConfig.ali_key" placeholder="Aliyun AccessKey ID" />
</el-form-item>
<el-form-item label="AccessKey Secret" prop="ali_secret">
<el-input v-model="dnsConfig.ali_secret" type="password" show-password placeholder="Aliyun AccessKey Secret" />
</el-form-item>
</template>
<!-- Cloudflare Config -->
<template v-if="form.challenge_type === 'dns' && form.dns_provider === 'cloudflare'">
<el-form-item label="API Token">
<el-input v-model="dnsConfig.cf_api_token" type="password" show-password placeholder="Cloudflare API Token" />
</el-form-item>
</template>
<!-- DNSPod Config -->
<template v-if="form.challenge_type === 'dns' && form.dns_provider === 'dnspod'">
<el-form-item label="ID">
<el-input v-model="dnsConfig.dnspod_id" placeholder="DNSPod ID" />
</el-form-item>
<el-form-item label="Key">
<el-input v-model="dnsConfig.dnspod_key" type="password" show-password placeholder="DNSPod Key" />
</el-form-item>
</template>
<el-form-item label="自动续期">
<el-switch v-model="form.auto_renew" />
</el-form-item>
<el-form-item v-if="form.auto_renew" label="提前续期天数">
<el-input-number v-model="form.renew_days" :min="1" :max="60" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSubmit" :loading="submitting">
<el-icon><Plus /></el-icon> 提交申请
</el-button>
<el-button @click="$router.push('/certificates')">取消</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { certApi } from '../api'
import { ElMessage } from 'element-plus'
import { useRouter } from 'vue-router'
const router = useRouter()
const formRef = ref()
const submitting = ref(false)
const form = reactive({
domain: '',
email: '',
provider: 'letsencrypt',
challenge_type: 'http',
dns_provider: 'alidns',
auto_renew: true,
renew_days: 30,
})
const dnsConfig = reactive({
ali_key: '',
ali_secret: '',
cf_api_token: '',
dnspod_id: '',
dnspod_key: '',
})
const rules = {
domain: [{ required: true, message: '请输入域名', trigger: 'blur' }],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '邮箱格式不正确', trigger: 'blur' },
],
}
const onChallengeChange = () => {
// Reset DNS config when switching
Object.keys(dnsConfig).forEach(k => (dnsConfig as any)[k] = '')
}
const handleSubmit = async () => {
const valid = await formRef.value.validate().catch(() => false)
if (!valid) return
submitting.value = true
try {
const payload: any = {
domain: form.domain,
email: form.email,
provider: form.provider,
challenge_type: form.challenge_type,
auto_renew: form.auto_renew,
renew_days: form.renew_days,
}
if (form.challenge_type === 'dns') {
payload.dns_provider = form.dns_provider
payload.dns_config = JSON.stringify(dnsConfig)
}
await certApi.create(payload)
ElMessage.success(`证书申请已提交,后台处理中`)
router.push('/certificates')
} catch (e: any) {
ElMessage.error('提交失败: ' + (e.response?.data?.error || e.message))
} finally {
submitting.value = false
}
}
</script>
<style scoped>
.page-title {
margin-bottom: 20px;
font-size: 24px;
color: #1a1a2e;
}
</style>