mirror of
https://gitee.com/mirrors/AllinSSL.git
synced 2026-03-18 04:02:02 +08:00
【新增】私有证书
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { useWorkflowStore } from '../../store/workflow'
|
||||
import { ApplyNodeData } from '../../types'
|
||||
import configStyles from './Config.module.css'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ApplyNodeConfig',
|
||||
props: {
|
||||
nodeId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
nodeData: {
|
||||
type: Object as () => ApplyNodeData,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const workflowStore = useWorkflowStore()
|
||||
const applicationContent = ref(props.nodeData.applicationContent || '')
|
||||
const applyStatus = ref<'idle' | 'applying' | 'success' | 'error'>('idle')
|
||||
const errorMessage = ref('')
|
||||
|
||||
// 更新节点标签
|
||||
const updateNodeLabel = (value: string) => {
|
||||
workflowStore.updateNodeData(props.nodeId, { label: value })
|
||||
}
|
||||
|
||||
// 更新申请内容
|
||||
const updateApplicationContent = (value: string) => {
|
||||
applicationContent.value = value
|
||||
}
|
||||
|
||||
// 提交申请
|
||||
const submitApplication = () => {
|
||||
if (!applicationContent.value.trim()) {
|
||||
errorMessage.value = '请输入申请内容'
|
||||
return
|
||||
}
|
||||
|
||||
// 模拟申请过程
|
||||
applyStatus.value = 'applying'
|
||||
errorMessage.value = ''
|
||||
|
||||
setTimeout(() => {
|
||||
applyStatus.value = 'success'
|
||||
workflowStore.updateNodeData(props.nodeId, {
|
||||
applicationContent: applicationContent.value,
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
return () => (
|
||||
<div class={configStyles.configContainer}>
|
||||
<div class={configStyles.configField}>
|
||||
<div class={configStyles.configLabel}>节点名称</div>
|
||||
<input
|
||||
type="text"
|
||||
value={props.nodeData.label}
|
||||
onInput={(e) => updateNodeLabel((e.target as HTMLInputElement).value)}
|
||||
class={configStyles.configInput}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class={configStyles.configField}>
|
||||
<div class={configStyles.configLabel}>申请内容</div>
|
||||
<textarea
|
||||
value={applicationContent.value}
|
||||
onInput={(e) => updateApplicationContent((e.target as HTMLTextAreaElement).value)}
|
||||
class={configStyles.configTextarea}
|
||||
placeholder="请输入申请内容"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
{errorMessage.value && <div class={configStyles.configError}>{errorMessage.value}</div>}
|
||||
|
||||
<div class={configStyles.configActions}>
|
||||
<button
|
||||
class={configStyles.configButton}
|
||||
onClick={submitApplication}
|
||||
disabled={applyStatus.value === 'applying'}
|
||||
>
|
||||
{applyStatus.value === 'applying' ? '申请中...' : '提交申请'}
|
||||
</button>
|
||||
|
||||
{applyStatus.value === 'success' && <div class={configStyles.configSuccess}>申请提交成功</div>}
|
||||
</div>
|
||||
|
||||
<div class={configStyles.configInfo}>
|
||||
<div class={configStyles.configInfoTitle}>节点说明</div>
|
||||
<div class={configStyles.configInfoContent}>申请节点用于提交申请。申请成功后,申请内容将保存到节点中。</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
})
|
||||
126
frontend/apps/vue-flow/components/configs/Config.module.css
Normal file
126
frontend/apps/vue-flow/components/configs/Config.module.css
Normal file
@@ -0,0 +1,126 @@
|
||||
.configContainer {
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.configField {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.configLabel {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 6px;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
.configInput {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.configInput:focus {
|
||||
outline: none;
|
||||
border-color: #60a5fa;
|
||||
box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.2);
|
||||
}
|
||||
|
||||
.configFileInput {
|
||||
width: 100%;
|
||||
padding: 8px 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.configTextarea {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
resize: vertical;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.configTextarea:focus {
|
||||
outline: none;
|
||||
border-color: #60a5fa;
|
||||
box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.2);
|
||||
}
|
||||
|
||||
.configSelect {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.configSelect:focus {
|
||||
outline: none;
|
||||
border-color: #60a5fa;
|
||||
box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.2);
|
||||
}
|
||||
|
||||
.configInfo {
|
||||
margin-top: 20px;
|
||||
background-color: #f3f4f6;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.configInfoTitle {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
color: #4b5563;
|
||||
}
|
||||
|
||||
.configInfoContent {
|
||||
font-size: 13px;
|
||||
color: #6b7280;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.configError {
|
||||
margin-bottom: 16px;
|
||||
padding: 8px;
|
||||
background-color: #fee2e2;
|
||||
border-radius: 4px;
|
||||
color: #b91c1c;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.configSuccess {
|
||||
margin-left: 12px;
|
||||
color: #047857;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.configActions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.configButton {
|
||||
padding: 8px 16px;
|
||||
background-color: #2563eb;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.configButton:hover {
|
||||
background-color: #1d4ed8;
|
||||
}
|
||||
|
||||
.configButton:disabled {
|
||||
background-color: #93c5fd;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { useWorkflowStore } from '../../store/workflow'
|
||||
import { DeployNodeData } from '../../types'
|
||||
import configStyles from './Config.module.css'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DeployNodeConfig',
|
||||
props: {
|
||||
nodeId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
nodeData: {
|
||||
type: Object as () => DeployNodeData,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const workflowStore = useWorkflowStore()
|
||||
const certificateContent = ref(props.nodeData.certificateContent || '')
|
||||
const deployStatus = ref<'idle' | 'deploying' | 'success' | 'error'>('idle')
|
||||
const errorMessage = ref('')
|
||||
|
||||
// 更新节点标签
|
||||
const updateNodeLabel = (value: string) => {
|
||||
workflowStore.updateNodeData(props.nodeId, { label: value })
|
||||
}
|
||||
|
||||
// 更新证书内容
|
||||
const updateCertificateContent = (value: string) => {
|
||||
certificateContent.value = value
|
||||
}
|
||||
|
||||
// 部署证书
|
||||
const deployCertificate = () => {
|
||||
if (!certificateContent.value.trim()) {
|
||||
errorMessage.value = '请输入证书内容'
|
||||
return
|
||||
}
|
||||
|
||||
// 模拟部署过程
|
||||
deployStatus.value = 'deploying'
|
||||
errorMessage.value = ''
|
||||
|
||||
setTimeout(() => {
|
||||
deployStatus.value = 'success'
|
||||
workflowStore.updateNodeData(props.nodeId, {
|
||||
certificateContent: certificateContent.value,
|
||||
})
|
||||
}, 1500)
|
||||
}
|
||||
|
||||
return () => (
|
||||
<div class={configStyles.configContainer}>
|
||||
<div class={configStyles.configField}>
|
||||
<div class={configStyles.configLabel}>节点名称</div>
|
||||
<input
|
||||
type="text"
|
||||
value={props.nodeData.label}
|
||||
onInput={(e) => updateNodeLabel((e.target as HTMLInputElement).value)}
|
||||
class={configStyles.configInput}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class={configStyles.configField}>
|
||||
<div class={configStyles.configLabel}>证书内容</div>
|
||||
<textarea
|
||||
value={certificateContent.value}
|
||||
onInput={(e) => updateCertificateContent((e.target as HTMLTextAreaElement).value)}
|
||||
class={configStyles.configTextarea}
|
||||
placeholder="请输入要部署的证书内容"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
{errorMessage.value && <div class={configStyles.configError}>{errorMessage.value}</div>}
|
||||
|
||||
<div class={configStyles.configActions}>
|
||||
<button
|
||||
class={configStyles.configButton}
|
||||
onClick={deployCertificate}
|
||||
disabled={deployStatus.value === 'deploying'}
|
||||
>
|
||||
{deployStatus.value === 'deploying' ? '部署中...' : '部署证书'}
|
||||
</button>
|
||||
|
||||
{deployStatus.value === 'success' && <div class={configStyles.configSuccess}>部署成功</div>}
|
||||
</div>
|
||||
|
||||
<div class={configStyles.configInfo}>
|
||||
<div class={configStyles.configInfoTitle}>节点说明</div>
|
||||
<div class={configStyles.configInfoContent}>
|
||||
部署证书节点用于部署证书。部署成功后,证书内容将保存到节点中。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
})
|
||||
45
frontend/apps/vue-flow/components/configs/EndNodeConfig.tsx
Normal file
45
frontend/apps/vue-flow/components/configs/EndNodeConfig.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import { defineComponent } from 'vue'
|
||||
import { useWorkflowStore } from '../../store/workflow'
|
||||
import { EndNodeData } from '../../types'
|
||||
import configStyles from './Config.module.css'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'EndNodeConfig',
|
||||
props: {
|
||||
nodeId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
nodeData: {
|
||||
type: Object as () => EndNodeData,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const workflowStore = useWorkflowStore()
|
||||
|
||||
const updateNodeLabel = (value: string) => {
|
||||
workflowStore.updateNodeData(props.nodeId, { label: value })
|
||||
}
|
||||
|
||||
return () => (
|
||||
<div class={configStyles.configContainer}>
|
||||
<div class={configStyles.configField}>
|
||||
<div class={configStyles.configLabel}>节点名称</div>
|
||||
<input
|
||||
type="text"
|
||||
value={props.nodeData.label}
|
||||
onInput={(e) => updateNodeLabel((e.target as HTMLInputElement).value)}
|
||||
class={configStyles.configInput}
|
||||
/>
|
||||
</div>
|
||||
<div class={configStyles.configInfo}>
|
||||
<div class={configStyles.configInfoTitle}>节点说明</div>
|
||||
<div class={configStyles.configInfoContent}>
|
||||
结束节点作为工作流的终点,不可移动,不可删除,不可更改节点类型,只能有一个入口。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,82 @@
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { useWorkflowStore } from '../../store/workflow'
|
||||
import { NormalNodeData } from '../../types'
|
||||
import configStyles from './Config.module.css'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NormalNodeConfig',
|
||||
props: {
|
||||
nodeId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
nodeData: {
|
||||
type: Object as () => NormalNodeData,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const workflowStore = useWorkflowStore()
|
||||
const message = ref(props.nodeData.message || '')
|
||||
const status = ref(props.nodeData.status || 'info')
|
||||
|
||||
// 更新节点标签
|
||||
const updateNodeLabel = (value: string) => {
|
||||
workflowStore.updateNodeData(props.nodeId, { label: value })
|
||||
}
|
||||
|
||||
// 更新消息内容
|
||||
const updateMessage = (value: string) => {
|
||||
message.value = value
|
||||
workflowStore.updateNodeData(props.nodeId, { message: value })
|
||||
}
|
||||
|
||||
// 更新状态
|
||||
const updateStatus = (value: string) => {
|
||||
status.value = value as 'success' | 'error' | 'info'
|
||||
workflowStore.updateNodeData(props.nodeId, { status: value as 'success' | 'error' | 'info' })
|
||||
}
|
||||
|
||||
return () => (
|
||||
<div class={configStyles.configContainer}>
|
||||
<div class={configStyles.configField}>
|
||||
<div class={configStyles.configLabel}>节点名称</div>
|
||||
<input
|
||||
type="text"
|
||||
value={props.nodeData.label}
|
||||
onInput={(e) => updateNodeLabel((e.target as HTMLInputElement).value)}
|
||||
class={configStyles.configInput}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class={configStyles.configField}>
|
||||
<div class={configStyles.configLabel}>状态</div>
|
||||
<select
|
||||
value={status.value}
|
||||
onChange={(e) => updateStatus((e.target as HTMLSelectElement).value)}
|
||||
class={configStyles.configSelect}
|
||||
>
|
||||
<option value="info">信息</option>
|
||||
<option value="success">成功</option>
|
||||
<option value="error">失败</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class={configStyles.configField}>
|
||||
<div class={configStyles.configLabel}>消息内容</div>
|
||||
<textarea
|
||||
value={message.value}
|
||||
onInput={(e) => updateMessage((e.target as HTMLTextAreaElement).value)}
|
||||
class={configStyles.configTextarea}
|
||||
placeholder="请输入消息内容"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div class={configStyles.configInfo}>
|
||||
<div class={configStyles.configInfoTitle}>节点说明</div>
|
||||
<div class={configStyles.configInfoContent}>普通节点用于显示文本或者成功/失败提示。</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,85 @@
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { useWorkflowStore } from '../../store/workflow'
|
||||
import { NotifyNodeData } from '../../types'
|
||||
import configStyles from './Config.module.css'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NotifyNodeConfig',
|
||||
props: {
|
||||
nodeId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
nodeData: {
|
||||
type: Object as () => NotifyNodeData,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const workflowStore = useWorkflowStore()
|
||||
const message = ref(props.nodeData.message || '')
|
||||
const notifyType = ref(props.nodeData.notifyType || 'email')
|
||||
|
||||
// 更新节点标签
|
||||
const updateNodeLabel = (value: string) => {
|
||||
workflowStore.updateNodeData(props.nodeId, { label: value })
|
||||
}
|
||||
|
||||
// 更新通知消息
|
||||
const updateMessage = (value: string) => {
|
||||
message.value = value
|
||||
workflowStore.updateNodeData(props.nodeId, { message: value })
|
||||
}
|
||||
|
||||
// 更新通知类型
|
||||
const updateNotifyType = (value: string) => {
|
||||
notifyType.value = value
|
||||
workflowStore.updateNodeData(props.nodeId, { notifyType: value })
|
||||
}
|
||||
|
||||
return () => (
|
||||
<div class={configStyles.configContainer}>
|
||||
<div class={configStyles.configField}>
|
||||
<div class={configStyles.configLabel}>节点名称</div>
|
||||
<input
|
||||
type="text"
|
||||
value={props.nodeData.label}
|
||||
onInput={(e) => updateNodeLabel((e.target as HTMLInputElement).value)}
|
||||
class={configStyles.configInput}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class={configStyles.configField}>
|
||||
<div class={configStyles.configLabel}>通知类型</div>
|
||||
<select
|
||||
value={notifyType.value}
|
||||
onChange={(e) => updateNotifyType((e.target as HTMLSelectElement).value)}
|
||||
class={configStyles.configSelect}
|
||||
>
|
||||
<option value="email">邮件通知</option>
|
||||
<option value="sms">短信通知</option>
|
||||
<option value="wechat">微信通知</option>
|
||||
<option value="dingding">钉钉通知</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class={configStyles.configField}>
|
||||
<div class={configStyles.configLabel}>通知内容</div>
|
||||
<textarea
|
||||
value={message.value}
|
||||
onInput={(e) => updateMessage((e.target as HTMLTextAreaElement).value)}
|
||||
class={configStyles.configTextarea}
|
||||
placeholder="请输入通知内容"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div class={configStyles.configInfo}>
|
||||
<div class={configStyles.configInfoTitle}>节点说明</div>
|
||||
<div class={configStyles.configInfoContent}>
|
||||
通知节点具备两个子节点,一个为成功节点,一个为失败节点,成功节点和失败节点各具备一个出口。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,45 @@
|
||||
import { defineComponent } from 'vue'
|
||||
import { useWorkflowStore } from '../../store/workflow'
|
||||
import { StartNodeData } from '../../types'
|
||||
import configStyles from './Config.module.css'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'StartNodeConfig',
|
||||
props: {
|
||||
nodeId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
nodeData: {
|
||||
type: Object as () => StartNodeData,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const workflowStore = useWorkflowStore()
|
||||
|
||||
const updateNodeLabel = (value: string) => {
|
||||
workflowStore.updateNodeData(props.nodeId, { label: value })
|
||||
}
|
||||
|
||||
return () => (
|
||||
<div class={configStyles.configContainer}>
|
||||
<div class={configStyles.configField}>
|
||||
<div class={configStyles.configLabel}>节点名称</div>
|
||||
<input
|
||||
type="text"
|
||||
value={props.nodeData.label}
|
||||
onInput={(e) => updateNodeLabel((e.target as HTMLInputElement).value)}
|
||||
class={configStyles.configInput}
|
||||
/>
|
||||
</div>
|
||||
<div class={configStyles.configInfo}>
|
||||
<div class={configStyles.configInfoTitle}>节点说明</div>
|
||||
<div class={configStyles.configInfoContent}>
|
||||
开始节点作为工作流的起点,不可移动,不可删除,不可更改节点类型,只能有一个出口。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
})
|
||||
123
frontend/apps/vue-flow/components/configs/UploadNodeConfig.tsx
Normal file
123
frontend/apps/vue-flow/components/configs/UploadNodeConfig.tsx
Normal file
@@ -0,0 +1,123 @@
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { useWorkflowStore } from '../../store/workflow'
|
||||
import { UploadNodeData } from '../../types'
|
||||
import configStyles from './Config.module.css'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'UploadNodeConfig',
|
||||
props: {
|
||||
nodeId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
nodeData: {
|
||||
type: Object as () => UploadNodeData,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const workflowStore = useWorkflowStore()
|
||||
const certificateContent = ref(props.nodeData.certificateContent || '')
|
||||
const uploadStatus = ref<'idle' | 'uploading' | 'success' | 'error'>('idle')
|
||||
const errorMessage = ref('')
|
||||
|
||||
// 更新节点标签
|
||||
const updateNodeLabel = (value: string) => {
|
||||
workflowStore.updateNodeData(props.nodeId, { label: value })
|
||||
}
|
||||
|
||||
// 更新证书内容
|
||||
const updateCertificateContent = (value: string) => {
|
||||
certificateContent.value = value
|
||||
}
|
||||
|
||||
// 上传证书
|
||||
const uploadCertificate = () => {
|
||||
if (!certificateContent.value.trim()) {
|
||||
errorMessage.value = '请输入证书内容'
|
||||
return
|
||||
}
|
||||
|
||||
// 模拟上传过程
|
||||
uploadStatus.value = 'uploading'
|
||||
errorMessage.value = ''
|
||||
|
||||
setTimeout(() => {
|
||||
uploadStatus.value = 'success'
|
||||
workflowStore.updateNodeData(props.nodeId, {
|
||||
certificateContent: certificateContent.value,
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 处理文件上传
|
||||
const handleFileUpload = (event: Event) => {
|
||||
const fileInput = event.target as HTMLInputElement
|
||||
const file = fileInput.files?.[0]
|
||||
|
||||
if (file) {
|
||||
const reader = new FileReader()
|
||||
reader.onload = (e) => {
|
||||
const content = e.target?.result as string
|
||||
certificateContent.value = content
|
||||
}
|
||||
reader.readAsText(file)
|
||||
}
|
||||
}
|
||||
|
||||
return () => (
|
||||
<div class={configStyles.configContainer}>
|
||||
<div class={configStyles.configField}>
|
||||
<div class={configStyles.configLabel}>节点名称</div>
|
||||
<input
|
||||
type="text"
|
||||
value={props.nodeData.label}
|
||||
onInput={(e) => updateNodeLabel((e.target as HTMLInputElement).value)}
|
||||
class={configStyles.configInput}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class={configStyles.configField}>
|
||||
<div class={configStyles.configLabel}>上传证书文件</div>
|
||||
<input
|
||||
type="file"
|
||||
class={configStyles.configFileInput}
|
||||
onChange={handleFileUpload}
|
||||
accept=".pem,.crt,.key,.cert"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class={configStyles.configField}>
|
||||
<div class={configStyles.configLabel}>或粘贴证书内容</div>
|
||||
<textarea
|
||||
value={certificateContent.value}
|
||||
onInput={(e) => updateCertificateContent((e.target as HTMLTextAreaElement).value)}
|
||||
class={configStyles.configTextarea}
|
||||
placeholder="请粘贴证书内容"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
{errorMessage.value && <div class={configStyles.configError}>{errorMessage.value}</div>}
|
||||
|
||||
<div class={configStyles.configActions}>
|
||||
<button
|
||||
class={configStyles.configButton}
|
||||
onClick={uploadCertificate}
|
||||
disabled={uploadStatus.value === 'uploading'}
|
||||
>
|
||||
{uploadStatus.value === 'uploading' ? '上传中...' : '上传证书'}
|
||||
</button>
|
||||
|
||||
{uploadStatus.value === 'success' && <div class={configStyles.configSuccess}>上传成功</div>}
|
||||
</div>
|
||||
|
||||
<div class={configStyles.configInfo}>
|
||||
<div class={configStyles.configInfoTitle}>节点说明</div>
|
||||
<div class={configStyles.configInfoContent}>
|
||||
上传证书节点用于上传证书文件或粘贴证书内容。上传成功后,证书内容将保存到节点中。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user