|
|
@@ -0,0 +1,123 @@
|
|
|
+<template>
|
|
|
+ <div class="app-container">
|
|
|
+ <el-card class="box-card">
|
|
|
+ <template #header>
|
|
|
+ <div class="card-header">
|
|
|
+ <span>HTTPS 证书配置</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <div class="ssl-config-container">
|
|
|
+ <el-alert
|
|
|
+ title="注意:更新证书后 Nginx 服务会自动重载,可能会导致短暂的连接中断。"
|
|
|
+ type="warning"
|
|
|
+ show-icon
|
|
|
+ :closable="false"
|
|
|
+ style="margin-bottom: 20px"
|
|
|
+ />
|
|
|
+
|
|
|
+ <el-form label-width="120px" style="max-width: 600px">
|
|
|
+ <el-form-item label="证书文件">
|
|
|
+ <input
|
|
|
+ type="file"
|
|
|
+ class="file-input"
|
|
|
+ @change="handleCertFile"
|
|
|
+ accept=".crt,.pem,.cer"
|
|
|
+ />
|
|
|
+ <div class="tip">请上传 .crt 或 .pem 格式的证书文件</div>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="私钥文件">
|
|
|
+ <input
|
|
|
+ type="file"
|
|
|
+ class="file-input"
|
|
|
+ @change="handleKeyFile"
|
|
|
+ accept=".key,.pem"
|
|
|
+ />
|
|
|
+ <div class="tip">请上传 .key 或 .pem 格式的私钥文件</div>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" @click="submitSSL" :loading="loading">
|
|
|
+ 更新证书并重载 Nginx
|
|
|
+ </el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref } from 'vue'
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
+import request from '../../../utils/request'
|
|
|
+
|
|
|
+const certFile = ref<File | null>(null)
|
|
|
+const keyFile = ref<File | null>(null)
|
|
|
+const loading = ref(false)
|
|
|
+
|
|
|
+const handleCertFile = (event: Event) => {
|
|
|
+ const target = event.target as HTMLInputElement
|
|
|
+ if (target.files && target.files.length > 0) {
|
|
|
+ certFile.value = target.files[0]
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const handleKeyFile = (event: Event) => {
|
|
|
+ const target = event.target as HTMLInputElement
|
|
|
+ if (target.files && target.files.length > 0) {
|
|
|
+ keyFile.value = target.files[0]
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const submitSSL = async () => {
|
|
|
+ if (!certFile.value || !keyFile.value) {
|
|
|
+ ElMessage.warning('请同时选择证书文件和私钥文件')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const formData = new FormData()
|
|
|
+ formData.append('crt_file', certFile.value)
|
|
|
+ formData.append('key_file', keyFile.value)
|
|
|
+
|
|
|
+ loading.value = true
|
|
|
+ try {
|
|
|
+ await request.post('/system/ssl/config', formData, {
|
|
|
+ headers: { 'Content-Type': 'multipart/form-data' }
|
|
|
+ })
|
|
|
+ ElMessage.success('证书更新成功,Nginx 正在后台重载...')
|
|
|
+ // Reset inputs if needed, or leave them
|
|
|
+ } catch (error) {
|
|
|
+ console.error(error)
|
|
|
+ // Error is usually handled by request interceptor, but we can double check
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.app-container {
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+.box-card {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+.card-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+.tip {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+ line-height: 1.5;
|
|
|
+ margin-top: 5px;
|
|
|
+}
|
|
|
+.file-input {
|
|
|
+ display: block;
|
|
|
+ padding: 5px 0;
|
|
|
+}
|
|
|
+</style>
|
|
|
+
|