【调整】SSH地址支持域名形式

【新增】支持自定义监控端口
【新增】通知类型-企业微信
【新增】申请证书(Buypass)、自定义ACME服务器地址
【新增】授权API管理(namesilo、Bunny、Gcore、name.com、京东云)
This commit is contained in:
chudong
2025-06-07 17:37:42 +08:00
parent 87ae1c9570
commit f0d83d23c6
106 changed files with 1570 additions and 223 deletions

View File

@@ -1,20 +1,65 @@
import { NCard, NSpace, NDescriptions, NDescriptionsItem, NIcon, NButton } from 'naive-ui'
import { NCard, NSpace, NDescriptions, NDescriptionsItem, NIcon, NButton, NBadge, NAlert } from 'naive-ui'
import { $t } from '@locales/index'
import { LogoGithub } from '@vicons/ionicons5'
import { getVersion } from '@api/setting'
import type { VersionData } from '@/types/setting'
/**
* 关于我们标签页组件
*/
export default defineComponent({
name: 'AboutSettings',
setup() {
// 版本检查相关状态
const versionData = ref<VersionData | null>(null)
const hasUpdate = ref(false)
// 版本检查API
const versionApi = getVersion()
// 检查版本更新
const checkVersion = async () => {
try {
await versionApi.fetch()
if (versionApi.data.value && versionApi.data.value.data) {
const data = versionApi.data.value.data
versionData.value = data
hasUpdate.value = data.update === '1'
}
} catch (error) {
console.error('检查版本更新失败:', error)
}
}
// 跳转到GitHub
const goToGitHub = () => {
window.open('https://github.com/allinssl/allinssl', '_blank')
}
// 组件挂载时检查版本
onMounted(() => {
checkVersion()
})
return () => (
<div class="about-settings">
<NCard title={$t('t_4_1745833932780')} class="mb-4">
<NSpace vertical size={24}>
<NDescriptions bordered>
<NDescriptionsItem label={$t('t_5_1745833933241')}>
<div class="flex items-center">
<span class="text-[2rem] font-medium">v1.0.4</span>
<div class="flex items-center space-x-[1.2rem]">
<span class="text-[2.0rem] font-medium">v1.0.4</span>
{hasUpdate.value && versionData.value && (
<div class="relative">
<NBadge value="NEW" type="success" offset={[4, -3]}>
<span
class="text-[1.4rem] text-primary cursor-pointer font-medium inline-block px-[.8rem] py-[.4rem]"
onClick={goToGitHub}
>
{versionData.value.new_version}
</span>
</NBadge>
</div>
)}
</div>
</NDescriptionsItem>
<NDescriptionsItem label={$t('t_29_1746667589773')}>
@@ -22,7 +67,7 @@ export default defineComponent({
<NIcon size="20" class="text-gray-600">
<LogoGithub />
</NIcon>
<NButton text tag="a" href="https://github.com/allinssl/allinssl" target="_blank" type="primary">
<NButton text onClick={goToGitHub} type="primary">
https://github.com/allinssl/allinssl
</NButton>
</div>
@@ -31,6 +76,33 @@ export default defineComponent({
</NSpace>
</NCard>
{/* 新版本信息卡片 */}
{hasUpdate.value && versionData.value && (
<NCard title="发现新版本" class="mb-4">
<NAlert type="info" title={`新版本 ${versionData.value.new_version} 已发布`} class="mb-[1.6rem]">
<div class="text-[1.4rem]">
<div class="mb-[1.2rem] text-[1.4rem]">: {versionData.value.date}</div>
<div class="mb-[1.2rem] text-[1.4rem]">
<strong>:</strong>
</div>
<div class="whitespace-pre-line text-gray-700 text-[1.3rem] leading-relaxed">
{versionData.value.log.replace(/\\r\\n/g, '\n').replace(/\\n/g, '\n')}
</div>
<div class="mt-4">
<NButton size="medium" type="primary" onClick={goToGitHub}>
<div class="flex items-center">
<NIcon size="18" class="mr-2">
<LogoGithub />
</NIcon>
GitHub下载
</div>
</NButton>
</div>
</div>
</NAlert>
</NCard>
)}
<NCard title={$t('t_13_1745833933630')} class="mb-4">
<div class="about-content">
<p class="text-gray-700 leading-relaxed">

View File

@@ -65,6 +65,19 @@ export default defineComponent({
return () => (
<div class="webhook-channel-form">
<WebhookForm labelPlacement="top"></WebhookForm>
{/* 模板变量说明 */}
<div class="mt-4 p-4 bg-gray-50 rounded-md">
<div class="font-medium text-gray-700 mb-3 text-xl"></div>
<div class="text-gray-600 space-y-3 text-lg">
<div>
<code class="px-2 py-1 bg-gray-200 rounded text-lg font-mono">__subject__</code>
</div>
<div>
<code class="px-2 py-1 bg-gray-200 rounded text-lg font-mono">__body__</code>
</div>
</div>
</div>
</div>
)
},

View File

@@ -0,0 +1,94 @@
import { useForm, useModalHooks } from '@baota/naive-ui/hooks'
import { useError } from '@baota/hooks/error'
import { useWecomChannelFormController } from './useController'
import { useStore } from '@settings/useStore'
import type { ReportWecom, ReportType } from '@/types/setting'
/**
* 企业微信通知渠道表单组件
*/
export default defineComponent({
name: 'WecomChannelModel',
props: {
data: {
type: Object as PropType<ReportType<ReportWecom> | null>,
default: () => null,
},
},
setup(props: { data: ReportType<ReportWecom> | null }) {
const { handleError } = useError()
const { confirm } = useModalHooks()
const { fetchNotifyChannels } = useStore()
const { config, rules, wecomChannelForm, submitForm } = useWecomChannelFormController()
if (props.data) {
const { name, config } = props.data
wecomChannelForm.value = {
name,
...config,
}
}
// 使用表单hooks
const {
component: WecomForm,
example,
data,
} = useForm({
config,
defaultValue: wecomChannelForm,
rules,
})
// 关联确认按钮
confirm(async (close) => {
try {
const { name, ...other } = data.value
await example.value?.validate()
const res = await submitForm(
{
type: 'workwx',
name: name || '',
config: other,
},
example,
props.data?.id,
)
fetchNotifyChannels()
if (res) close()
} catch (error) {
handleError(error)
}
})
return () => (
<div class="wecom-channel-form">
<WecomForm labelPlacement="top"></WecomForm>
{/* 模板变量说明 */}
<div class="mt-4 p-4 bg-gray-50 rounded-md">
<div class="font-medium text-gray-700 mb-3 text-xl"></div>
<div class="text-gray-600 space-y-3 text-lg">
<div>
<code class="px-2 py-1 bg-gray-200 rounded text-lg font-mono">__subject__</code>
</div>
<div>
<code class="px-2 py-1 bg-gray-200 rounded text-lg font-mono">__body__</code>
</div>
</div>
<div class="mt-4 pt-3 border-t border-gray-200">
<a
href="https://developer.work.weixin.qq.com/document/path/91770"
target="_blank"
class="hover:opacity-80 text-xl"
style="color: #20a50a"
>
📖
</a>
</div>
</div>
</div>
)
},
})

View File

@@ -3,13 +3,21 @@ import { useFormHooks, useLoadingMask } from '@baota/naive-ui/hooks'
import { useError } from '@baota/hooks/error'
import { $t } from '@locales/index'
import { useStore } from '@settings/useStore'
import type { ReportMail, ReportFeishu, ReportWebhook, ReportDingtalk, AddReportParams } from '@/types/setting'
import type {
ReportMail,
ReportFeishu,
ReportWebhook,
ReportDingtalk,
ReportWecom,
AddReportParams,
} from '@/types/setting'
const {
emailChannelForm,
feishuChannelForm,
webhookChannelForm,
dingtalkChannelForm,
wecomChannelForm,
addReportChannel,
updateReportChannel,
} = useStore()
@@ -359,3 +367,100 @@ export const useDingtalkChannelFormController = () => {
submitForm,
}
}
/**
* 企业微信通知渠道表单控制器
* @function useWecomChannelFormController
* @description 提供企业微信通知渠道表单的配置、规则和提交方法
* @returns {object} 返回表单相关配置、规则和方法
*/
export const useWecomChannelFormController = () => {
const { open: openLoad, close: closeLoad } = useLoadingMask({ text: $t('t_0_1746667592819') })
/**
* 表单验证规则
* @type {FormRules}
*/
const rules: FormRules = {
name: {
required: true,
trigger: ['input', 'blur'],
message: $t('t_25_1746773349596'),
},
url: {
required: true,
trigger: ['input', 'blur'],
message: '请输入企业微信webhook地址',
},
}
/**
* 表单配置
* @type {ComputedRef<FormConfig>}
* @description 生成企业微信通知渠道表单的字段配置
*/
const config = computed(() => [
useFormInput($t('t_2_1745289353944'), 'name'),
useFormInput('企业微信WebHook地址', 'url'),
useFormTextarea(
'推送数据格式',
'data',
{
placeholder: `请输入企业微信推送数据格式,支持模板变量 __subject__ 和 __body__
示例格式:
{
"msgtype": "news",
"news": {
"articles": [
{
"title": "__subject__",
"description": "__body__。",
"url": "https://allinssl.com/",
"picurl": "https://allinssl.com/logo.svg"
}
]
}
}`,
rows: 12,
},
{ showRequireMark: false },
),
])
/**
* 提交表单
* @async
* @function submitForm
* @description 验证并提交企业微信通知渠道表单
* @param {any} params - 表单参数
* @param {Ref<FormInst>} formRef - 表单实例引用
* @returns {Promise<boolean>} 提交成功返回true失败返回false
*/
const submitForm = async (
{ config, ...other }: AddReportParams<ReportWecom>,
formRef: Ref<FormInst | null>,
id?: number,
) => {
try {
openLoad()
if (id) {
await updateReportChannel({ id, config: JSON.stringify(config), ...other })
} else {
await addReportChannel({ config: JSON.stringify(config), ...other })
}
return true
} catch (error) {
handleError(error)
return false
} finally {
closeLoad()
}
}
return {
config,
rules,
wecomChannelForm,
submitForm,
}
}

View File

@@ -16,6 +16,7 @@ export default defineComponent({
openAddFeishuChannelModal,
openAddWebhookChannelModal,
openAddDingtalkChannelModal,
openAddWecomChannelModal,
editChannelConfig,
testChannelConfig,
confirmDeleteChannel,
@@ -64,6 +65,12 @@ export default defineComponent({
{$t('t_1_1746676859550')}
</NButton>
)
} else if (type === 'workwx') {
return (
<NButton strong secondary type="primary" onClick={() => openAddWecomChannelModal(getConfiguredCount(type))}>
{$t('t_1_1746676859550')}
</NButton>
)
}
// 其他渠道暂未支持
return (
@@ -100,7 +107,7 @@ export default defineComponent({
color: '#1677ff',
},
{
type: 'wecom',
type: 'workwx',
name: $t('t_7_1746676857191'),
description: $t('t_8_1746676860457'),
color: '#07c160',

View File

@@ -10,6 +10,7 @@ import EmailChannelModel from './components/channel/EmailChannelModel'
import FeishuChannelModel from './components/channel/FeishuChannelModel'
import WebhookChannelModel from './components/channel/WebhookChannelModel'
import DingtalkChannelModel from './components/channel/DingtalkChannelModel'
import WecomChannelModel from './components/channel/WecomChannelModel'
import type { ReportMail, SaveSettingParams, ReportType } from '@/types/setting'
const {
@@ -178,6 +179,25 @@ export const useController = () => {
})
}
/**
* 打开添加企业微信通知渠道弹窗
* @function openAddWecomChannelModal
* @description 打开添加企业微信通知渠道的模态框,并在关闭后刷新通知渠道列表
* @returns {void} 无返回值
*/
const openAddWecomChannelModal = (limit: number = 1) => {
if (limit >= 1) {
message.warning('企业微信通知渠道已达到上限')
return
}
useModal({
title: '添加企业微信通知',
area: 650,
component: WecomChannelModel,
footer: true,
})
}
// 处理启用状态切换
const handleEnableChange = async (item: ReportType<ReportMail>) => {
useDialog({
@@ -263,6 +283,17 @@ export const useController = () => {
footer: true,
onClose: () => fetchNotifyChannels(),
})
} else if (item.type === 'workwx') {
useModal({
title: '编辑企业微信通知',
area: 650,
component: WecomChannelModel,
componentProps: {
data: item,
},
footer: true,
onClose: () => fetchNotifyChannels(),
})
}
}
@@ -274,7 +305,13 @@ export const useController = () => {
* @returns {void} 无返回值
*/
const testChannelConfig = (item: ReportType<any>) => {
if (item.type !== 'mail' && item.type !== 'feishu' && item.type !== 'webhook' && item.type !== 'dingtalk') {
if (
item.type !== 'mail' &&
item.type !== 'feishu' &&
item.type !== 'webhook' &&
item.type !== 'dingtalk' &&
item.type !== 'workwx'
) {
message.warning($t('t_19_1746773352558'))
return
}
@@ -283,6 +320,7 @@ export const useController = () => {
feishu: $t('t_34_1746773350153'),
webhook: $t('t_3_1748591484673'),
dingtalk: $t('t_32_1746773348993'),
workwx: $t('t_33_1746773350932'),
}
const { open, close } = useLoadingMask({ text: $t('t_4_1748591492587', { type: typeMap[item.type] }) })
useDialog({
@@ -337,6 +375,7 @@ export const useController = () => {
openAddFeishuChannelModal,
openAddWebhookChannelModal,
openAddDingtalkChannelModal,
openAddWecomChannelModal,
handleEnableChange,
editChannelConfig,
testChannelConfig,

View File

@@ -22,6 +22,7 @@ import type {
ReportFeishu,
ReportWebhook,
ReportDingtalk,
ReportWecom,
} from '@/types/setting'
const { handleError } = useError()
@@ -63,7 +64,7 @@ export const useSettingsStore = defineStore('settings-store', () => {
const channelTypes = ref<Record<string, string>>({
mail: $t('t_68_1745289354676'),
dingtalk: $t('t_32_1746773348993'),
wecom: $t('t_33_1746773350932'),
workwx: $t('t_33_1746773350932'),
feishu: $t('t_34_1746773350153'),
webhook: 'WebHook',
})
@@ -107,6 +108,26 @@ export const useSettingsStore = defineStore('settings-store', () => {
secret: '', // 钉钉webhook加密密钥可选
})
// 企业微信通知渠道表单
const wecomChannelForm = ref<ReportWecom>({
name: '',
enabled: '1',
url: '', // 企业微信webhook地址
data: `{
"msgtype": "news",
"news": {
"articles": [
{
"title": "__subject__",
"description": "__body__。",
"url": "https://allinssl.com/",
"picurl": "https://allinssl.com/logo.svg"
}
]
}
}`, // 企业微信推送数据格式
})
// 关于页面数据
const aboutInfo = ref({
version: '1.0.0',
@@ -250,6 +271,7 @@ export const useSettingsStore = defineStore('settings-store', () => {
feishuChannelForm,
webhookChannelForm,
dingtalkChannelForm,
wecomChannelForm,
aboutInfo,
// 方法