feat: AutoSSL certificate management tool with Web UI
This commit is contained in:
@@ -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>
|
||||
Reference in New Issue
Block a user