mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 14:57:16 +08:00
feat: 重构证书组件
This commit is contained in:
@@ -15,7 +15,7 @@ export default {
|
||||
// ACME 账号详情
|
||||
accountInfo: (id: number): Promise<AxiosResponse<any>> => request.get(`/cert/account/${id}`),
|
||||
// ACME 账号添加
|
||||
accountAdd: (data: any): Promise<AxiosResponse<any>> => request.post('/cert/account', data),
|
||||
accountCreate: (data: any): Promise<AxiosResponse<any>> => request.post('/cert/account', data),
|
||||
// ACME 账号更新
|
||||
accountUpdate: (id: number, data: any): Promise<AxiosResponse<any>> =>
|
||||
request.put(`/cert/account/${id}`, data),
|
||||
@@ -27,7 +27,7 @@ export default {
|
||||
// DNS 记录详情
|
||||
dnsInfo: (id: number): Promise<AxiosResponse<any>> => request.get(`/cert/dns/${id}`),
|
||||
// DNS 记录添加
|
||||
dnsAdd: (data: any): Promise<AxiosResponse<any>> => request.post('/cert/dns', data),
|
||||
dnsCreate: (data: any): Promise<AxiosResponse<any>> => request.post('/cert/dns', data),
|
||||
// DNS 记录更新
|
||||
dnsUpdate: (id: number, data: any): Promise<AxiosResponse<any>> =>
|
||||
request.put(`/cert/dns/${id}`, data),
|
||||
@@ -39,7 +39,7 @@ export default {
|
||||
// 证书详情
|
||||
certInfo: (id: number): Promise<AxiosResponse<any>> => request.get(`/cert/cert/${id}`),
|
||||
// 证书添加
|
||||
certAdd: (data: any): Promise<AxiosResponse<any>> => request.post('/cert/cert', data),
|
||||
certCreate: (data: any): Promise<AxiosResponse<any>> => request.post('/cert/cert', data),
|
||||
// 证书更新
|
||||
certUpdate: (id: number, data: any): Promise<AxiosResponse<any>> =>
|
||||
request.put(`/cert/cert/${id}`, data),
|
||||
|
||||
@@ -243,12 +243,10 @@ onMounted(() => {
|
||||
<template>
|
||||
<common-page show-footer>
|
||||
<template #action>
|
||||
<div flex items-center>
|
||||
<n-button type="primary" @click="handleUpdateCache">
|
||||
<TheIcon :size="18" icon="material-symbols:refresh" />
|
||||
{{ $t('appIndex.buttons.updateCache') }}
|
||||
</n-button>
|
||||
</div>
|
||||
<n-button type="primary" @click="handleUpdateCache">
|
||||
<TheIcon :size="18" icon="material-symbols:refresh" />
|
||||
{{ $t('appIndex.buttons.updateCache') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<n-flex vertical>
|
||||
<n-alert type="warning">{{ $t('appIndex.alerts.warning') }}</n-alert>
|
||||
|
||||
@@ -12,14 +12,15 @@ import {
|
||||
import cert from '@/api/panel/cert'
|
||||
import type { Account } from '@/views/cert/types'
|
||||
|
||||
let messageReactive: MessageReactive | null = null
|
||||
const addAccountModel = ref<any>({
|
||||
hmac_encoded: '',
|
||||
email: '',
|
||||
kid: '',
|
||||
key_type: 'P256',
|
||||
ca: 'googlecn'
|
||||
const props = defineProps({
|
||||
caProviders: Array<any>,
|
||||
algorithms: Array<any>
|
||||
})
|
||||
|
||||
const { caProviders, algorithms } = toRefs(props)
|
||||
|
||||
let messageReactive: MessageReactive | null = null
|
||||
|
||||
const updateAccountModel = ref<any>({
|
||||
hmac_encoded: '',
|
||||
email: '',
|
||||
@@ -27,17 +28,9 @@ const updateAccountModel = ref<any>({
|
||||
key_type: 'P256',
|
||||
ca: 'googlecn'
|
||||
})
|
||||
const addAccountModal = ref(false)
|
||||
const updateAccountModal = ref(false)
|
||||
const updateAccount = ref<any>()
|
||||
|
||||
const showEAB = computed(() => {
|
||||
return addAccountModel.value.ca === 'google' || addAccountModel.value.ca === 'sslcom'
|
||||
})
|
||||
|
||||
const caProviders = ref<any>([])
|
||||
const algorithms = ref<any>([])
|
||||
|
||||
const accountColumns: any = [
|
||||
{
|
||||
title: '邮箱',
|
||||
@@ -61,7 +54,7 @@ const accountColumns: any = [
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return caProviders.value.find((item: any) => item.value === row.ca)?.label
|
||||
return caProviders?.value?.find((item: any) => item.value === row.ca)?.label
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -164,20 +157,6 @@ const getAccountList = async (page: number, limit: number) => {
|
||||
return data
|
||||
}
|
||||
|
||||
const handleAddAccount = async () => {
|
||||
messageReactive = window.$message.loading('正在向 CA 注册账号,请耐心等待', {
|
||||
duration: 0
|
||||
})
|
||||
await cert.accountAdd(addAccountModel.value)
|
||||
messageReactive.destroy()
|
||||
window.$message.success('添加成功')
|
||||
addAccountModal.value = false
|
||||
onAccountPageChange(1)
|
||||
addAccountModel.value.email = ''
|
||||
addAccountModel.value.hmac_encoded = ''
|
||||
addAccountModel.value.kid = ''
|
||||
}
|
||||
|
||||
const handleUpdateAccount = async () => {
|
||||
messageReactive = window.$message.loading('正在向 CA 注册账号,请耐心等待', {
|
||||
duration: 0
|
||||
@@ -193,23 +172,12 @@ const handleUpdateAccount = async () => {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
cert.caProviders().then((res) => {
|
||||
caProviders.value = res.data
|
||||
})
|
||||
cert.algorithms().then((res) => {
|
||||
algorithms.value = res.data
|
||||
})
|
||||
onAccountPageChange(1)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-space vertical size="large">
|
||||
<n-card rounded-10>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="addAccountModal = true"> 添加账号 </n-button>
|
||||
</n-space>
|
||||
</n-card>
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
@@ -223,65 +191,6 @@ onMounted(() => {
|
||||
@update:page-size="onAccountPageSizeChange"
|
||||
/>
|
||||
</n-space>
|
||||
<n-modal
|
||||
v-model:show="addAccountModal"
|
||||
preset="card"
|
||||
title="添加账号"
|
||||
style="width: 60vw"
|
||||
size="huge"
|
||||
:bordered="false"
|
||||
:segmented="false"
|
||||
>
|
||||
<n-space vertical>
|
||||
<n-alert type="info"> Google 和 SSL.com 需要先去官网获得 KID 和 HMAC 并填入 </n-alert>
|
||||
<n-alert type="warning">
|
||||
境内无法使用 Google,其他 CA 视网络情况而定,建议使用 GoogleCN 或 Let's Encrypt
|
||||
</n-alert>
|
||||
<n-form :model="addAccountModel">
|
||||
<n-form-item path="ca" label="CA">
|
||||
<n-select
|
||||
v-model:value="addAccountModel.ca"
|
||||
placeholder="选择 CA"
|
||||
clearable
|
||||
:options="caProviders"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="key_type" label="密钥类型">
|
||||
<n-select
|
||||
v-model:value="addAccountModel.key_type"
|
||||
placeholder="选择密钥类型"
|
||||
clearable
|
||||
:options="algorithms"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="email" label="邮箱">
|
||||
<n-input
|
||||
v-model:value="addAccountModel.email"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入邮箱地址"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="showEAB" path="kid" label="KID">
|
||||
<n-input
|
||||
v-model:value="addAccountModel.kid"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入 KID"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="showEAB" path="hmac_encoded" label="HMAC">
|
||||
<n-input
|
||||
v-model:value="addAccountModel.hmac_encoded"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入 HMAC"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block @click="handleAddAccount">提交</n-button>
|
||||
</n-space>
|
||||
</n-modal>
|
||||
<n-modal
|
||||
v-model:show="updateAccountModal"
|
||||
preset="card"
|
||||
|
||||
@@ -2,20 +2,20 @@
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { NButton, NDataTable, NPopconfirm, NSpace, NSwitch, NTable, NTag } from 'naive-ui'
|
||||
|
||||
import app from '@/api/panel/app'
|
||||
import cert from '@/api/panel/cert'
|
||||
import website from '@/api/panel/website'
|
||||
import type { Cert } from '@/views/cert/types'
|
||||
|
||||
let messageReactive: any
|
||||
const addCertModel = ref<any>({
|
||||
domains: [],
|
||||
dns_id: 0,
|
||||
type: 'P256',
|
||||
account_id: null,
|
||||
website_id: 0,
|
||||
auto_renew: true
|
||||
const props = defineProps({
|
||||
algorithms: Array<any>,
|
||||
websites: Array<any>,
|
||||
accounts: Array<any>,
|
||||
dns: Array<any>
|
||||
})
|
||||
|
||||
const { algorithms, websites, accounts, dns } = toRefs(props)
|
||||
|
||||
let messageReactive: any
|
||||
|
||||
const updateCertModel = ref<any>({
|
||||
domains: [],
|
||||
dns_id: 0,
|
||||
@@ -24,7 +24,6 @@ const updateCertModel = ref<any>({
|
||||
website_id: 0,
|
||||
auto_renew: true
|
||||
})
|
||||
const addCertModal = ref(false)
|
||||
const updateCertModal = ref(false)
|
||||
const updateCert = ref<any>()
|
||||
const showModal = ref(false)
|
||||
@@ -38,11 +37,6 @@ const deployCertModel = ref<any>({
|
||||
website_id: 0
|
||||
})
|
||||
|
||||
const algorithms = ref<any>([])
|
||||
const websites = ref<any>([])
|
||||
const dns = ref<any>([])
|
||||
const accounts = ref<any>([])
|
||||
|
||||
const certColumns: any = [
|
||||
{
|
||||
title: '域名',
|
||||
@@ -398,20 +392,6 @@ const getCertList = async (page: number, limit: number) => {
|
||||
return data
|
||||
}
|
||||
|
||||
const handleAddCert = async () => {
|
||||
await cert.certAdd(addCertModel.value)
|
||||
window.$message.success('添加成功')
|
||||
addCertModal.value = false
|
||||
onCertPageChange(1)
|
||||
addCertModel.value.domains = []
|
||||
addCertModel.value.dns_id = 0
|
||||
addCertModel.value.type = 'P256'
|
||||
addCertModel.value.account_id = 0
|
||||
addCertModel.value.website_id = 0
|
||||
addCertModel.value.auto_renew = true
|
||||
await getAsyncData()
|
||||
}
|
||||
|
||||
const handleUpdateCert = async () => {
|
||||
await cert.certUpdate(updateCert.value, updateCertModel.value)
|
||||
window.$message.success('更新成功')
|
||||
@@ -423,7 +403,6 @@ const handleUpdateCert = async () => {
|
||||
updateCertModel.value.account_id = 0
|
||||
updateCertModel.value.website_id = 0
|
||||
updateCertModel.value.auto_renew = true
|
||||
await getAsyncData()
|
||||
}
|
||||
|
||||
const handleDeployCert = async () => {
|
||||
@@ -435,68 +414,18 @@ const handleDeployCert = async () => {
|
||||
onCertPageChange(1)
|
||||
}
|
||||
|
||||
const getAsyncData = async () => {
|
||||
const { data: algorithmData } = await cert.algorithms()
|
||||
algorithms.value = algorithmData
|
||||
|
||||
websites.value = []
|
||||
websites.value.push({
|
||||
label: '无',
|
||||
value: 0
|
||||
})
|
||||
app.isInstalled('nginx').then(async (res) => {
|
||||
if (res.data.installed) {
|
||||
const { data: websiteData } = await website.list(1, 10000)
|
||||
for (const item of websiteData.items) {
|
||||
websites.value.push({
|
||||
label: item.name,
|
||||
value: item.id
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const { data: dnsData } = await cert.dns(1, 10000)
|
||||
dns.value = []
|
||||
dns.value.push({
|
||||
label: '无',
|
||||
value: 0
|
||||
})
|
||||
for (const item of dnsData.items) {
|
||||
dns.value.push({
|
||||
label: item.name,
|
||||
value: item.id
|
||||
})
|
||||
}
|
||||
|
||||
const { data: accountData } = await cert.accounts(1, 10000)
|
||||
accounts.value = []
|
||||
for (const item of accountData.items) {
|
||||
accounts.value.push({
|
||||
label: item.email,
|
||||
value: item.id
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleShowModalClose = () => {
|
||||
showCertModel.value.cert = ''
|
||||
showCertModel.value.key = ''
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getAsyncData()
|
||||
onCertPageChange(1)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-space vertical size="large">
|
||||
<n-card rounded-10>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="addCertModal = true"> 添加证书 </n-button>
|
||||
</n-space>
|
||||
</n-card>
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
@@ -510,65 +439,6 @@ onMounted(() => {
|
||||
@update:page-size="onCertPageSizeChange"
|
||||
/>
|
||||
</n-space>
|
||||
<n-modal
|
||||
v-model:show="addCertModal"
|
||||
preset="card"
|
||||
title="添加证书"
|
||||
style="width: 60vw"
|
||||
size="huge"
|
||||
:bordered="false"
|
||||
:segmented="false"
|
||||
>
|
||||
<n-space vertical>
|
||||
<n-alert type="info">
|
||||
可以通过选择网站 / DNS 中的任意一项来自动签发和部署证书,也可以手动输入域名并设置 DNS
|
||||
解析来签发证书
|
||||
</n-alert>
|
||||
<n-form :model="addCertModel">
|
||||
<n-form-item label="域名">
|
||||
<n-dynamic-input
|
||||
v-model:value="addCertModel.domains"
|
||||
placeholder="example.com"
|
||||
:min="1"
|
||||
show-sort-button
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="type" label="密钥类型">
|
||||
<n-select
|
||||
v-model:value="addCertModel.type"
|
||||
placeholder="选择密钥类型"
|
||||
clearable
|
||||
:options="algorithms"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="website_id" label="网站">
|
||||
<n-select
|
||||
v-model:value="addCertModel.website_id"
|
||||
placeholder="选择用于部署证书的网站"
|
||||
clearable
|
||||
:options="websites"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="account_id" label="账号">
|
||||
<n-select
|
||||
v-model:value="addCertModel.account_id"
|
||||
placeholder="选择用于签发证书的账号"
|
||||
clearable
|
||||
:options="accounts"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="account_id" label="DNS">
|
||||
<n-select
|
||||
v-model:value="addCertModel.dns_id"
|
||||
placeholder="选择用于签发证书的DNS"
|
||||
clearable
|
||||
:options="dns"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block @click="handleAddCert">提交</n-button>
|
||||
</n-space>
|
||||
</n-modal>
|
||||
<n-modal
|
||||
v-model:show="updateCertModal"
|
||||
preset="card"
|
||||
|
||||
109
web/src/views/cert/CreateAccountModal.vue
Normal file
109
web/src/views/cert/CreateAccountModal.vue
Normal file
@@ -0,0 +1,109 @@
|
||||
<script setup lang="ts">
|
||||
import cert from '@/api/panel/cert'
|
||||
import type { MessageReactive } from 'naive-ui'
|
||||
import { NButton, NInput, NSpace } from 'naive-ui'
|
||||
|
||||
const show = defineModel<boolean>('show', { type: Boolean, required: true })
|
||||
|
||||
const props = defineProps({
|
||||
caProviders: Array<any>,
|
||||
algorithms: Array<any>
|
||||
})
|
||||
|
||||
const { caProviders, algorithms } = toRefs(props)
|
||||
|
||||
let messageReactive: MessageReactive | null = null
|
||||
|
||||
const model = ref<any>({
|
||||
hmac_encoded: '',
|
||||
email: '',
|
||||
kid: '',
|
||||
key_type: 'P256',
|
||||
ca: 'googlecn'
|
||||
})
|
||||
|
||||
const showEAB = computed(() => {
|
||||
return model.value.ca === 'google' || model.value.ca === 'sslcom'
|
||||
})
|
||||
|
||||
const handleCreateAccount = async () => {
|
||||
messageReactive = window.$message.loading('正在向 CA 注册账号,请耐心等待', {
|
||||
duration: 0
|
||||
})
|
||||
cert
|
||||
.accountCreate(model.value)
|
||||
.then(() => {
|
||||
window.$message.success('创建成功')
|
||||
model.value.email = ''
|
||||
model.value.hmac_encoded = ''
|
||||
model.value.kid = ''
|
||||
})
|
||||
.finally(() => {
|
||||
messageReactive?.destroy()
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-modal
|
||||
v-model:show="show"
|
||||
preset="card"
|
||||
title="创建账号"
|
||||
style="width: 60vw"
|
||||
size="huge"
|
||||
:bordered="false"
|
||||
:segmented="false"
|
||||
>
|
||||
<n-space vertical>
|
||||
<n-alert type="info"> Google 和 SSL.com 需要先去官网获得 KID 和 HMAC 并填入 </n-alert>
|
||||
<n-alert type="warning">
|
||||
境内无法使用 Google,其他 CA 视网络情况而定,建议使用 GoogleCN 或 Let's Encrypt
|
||||
</n-alert>
|
||||
<n-form :model="model">
|
||||
<n-form-item path="ca" label="CA">
|
||||
<n-select
|
||||
v-model:value="model.ca"
|
||||
placeholder="选择 CA"
|
||||
clearable
|
||||
:options="caProviders"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="key_type" label="密钥类型">
|
||||
<n-select
|
||||
v-model:value="model.key_type"
|
||||
placeholder="选择密钥类型"
|
||||
clearable
|
||||
:options="algorithms"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="email" label="邮箱">
|
||||
<n-input
|
||||
v-model:value="model.email"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入邮箱地址"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="showEAB" path="kid" label="KID">
|
||||
<n-input
|
||||
v-model:value="model.kid"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入 KID"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="showEAB" path="hmac_encoded" label="HMAC">
|
||||
<n-input
|
||||
v-model:value="model.hmac_encoded"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入 HMAC"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block @click="handleCreateAccount">提交</n-button>
|
||||
</n-space>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
100
web/src/views/cert/CreateCertModal.vue
Normal file
100
web/src/views/cert/CreateCertModal.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<script setup lang="ts">
|
||||
import cert from '@/api/panel/cert'
|
||||
import { NButton, NSpace } from 'naive-ui'
|
||||
|
||||
const show = defineModel<boolean>('show', { type: Boolean, required: true })
|
||||
|
||||
const props = defineProps({
|
||||
algorithms: Array<any>,
|
||||
websites: Array<any>,
|
||||
accounts: Array<any>,
|
||||
dns: Array<any>
|
||||
})
|
||||
|
||||
const { algorithms, websites, accounts, dns } = toRefs(props)
|
||||
|
||||
const model = ref<any>({
|
||||
domains: [],
|
||||
dns_id: 0,
|
||||
type: 'P256',
|
||||
account_id: null,
|
||||
website_id: 0,
|
||||
auto_renew: true
|
||||
})
|
||||
|
||||
const handleCreateCert = async () => {
|
||||
await cert.certCreate(model.value)
|
||||
window.$message.success('创建成功')
|
||||
model.value = false
|
||||
model.value.domains = []
|
||||
model.value.dns_id = 0
|
||||
model.value.type = 'P256'
|
||||
model.value.account_id = 0
|
||||
model.value.website_id = 0
|
||||
model.value.auto_renew = true
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-modal
|
||||
v-model:show="show"
|
||||
preset="card"
|
||||
title="创建证书"
|
||||
style="width: 60vw"
|
||||
size="huge"
|
||||
:bordered="false"
|
||||
:segmented="false"
|
||||
>
|
||||
<n-space vertical>
|
||||
<n-alert type="info">
|
||||
可以通过选择网站 / DNS 中的任意一项来自动签发和部署证书,也可以手动输入域名并设置 DNS
|
||||
解析来签发证书
|
||||
</n-alert>
|
||||
<n-form :model="model">
|
||||
<n-form-item label="域名">
|
||||
<n-dynamic-input
|
||||
v-model:value="model.domains"
|
||||
placeholder="example.com"
|
||||
:min="1"
|
||||
show-sort-button
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="type" label="密钥类型">
|
||||
<n-select
|
||||
v-model:value="model.type"
|
||||
placeholder="选择密钥类型"
|
||||
clearable
|
||||
:options="algorithms"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="website_id" label="网站">
|
||||
<n-select
|
||||
v-model:value="model.website_id"
|
||||
placeholder="选择用于部署证书的网站"
|
||||
clearable
|
||||
:options="websites"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="account_id" label="账号">
|
||||
<n-select
|
||||
v-model:value="model.account_id"
|
||||
placeholder="选择用于签发证书的账号"
|
||||
clearable
|
||||
:options="accounts"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="account_id" label="DNS">
|
||||
<n-select
|
||||
v-model:value="model.dns_id"
|
||||
placeholder="选择用于签发证书的DNS"
|
||||
clearable
|
||||
:options="dns"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block @click="handleCreateCert">提交</n-button>
|
||||
</n-space>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
122
web/src/views/cert/CreateDnsModal.vue
Normal file
122
web/src/views/cert/CreateDnsModal.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<script setup lang="ts">
|
||||
import cert from '@/api/panel/cert'
|
||||
import { NButton, NInput, NSpace } from 'naive-ui'
|
||||
|
||||
const show = defineModel<boolean>('show', { type: Boolean, required: true })
|
||||
|
||||
const props = defineProps({
|
||||
dnsProviders: Array<any>
|
||||
})
|
||||
|
||||
const { dnsProviders } = toRefs(props)
|
||||
|
||||
const model = ref<any>({
|
||||
data: {
|
||||
ak: '',
|
||||
sk: ''
|
||||
},
|
||||
type: 'aliyun',
|
||||
name: ''
|
||||
})
|
||||
|
||||
const handleCreateDNS = async () => {
|
||||
await cert.dnsCreate(model.value)
|
||||
window.$message.success('创建成功')
|
||||
show.value = false
|
||||
model.value.data.ak = ''
|
||||
model.value.data.sk = ''
|
||||
model.value.name = ''
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-modal
|
||||
v-model:show="show"
|
||||
preset="card"
|
||||
title="创建 DNS"
|
||||
style="width: 60vw"
|
||||
size="huge"
|
||||
:bordered="false"
|
||||
:segmented="false"
|
||||
>
|
||||
<n-space vertical>
|
||||
<n-form :model="model">
|
||||
<n-form-item path="name" label="备注名称">
|
||||
<n-input
|
||||
v-model:value="model.name"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入备注名称"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="type" label="DNS">
|
||||
<n-select
|
||||
v-model:value="model.type"
|
||||
placeholder="选择 DNS"
|
||||
clearable
|
||||
:options="dnsProviders"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="model.type == 'aliyun'" path="ak" label="Access Key">
|
||||
<n-input
|
||||
v-model:value="model.data.ak"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入阿里云 Access Key"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="model.type == 'aliyun'" path="sk" label="Secret Key">
|
||||
<n-input
|
||||
v-model:value="model.data.sk"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入阿里云 Secret Key"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="model.type == 'tencent'" path="ak" label="SecretId">
|
||||
<n-input
|
||||
v-model:value="model.data.ak"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入腾讯云 SecretId"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="model.type == 'tencent'" path="sk" label="SecretKey">
|
||||
<n-input
|
||||
v-model:value="model.data.sk"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入腾讯云 SecretKey"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="model.type == 'huawei'" path="ak" label="AccessKeyId">
|
||||
<n-input
|
||||
v-model:value="model.data.ak"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入华为云 AccessKeyId"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="model.type == 'huawei'" path="sk" label="SecretAccessKey">
|
||||
<n-input
|
||||
v-model:value="model.data.sk"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入华为云 SecretAccessKey"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="model.type == 'cloudflare'" path="ak" label="API Key">
|
||||
<n-input
|
||||
v-model:value="model.data.ak"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入 Cloudflare API Key"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block @click="handleCreateDNS">提交</n-button>
|
||||
</n-space>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
@@ -4,14 +4,12 @@ import { NButton, NDataTable, NInput, NPopconfirm, NSpace, NTag } from 'naive-ui
|
||||
import cert from '@/api/panel/cert'
|
||||
import type { DNS } from '@/views/cert/types'
|
||||
|
||||
const addDNSModel = ref<any>({
|
||||
data: {
|
||||
ak: '',
|
||||
sk: ''
|
||||
},
|
||||
type: 'aliyun',
|
||||
name: ''
|
||||
const props = defineProps({
|
||||
dnsProviders: Array<any>
|
||||
})
|
||||
|
||||
const { dnsProviders } = toRefs(props)
|
||||
|
||||
const updateDNSModel = ref<any>({
|
||||
data: {
|
||||
ak: '',
|
||||
@@ -20,12 +18,9 @@ const updateDNSModel = ref<any>({
|
||||
type: 'aliyun',
|
||||
name: ''
|
||||
})
|
||||
const addDNSModal = ref(false)
|
||||
const updateDNSModal = ref(false)
|
||||
const updateDNS = ref<any>()
|
||||
|
||||
const dnsProviders = ref<any>([])
|
||||
|
||||
const dnsColumns: any = [
|
||||
{
|
||||
title: '备注名称',
|
||||
@@ -155,16 +150,6 @@ const getDnsList = async (page: number, limit: number) => {
|
||||
return data
|
||||
}
|
||||
|
||||
const handleAddDNS = async () => {
|
||||
await cert.dnsAdd(addDNSModel.value)
|
||||
window.$message.success('添加成功')
|
||||
addDNSModal.value = false
|
||||
onDnsPageChange(1)
|
||||
addDNSModel.value.data.ak = ''
|
||||
addDNSModel.value.data.sk = ''
|
||||
addDNSModel.value.name = ''
|
||||
}
|
||||
|
||||
const handleUpdateDNS = async () => {
|
||||
await cert.dnsUpdate(updateDNS.value, updateDNSModel.value)
|
||||
window.$message.success('更新成功')
|
||||
@@ -176,20 +161,12 @@ const handleUpdateDNS = async () => {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
cert.dnsProviders().then((res) => {
|
||||
dnsProviders.value = res.data
|
||||
})
|
||||
onDnsPageChange(1)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-space vertical size="large">
|
||||
<n-card rounded-10>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="addDNSModal = true"> 添加 DNS </n-button>
|
||||
</n-space>
|
||||
</n-card>
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
@@ -203,93 +180,6 @@ onMounted(async () => {
|
||||
@update:page-size="onDnsPageSizeChange"
|
||||
/>
|
||||
</n-space>
|
||||
<n-modal
|
||||
v-model:show="addDNSModal"
|
||||
preset="card"
|
||||
title="添加 DNS"
|
||||
style="width: 60vw"
|
||||
size="huge"
|
||||
:bordered="false"
|
||||
:segmented="false"
|
||||
>
|
||||
<n-space vertical>
|
||||
<n-form :model="addDNSModel">
|
||||
<n-form-item path="name" label="备注名称">
|
||||
<n-input
|
||||
v-model:value="addDNSModel.name"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入备注名称"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="type" label="DNS">
|
||||
<n-select
|
||||
v-model:value="addDNSModel.type"
|
||||
placeholder="选择 DNS"
|
||||
clearable
|
||||
:options="dnsProviders"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="addDNSModel.type == 'aliyun'" path="ak" label="Access Key">
|
||||
<n-input
|
||||
v-model:value="addDNSModel.data.ak"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入阿里云 Access Key"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="addDNSModel.type == 'aliyun'" path="sk" label="Secret Key">
|
||||
<n-input
|
||||
v-model:value="addDNSModel.data.sk"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入阿里云 Secret Key"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="addDNSModel.type == 'tencent'" path="ak" label="SecretId">
|
||||
<n-input
|
||||
v-model:value="addDNSModel.data.ak"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入腾讯云 SecretId"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="addDNSModel.type == 'tencent'" path="sk" label="SecretKey">
|
||||
<n-input
|
||||
v-model:value="addDNSModel.data.sk"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入腾讯云 SecretKey"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="addDNSModel.type == 'huawei'" path="ak" label="AccessKeyId">
|
||||
<n-input
|
||||
v-model:value="addDNSModel.data.ak"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入华为云 AccessKeyId"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="addDNSModel.type == 'huawei'" path="sk" label="SecretAccessKey">
|
||||
<n-input
|
||||
v-model:value="addDNSModel.data.sk"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入华为云 SecretAccessKey"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="addDNSModel.type == 'cloudflare'" path="ak" label="API Key">
|
||||
<n-input
|
||||
v-model:value="addDNSModel.data.ak"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入 Cloudflare API Key"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block @click="handleAddDNS">提交</n-button>
|
||||
</n-space>
|
||||
</n-modal>
|
||||
<n-modal
|
||||
v-model:show="updateDNSModal"
|
||||
preset="card"
|
||||
|
||||
@@ -3,25 +3,125 @@ defineOptions({
|
||||
name: 'cert-index'
|
||||
})
|
||||
|
||||
import { NButton } from 'naive-ui'
|
||||
|
||||
import app from '@/api/panel/app'
|
||||
import cert from '@/api/panel/cert'
|
||||
import website from '@/api/panel/website'
|
||||
import AccountView from '@/views/cert/AccountView.vue'
|
||||
import CertView from '@/views/cert/CertView.vue'
|
||||
import CreateAccountModal from '@/views/cert/CreateAccountModal.vue'
|
||||
import CreateCertModal from '@/views/cert/CreateCertModal.vue'
|
||||
import CreateDnsModal from '@/views/cert/CreateDnsModal.vue'
|
||||
import DnsView from '@/views/cert/DnsView.vue'
|
||||
|
||||
const currentTab = ref('cert')
|
||||
|
||||
const createDNS = ref(false)
|
||||
const createCert = ref(false)
|
||||
const createAccount = ref(false)
|
||||
|
||||
const algorithms = ref<any>([])
|
||||
const websites = ref<any>([])
|
||||
const dns = ref<any>([])
|
||||
const accounts = ref<any>([])
|
||||
const dnsProviders = ref<any>([])
|
||||
const caProviders = ref<any>([])
|
||||
|
||||
const getAsyncData = async () => {
|
||||
const { data: algorithmData } = await cert.algorithms()
|
||||
algorithms.value = algorithmData
|
||||
|
||||
websites.value = []
|
||||
websites.value.push({
|
||||
label: '无',
|
||||
value: 0
|
||||
})
|
||||
app.isInstalled('nginx').then(async (res) => {
|
||||
if (res.data.installed) {
|
||||
const { data: websiteData } = await website.list(1, 10000)
|
||||
for (const item of websiteData.items) {
|
||||
websites.value.push({
|
||||
label: item.name,
|
||||
value: item.id
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const { data: dnsData } = await cert.dns(1, 10000)
|
||||
dns.value = []
|
||||
dns.value.push({
|
||||
label: '无',
|
||||
value: 0
|
||||
})
|
||||
for (const item of dnsData.items) {
|
||||
dns.value.push({
|
||||
label: item.name,
|
||||
value: item.id
|
||||
})
|
||||
}
|
||||
|
||||
const { data: accountData } = await cert.accounts(1, 10000)
|
||||
accounts.value = []
|
||||
for (const item of accountData.items) {
|
||||
accounts.value.push({
|
||||
label: item.email,
|
||||
value: item.id
|
||||
})
|
||||
}
|
||||
|
||||
const { data: dnsProviderData } = await cert.dnsProviders()
|
||||
dnsProviders.value = dnsProviderData
|
||||
|
||||
const { data: caProviderData } = await cert.caProviders()
|
||||
caProviders.value = caProviderData
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getAsyncData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<common-page show-footer>
|
||||
<template #action>
|
||||
<n-button v-if="currentTab == 'cert'" type="primary" @click="createCert = true">
|
||||
<TheIcon :size="18" icon="material-symbols:add" />
|
||||
创建证书
|
||||
</n-button>
|
||||
<n-button v-if="currentTab == 'user'" type="primary" @click="createAccount = true">
|
||||
<TheIcon :size="18" icon="material-symbols:add" />
|
||||
创建账号
|
||||
</n-button>
|
||||
<n-button v-if="currentTab == 'dns'" type="primary" @click="createDNS = true">
|
||||
<TheIcon :size="18" icon="material-symbols:add" />
|
||||
创建 DNS
|
||||
</n-button>
|
||||
</template>
|
||||
<n-tabs v-model:value="currentTab" type="line" animated>
|
||||
<n-tab-pane name="cert" tab="证书列表">
|
||||
<cert-view />
|
||||
<cert-view :accounts="accounts" :algorithms="algorithms" :websites="websites" :dns="dns" />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="user" tab="账号列表">
|
||||
<account-view />
|
||||
<account-view :ca-providers="caProviders" :algorithms="algorithms" />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="dns" tab="DNS 列表">
|
||||
<dns-view />
|
||||
<dns-view :dns-providers="dnsProviders" />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</common-page>
|
||||
<create-cert-modal
|
||||
v-model:show="createCert"
|
||||
:accounts="accounts"
|
||||
:algorithms="algorithms"
|
||||
:websites="websites"
|
||||
:dns="dns"
|
||||
/>
|
||||
<create-dns-modal v-model:show="createDNS" :dns-providers="dnsProviders" />
|
||||
<create-account-modal
|
||||
v-model:show="createAccount"
|
||||
:ca-providers="caProviders"
|
||||
:algorithms="algorithms"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -234,12 +234,10 @@ onUnmounted(() => {
|
||||
<template>
|
||||
<common-page show-footer>
|
||||
<template #action>
|
||||
<div flex items-center>
|
||||
<n-button type="primary" @click="create = true">
|
||||
<TheIcon :size="18" icon="material-symbols:add" />
|
||||
创建主机
|
||||
</n-button>
|
||||
</div>
|
||||
<n-button type="primary" @click="create = true">
|
||||
<TheIcon :size="18" icon="material-symbols:add" />
|
||||
创建主机
|
||||
</n-button>
|
||||
</template>
|
||||
<n-layout has-sider sider-placement="right">
|
||||
<n-layout content-style="overflow: visible" bg-hex-111>
|
||||
|
||||
@@ -3,19 +3,17 @@ import cronstrue from 'cronstrue'
|
||||
import 'cronstrue/locales/zh_CN'
|
||||
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { NButton, NDataTable, NFlex, NInput, NPopconfirm, NSwitch, NTag } from 'naive-ui'
|
||||
import { NButton, NDataTable, NInput, NPopconfirm, NSwitch, NTag } from 'naive-ui'
|
||||
|
||||
import cron from '@/api/panel/cron'
|
||||
import file from '@/api/panel/file'
|
||||
import { formatDateTime, renderIcon } from '@/utils'
|
||||
import CreateModal from '@/views/task/CreateModal.vue'
|
||||
import type { CronTask } from '@/views/task/types'
|
||||
import { CronNaive } from '@vue-js-cron/naive-ui'
|
||||
|
||||
const logPath = ref('')
|
||||
const logModal = ref(false)
|
||||
const editModal = ref(false)
|
||||
const create = ref(false)
|
||||
|
||||
const columns: any = [
|
||||
{ type: 'selection', fixed: 'left' },
|
||||
@@ -232,36 +230,27 @@ const saveTaskEdit = async () => {
|
||||
})
|
||||
}
|
||||
|
||||
watch(create, () => {
|
||||
onPageChange(pagination.page)
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
onPageChange(pagination.page)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-flex vertical>
|
||||
<n-card flex-1 rounded-10>
|
||||
<n-button type="primary" @click="create = true">创建计划任务</n-button>
|
||||
</n-card>
|
||||
<n-card flex-1 rounded-10>
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
:scroll-x="1300"
|
||||
:data="data"
|
||||
:columns="columns"
|
||||
:row-key="(row: any) => row.id"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:loading="false"
|
||||
@update:page="onPageChange"
|
||||
@update:page-size="onPageSizeChange"
|
||||
/>
|
||||
</n-card>
|
||||
</n-flex>
|
||||
<n-card flex-1 rounded-10>
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
:scroll-x="1300"
|
||||
:data="data"
|
||||
:columns="columns"
|
||||
:row-key="(row: any) => row.id"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:loading="false"
|
||||
@update:page="onPageChange"
|
||||
@update:page-size="onPageSizeChange"
|
||||
/>
|
||||
</n-card>
|
||||
<realtime-log-modal v-model:show="logModal" :path="logPath" />
|
||||
<n-modal
|
||||
v-model:show="editModal"
|
||||
@@ -294,5 +283,4 @@ onMounted(() => {
|
||||
}"
|
||||
/>
|
||||
</n-modal>
|
||||
<create-modal v-model:show="create" />
|
||||
</template>
|
||||
|
||||
@@ -1,16 +1,28 @@
|
||||
<script setup lang="ts">
|
||||
import { NButton } from 'naive-ui'
|
||||
|
||||
defineOptions({
|
||||
name: 'task-index'
|
||||
})
|
||||
|
||||
import TheIcon from '@/components/custom/TheIcon.vue'
|
||||
import CreateModal from '@/views/task/CreateModal.vue'
|
||||
import CronView from '@/views/task/CronView.vue'
|
||||
import TaskView from '@/views/task/TaskView.vue'
|
||||
|
||||
const current = ref('cron')
|
||||
|
||||
const create = ref(false)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<common-page show-footer>
|
||||
<template #action>
|
||||
<n-button v-if="current == 'cron'" type="primary" @click="create = true">
|
||||
<TheIcon :size="18" icon="material-symbols:add" />
|
||||
创建任务
|
||||
</n-button>
|
||||
</template>
|
||||
<n-tabs v-model:value="current" type="line" animated size="large">
|
||||
<n-tab-pane name="cron" tab="计划任务">
|
||||
<cron-view />
|
||||
@@ -20,6 +32,7 @@ const current = ref('cron')
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</common-page>
|
||||
<create-modal v-model:show="create" />
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
Reference in New Issue
Block a user