mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-03-15 02:04:46 +08:00
feat: 证书增加下载功能 (#3090)
Refs https://github.com/1Panel-dev/1Panel/issues/2767
This commit is contained in:
parent
59c216c184
commit
86bc75ff28
@ -1,7 +1,10 @@
|
|||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
@ -213,3 +216,32 @@ func (b *BaseApi) UploadWebsiteSSL(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithData(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags Website SSL
|
||||||
|
// @Summary Download SSL file
|
||||||
|
// @Description 下载证书文件
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.WebsiteResourceReq true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/ssl/download [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"website_ssls","output_column":"primary_domain","output_value":"domain"}],"formatZH":"下载证书文件 [domain]","formatEN":"download ssl file [domain]"}
|
||||||
|
func (b *BaseApi) DownloadWebsiteSSL(c *gin.Context) {
|
||||||
|
var req request.WebsiteResourceReq
|
||||||
|
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file, err := websiteSSLService.DownloadFile(req.ID)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
info, err := file.Stat()
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Header("Content-Length", strconv.FormatInt(info.Size(), 10))
|
||||||
|
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(info.Name()))
|
||||||
|
http.ServeContent(c.Writer, c.Request, info.Name(), info.ModTime(), file)
|
||||||
|
}
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/1Panel-dev/1Panel/backend/i18n"
|
"github.com/1Panel-dev/1Panel/backend/i18n"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
@ -41,6 +42,7 @@ type IWebsiteSSLService interface {
|
|||||||
Upload(req request.WebsiteSSLUpload) error
|
Upload(req request.WebsiteSSLUpload) error
|
||||||
ObtainSSL(apply request.WebsiteSSLApply) error
|
ObtainSSL(apply request.WebsiteSSLApply) error
|
||||||
SyncForRestart() error
|
SyncForRestart() error
|
||||||
|
DownloadFile(id uint) (*os.File, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIWebsiteSSLService() IWebsiteSSLService {
|
func NewIWebsiteSSLService() IWebsiteSSLService {
|
||||||
@ -425,6 +427,34 @@ func (w WebsiteSSLService) Upload(req request.WebsiteSSLUpload) error {
|
|||||||
return websiteSSLRepo.Create(context.Background(), websiteSSL)
|
return websiteSSLRepo.Create(context.Background(), websiteSSL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w WebsiteSSLService) DownloadFile(id uint) (*os.File, error) {
|
||||||
|
websiteSSL, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(id))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fileOp := files.NewFileOp()
|
||||||
|
dir := path.Join(global.CONF.System.BaseDir, "1panel/tmp/ssl", websiteSSL.PrimaryDomain)
|
||||||
|
if fileOp.Stat(dir) {
|
||||||
|
if err = fileOp.DeleteDir(dir); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = fileOp.CreateDir(dir, 0666); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = fileOp.WriteFile(path.Join(dir, "fullchain.pem"), strings.NewReader(websiteSSL.Pem), 0644); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = fileOp.WriteFile(path.Join(dir, "privkey.pem"), strings.NewReader(websiteSSL.PrivateKey), 0644); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fileName := websiteSSL.PrimaryDomain + ".zip"
|
||||||
|
if err = fileOp.Compress([]string{path.Join(dir, "fullchain.pem"), path.Join(dir, "privkey.pem")}, dir, fileName, files.SdkZip); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return os.Open(path.Join(dir, fileName))
|
||||||
|
}
|
||||||
|
|
||||||
func (w WebsiteSSLService) SyncForRestart() error {
|
func (w WebsiteSSLService) SyncForRestart() error {
|
||||||
sslList, err := websiteSSLRepo.List()
|
sslList, err := websiteSSLRepo.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -24,5 +24,6 @@ func (a *WebsiteSSLRouter) InitWebsiteSSLRouter(Router *gin.RouterGroup) {
|
|||||||
groupRouter.POST("/update", baseApi.UpdateWebsiteSSL)
|
groupRouter.POST("/update", baseApi.UpdateWebsiteSSL)
|
||||||
groupRouter.POST("/upload", baseApi.UploadWebsiteSSL)
|
groupRouter.POST("/upload", baseApi.UploadWebsiteSSL)
|
||||||
groupRouter.POST("/obtain", baseApi.ApplyWebsiteSSL)
|
groupRouter.POST("/obtain", baseApi.ApplyWebsiteSSL)
|
||||||
|
groupRouter.POST("/download", baseApi.DownloadWebsiteSSL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12879,6 +12879,57 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/websites/ssl/download": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "下载证书文件",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Website SSL"
|
||||||
|
],
|
||||||
|
"summary": "Download SSL file",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "request",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/request.WebsiteResourceReq"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-panel-log": {
|
||||||
|
"BeforeFunctions": [
|
||||||
|
{
|
||||||
|
"db": "website_ssls",
|
||||||
|
"input_column": "id",
|
||||||
|
"input_value": "id",
|
||||||
|
"isList": false,
|
||||||
|
"output_column": "primary_domain",
|
||||||
|
"output_value": "domain"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bodyKeys": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"formatEN": "download ssl file [domain]",
|
||||||
|
"formatZH": "下载证书文件 [domain]",
|
||||||
|
"paramKeys": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/websites/ssl/obtain": {
|
"/websites/ssl/obtain": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
@ -17478,6 +17529,9 @@ const docTemplate = `{
|
|||||||
"createdAt": {
|
"createdAt": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"dir": {
|
"dir": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -19522,14 +19576,33 @@ const docTemplate = `{
|
|||||||
"request.WebsiteSSLUpdate": {
|
"request.WebsiteSSLUpdate": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"id"
|
"id",
|
||||||
|
"type"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"autoRenew": {
|
"autoRenew": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"certificate": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"autoRenew",
|
||||||
|
"description",
|
||||||
|
"certificate",
|
||||||
|
"privateKey"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -19551,6 +19624,9 @@ const docTemplate = `{
|
|||||||
"privateKeyPath": {
|
"privateKeyPath": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"sslID": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
@ -12872,6 +12872,57 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/websites/ssl/download": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "下载证书文件",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Website SSL"
|
||||||
|
],
|
||||||
|
"summary": "Download SSL file",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "request",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/request.WebsiteResourceReq"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-panel-log": {
|
||||||
|
"BeforeFunctions": [
|
||||||
|
{
|
||||||
|
"db": "website_ssls",
|
||||||
|
"input_column": "id",
|
||||||
|
"input_value": "id",
|
||||||
|
"isList": false,
|
||||||
|
"output_column": "primary_domain",
|
||||||
|
"output_value": "domain"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bodyKeys": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"formatEN": "download ssl file [domain]",
|
||||||
|
"formatZH": "下载证书文件 [domain]",
|
||||||
|
"paramKeys": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/websites/ssl/obtain": {
|
"/websites/ssl/obtain": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
@ -17471,6 +17522,9 @@
|
|||||||
"createdAt": {
|
"createdAt": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"dir": {
|
"dir": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -19515,14 +19569,33 @@
|
|||||||
"request.WebsiteSSLUpdate": {
|
"request.WebsiteSSLUpdate": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"id"
|
"id",
|
||||||
|
"type"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"autoRenew": {
|
"autoRenew": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"certificate": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"autoRenew",
|
||||||
|
"description",
|
||||||
|
"certificate",
|
||||||
|
"privateKey"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -19544,6 +19617,9 @@
|
|||||||
"privateKeyPath": {
|
"privateKeyPath": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"sslID": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
@ -2800,6 +2800,8 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
createdAt:
|
createdAt:
|
||||||
type: string
|
type: string
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
dir:
|
dir:
|
||||||
type: string
|
type: string
|
||||||
dnsAccount:
|
dnsAccount:
|
||||||
@ -4178,10 +4180,24 @@ definitions:
|
|||||||
properties:
|
properties:
|
||||||
autoRenew:
|
autoRenew:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
certificate:
|
||||||
|
type: string
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
id:
|
id:
|
||||||
type: integer
|
type: integer
|
||||||
|
privateKey:
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
enum:
|
||||||
|
- autoRenew
|
||||||
|
- description
|
||||||
|
- certificate
|
||||||
|
- privateKey
|
||||||
|
type: string
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
|
- type
|
||||||
type: object
|
type: object
|
||||||
request.WebsiteSSLUpload:
|
request.WebsiteSSLUpload:
|
||||||
properties:
|
properties:
|
||||||
@ -4193,6 +4209,8 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
privateKeyPath:
|
privateKeyPath:
|
||||||
type: string
|
type: string
|
||||||
|
sslID:
|
||||||
|
type: integer
|
||||||
type:
|
type:
|
||||||
enum:
|
enum:
|
||||||
- paste
|
- paste
|
||||||
@ -12874,6 +12892,39 @@ paths:
|
|||||||
formatEN: Delete ssl [domain]
|
formatEN: Delete ssl [domain]
|
||||||
formatZH: 删除 ssl [domain]
|
formatZH: 删除 ssl [domain]
|
||||||
paramKeys: []
|
paramKeys: []
|
||||||
|
/websites/ssl/download:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 下载证书文件
|
||||||
|
parameters:
|
||||||
|
- description: request
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/request.WebsiteResourceReq'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
summary: Download SSL file
|
||||||
|
tags:
|
||||||
|
- Website SSL
|
||||||
|
x-panel-log:
|
||||||
|
BeforeFunctions:
|
||||||
|
- db: website_ssls
|
||||||
|
input_column: id
|
||||||
|
input_value: id
|
||||||
|
isList: false
|
||||||
|
output_column: primary_domain
|
||||||
|
output_value: domain
|
||||||
|
bodyKeys:
|
||||||
|
- id
|
||||||
|
formatEN: download ssl file [domain]
|
||||||
|
formatZH: 下载证书文件 [domain]
|
||||||
|
paramKeys: []
|
||||||
/websites/ssl/obtain:
|
/websites/ssl/obtain:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
@ -490,4 +490,8 @@ export namespace Website {
|
|||||||
export interface RenewSSLByCA {
|
export interface RenewSSLByCA {
|
||||||
SSLID: number;
|
SSLID: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SSLDownload {
|
||||||
|
id: number;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -263,3 +263,10 @@ export const DeleteCA = (req: Website.DelReq) => {
|
|||||||
export const RenewSSLByCA = (req: Website.RenewSSLByCA) => {
|
export const RenewSSLByCA = (req: Website.RenewSSLByCA) => {
|
||||||
return http.post<any>(`/websites/ca/renew`, req);
|
return http.post<any>(`/websites/ca/renew`, req);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const DownloadFile = (params: Website.SSLDownload) => {
|
||||||
|
return http.download<BlobPart>(`/websites/ssl/download`, params, {
|
||||||
|
responseType: 'blob',
|
||||||
|
timeout: TimeoutEnum.T_40S,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -3,15 +3,13 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<DrawerHeader :header="$t('ssl.detail')" :back="handleClose" />
|
<DrawerHeader :header="$t('ssl.detail')" :back="handleClose" />
|
||||||
</template>
|
</template>
|
||||||
<div>
|
<div v-loading="loading">
|
||||||
<el-radio-group v-model="curr">
|
<el-radio-group v-model="curr">
|
||||||
<el-radio-button label="detail">{{ $t('ssl.msg') }}</el-radio-button>
|
<el-radio-button label="detail">{{ $t('ssl.msg') }}</el-radio-button>
|
||||||
<el-radio-button label="ssl">{{ $t('ssl.ssl') }}</el-radio-button>
|
<el-radio-button label="ssl">{{ $t('ssl.ssl') }}</el-radio-button>
|
||||||
<el-radio-button label="key">{{ $t('ssl.key') }}</el-radio-button>
|
<el-radio-button label="key">{{ $t('ssl.key') }}</el-radio-button>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
<br />
|
<div v-if="curr === 'detail'" class="mt-5">
|
||||||
<br />
|
|
||||||
<div v-if="curr === 'detail'">
|
|
||||||
<el-descriptions border :column="1">
|
<el-descriptions border :column="1">
|
||||||
<el-descriptions-item :label="$t('website.primaryDomain')">
|
<el-descriptions-item :label="$t('website.primaryDomain')">
|
||||||
{{ ssl.primaryDomain }}
|
{{ ssl.primaryDomain }}
|
||||||
@ -52,14 +50,14 @@
|
|||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="curr === 'ssl'">
|
<div v-else-if="curr === 'ssl'" class="mt-5">
|
||||||
<el-input v-model="ssl.pem" :autosize="{ minRows: 15, maxRows: 30 }" type="textarea" id="textArea" />
|
<el-input v-model="ssl.pem" :autosize="{ minRows: 15, maxRows: 30 }" type="textarea" id="textArea" />
|
||||||
<div>
|
<div>
|
||||||
<br />
|
<br />
|
||||||
<el-button type="primary" @click="copyText(ssl.pem)">{{ $t('file.copy') }}</el-button>
|
<el-button type="primary" @click="copyText(ssl.pem)">{{ $t('file.copy') }}</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else class="mt-5">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="ssl.privateKey"
|
v-model="ssl.privateKey"
|
||||||
:autosize="{ minRows: 15, maxRows: 30 }"
|
:autosize="{ minRows: 15, maxRows: 30 }"
|
||||||
@ -88,6 +86,7 @@ const open = ref(false);
|
|||||||
const id = ref(0);
|
const id = ref(0);
|
||||||
const curr = ref('detail');
|
const curr = ref('detail');
|
||||||
const ssl = ref<any>({});
|
const ssl = ref<any>({});
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
open.value = false;
|
open.value = false;
|
||||||
|
@ -150,7 +150,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, reactive, ref, computed } from 'vue';
|
import { onMounted, reactive, ref, computed } from 'vue';
|
||||||
import OpDialog from '@/components/del-dialog/index.vue';
|
import OpDialog from '@/components/del-dialog/index.vue';
|
||||||
import { DeleteSSL, SearchSSL, UpdateSSL } from '@/api/modules/website';
|
import { DeleteSSL, DownloadFile, SearchSSL, UpdateSSL } from '@/api/modules/website';
|
||||||
import DnsAccount from './dns-account/index.vue';
|
import DnsAccount from './dns-account/index.vue';
|
||||||
import AcmeAccount from './acme-account/index.vue';
|
import AcmeAccount from './acme-account/index.vue';
|
||||||
import CA from './ca/index.vue';
|
import CA from './ca/index.vue';
|
||||||
@ -229,6 +229,12 @@ const buttons = [
|
|||||||
return row.provider == 'manual';
|
return row.provider == 'manual';
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: i18n.global.t('file.download'),
|
||||||
|
click: function (row: Website.SSLDTO) {
|
||||||
|
onDownload(row);
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: i18n.global.t('commons.button.delete'),
|
label: i18n.global.t('commons.button.delete'),
|
||||||
click: function (row: Website.SSLDTO) {
|
click: function (row: Website.SSLDTO) {
|
||||||
@ -237,6 +243,23 @@ const buttons = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const onDownload = (ssl: Website.SSLDTO) => {
|
||||||
|
loading.value = true;
|
||||||
|
DownloadFile({ id: ssl.id })
|
||||||
|
.then((res) => {
|
||||||
|
const downloadUrl = window.URL.createObjectURL(new Blob([res]));
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.style.display = 'none';
|
||||||
|
a.href = downloadUrl;
|
||||||
|
a.download = ssl.primaryDomain + '.zip';
|
||||||
|
const event = new MouseEvent('click');
|
||||||
|
a.dispatchEvent(event);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const mobile = computed(() => {
|
const mobile = computed(() => {
|
||||||
return globalStore.isMobile();
|
return globalStore.isMobile();
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user