1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-03-14 01:34:47 +08:00

feat: 优化网站域名添加 (#6069)

This commit is contained in:
zhengkunwang 2024-08-08 18:26:36 +08:00 committed by GitHub
parent 94b5a7fae4
commit a225d2d79a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 313 additions and 185 deletions

View File

@ -13,15 +13,15 @@ type WebsiteSearch struct {
}
type WebsiteCreate struct {
PrimaryDomain string `json:"primaryDomain" validate:"required"`
Type string `json:"type" validate:"required"`
Alias string `json:"alias" validate:"required"`
Remark string `json:"remark"`
OtherDomains string `json:"otherDomains"`
Proxy string `json:"proxy"`
WebsiteGroupID uint `json:"webSiteGroupID" validate:"required"`
IPV6 bool `json:"IPV6"`
Domains []WebsiteDomain `json:"domains"`
AppType string `json:"appType" validate:"oneof=new installed"`
AppInstall NewAppInstall `json:"appInstall"`
AppID uint `json:"appID"`
@ -124,7 +124,13 @@ type WebsiteGroupUpdate struct {
type WebsiteDomainCreate struct {
WebsiteID uint `json:"websiteID" validate:"required"`
Domains string `json:"domains" validate:"required"`
Domains []WebsiteDomain `json:"domains" validate:"required"`
}
type WebsiteDomain struct {
Domain string `json:"domain" validate:"required"`
Port int `json:"port"`
SSL bool `json:"SSL"`
}
type WebsiteDomainDelete struct {
@ -145,7 +151,7 @@ type WebsiteHTTPSOp struct {
SSLProtocol []string `json:"SSLProtocol"`
Algorithm string `json:"algorithm"`
Hsts bool `json:"hsts"`
HttpsPort int `json:"httpsPort"`
HttpsPorts []int `json:"httpsPorts"`
}
type WebsiteNginxUpdate struct {

View File

@ -59,7 +59,8 @@ type WebsiteHTTPS struct {
SSLProtocol []string `json:"SSLProtocol"`
Algorithm string `json:"algorithm"`
Hsts bool `json:"hsts"`
HttpsPort int `json:"httpsPort"`
HttpsPorts []int `json:"httpsPorts"`
HttpsPort string `json:"httpsPort"`
}
type WebsiteLog struct {

View File

@ -28,8 +28,6 @@ type Website struct {
AppInstallID uint `gorm:"type:integer" json:"appInstallId"`
FtpID uint `gorm:"type:integer" json:"ftpId"`
HttpsPort int `json:"httpsPort"`
User string `gorm:"type:varchar;" json:"user"`
Group string `gorm:"type:varchar;" json:"group"`

View File

@ -4,6 +4,7 @@ type WebsiteDomain struct {
BaseModel
WebsiteID uint `gorm:"column:website_id;type:varchar(64);not null;" json:"websiteId"`
Domain string `gorm:"type:varchar(256);not null" json:"domain"`
SSL bool `json:"SSL"`
Port int `gorm:"type:integer" json:"port"`
}

View File

@ -225,28 +225,21 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
return err
}
defaultHttpPort := nginxInstall.HttpPort
defaultHttpsPort := nginxInstall.HttpsPort
var (
otherDomains []model.WebsiteDomain
domains []model.WebsiteDomain
)
domains, _, _, err = getWebsiteDomains(create.PrimaryDomain, defaultHttpPort, 0)
domains, _, _, err = getWebsiteDomains(create.Domains, defaultHttpPort, 0)
if err != nil {
return err
}
otherDomains, _, _, err = getWebsiteDomains(create.OtherDomains, defaultHttpPort, 0)
if err != nil {
return err
}
domains = append(domains, otherDomains...)
if len(domains) == 1 && domains[0].Port != defaultHttpPort {
defaultHttpsPort = domains[0].Port
primaryDomain := domains[0].Domain
if domains[0].Port != defaultHttpPort {
primaryDomain = fmt.Sprintf("%s:%v", domains[0].Domain, domains[0].Port)
}
defaultDate, _ := time.Parse(constant.DateLayout, constant.DefaultDate)
website := &model.Website{
PrimaryDomain: create.PrimaryDomain,
PrimaryDomain: primaryDomain,
Type: create.Type,
Alias: alias,
Remark: create.Remark,
@ -259,7 +252,6 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
AccessLog: true,
ErrorLog: true,
IPV6: create.IPV6,
HttpsPort: defaultHttpsPort,
}
var (
@ -267,7 +259,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
runtime *model.Runtime
)
createTask, err := task.NewTaskWithOps(create.PrimaryDomain, task.TaskCreate, task.TaskScopeWebsite, create.TaskID, 0)
createTask, err := task.NewTaskWithOps(primaryDomain, task.TaskCreate, task.TaskScopeWebsite, create.TaskID, 0)
if err != nil {
return err
}
@ -464,7 +456,6 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
SSLProtocol: []string{"TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1"},
Algorithm: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED",
Hsts: true,
HttpsPort: website.HttpsPort,
}
if err = applySSL(website, *websiteModel, appSSLReq); err != nil {
return err
@ -607,7 +598,6 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
var (
domainModels []model.WebsiteDomain
addPorts []int
addDomains []string
)
httpPort, _, err := getAppInstallPort(constant.AppOpenresty)
if err != nil {
@ -618,7 +608,7 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
return nil, err
}
domainModels, addPorts, addDomains, err = getWebsiteDomains(create.Domains, httpPort, create.WebsiteID)
domainModels, addPorts, _, err = getWebsiteDomains(create.Domains, httpPort, create.WebsiteID)
if err != nil {
return nil, err
}
@ -626,7 +616,7 @@ func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate)
_ = OperateFirewallPort(nil, addPorts)
}()
if err := addListenAndServerName(website, addPorts, addDomains); err != nil {
if err = addListenAndServerName(website, domainModels); err != nil {
return nil, err
}
@ -868,8 +858,22 @@ func (w WebsiteService) GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS,
if err != nil {
return response.WebsiteHTTPS{}, err
}
var res response.WebsiteHTTPS
res.HttpsPort = website.HttpsPort
var (
res response.WebsiteHTTPS
httpsPorts []string
)
websiteDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(websiteId))
for _, domain := range websiteDomains {
if domain.SSL {
httpsPorts = append(httpsPorts, strconv.Itoa(domain.Port))
}
}
if len(httpsPorts) == 0 {
nginxInstall, _ := getAppInstallByKey(constant.AppOpenresty)
res.HttpsPort = strconv.Itoa(nginxInstall.HttpsPort)
} else {
res.HttpsPort = strings.Join(httpsPorts, ",")
}
if website.WebsiteSSLID == 0 {
res.Enable = false
return res, nil
@ -925,17 +929,17 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
if !req.Enable {
website.Protocol = constant.ProtocolHTTP
website.WebsiteSSLID = 0
httpsPort := website.HttpsPort
if httpsPort == 0 {
_, httpsPort, err = getAppInstallPort(constant.AppOpenresty)
if err != nil {
return nil, err
}
}
httpsPortStr := strconv.Itoa(httpsPort)
if err := deleteListenAndServerName(website, []string{httpsPortStr, "[::]:" + httpsPortStr}, []string{}); err != nil {
return nil, err
}
//httpsPort := req.HttpsPort
//if len(httpsPort) == 0 {
// _, httpsPort, err = getAppInstallPort(constant.AppOpenresty)
// if err != nil {
// return nil, err
// }
//}
//httpsPortStr := strconv.Itoa(httpsPort)
//if err = deleteListenAndServerName(website, []string{httpsPortStr, "[::]:" + httpsPortStr}, []string{}); err != nil {
// return nil, err
//}
nginxParams := getNginxParamsFromStaticFile(dto.SSL, nil)
nginxParams = append(nginxParams,
dto.NginxParam{
@ -1035,18 +1039,18 @@ func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteH
}
website.Protocol = constant.ProtocolHTTPS
if err := applySSL(&website, websiteSSL, req); err != nil {
if err = applySSL(&website, websiteSSL, req); err != nil {
return nil, err
}
website.HttpConfig = req.HttpConfig
if websiteSSL.ID == 0 {
if err := websiteSSLRepo.Create(ctx, &websiteSSL); err != nil {
if err = websiteSSLRepo.Create(ctx, &websiteSSL); err != nil {
return nil, err
}
website.WebsiteSSLID = websiteSSL.ID
}
if err := websiteRepo.Save(ctx, &website); err != nil {
if err = websiteRepo.Save(ctx, &website); err != nil {
return nil, err
}
return &res, nil

View File

@ -7,7 +7,6 @@ import (
"os"
"path"
"path/filepath"
"reflect"
"strconv"
"strings"
"time"
@ -35,40 +34,6 @@ import (
"gorm.io/gorm"
)
func getDomain(domainStr string, defaultPort int) (model.WebsiteDomain, error) {
var (
err error
domain = model.WebsiteDomain{}
portN int
)
domainArray := strings.Split(domainStr, ":")
if len(domainArray) == 1 {
domain.Domain, err = handleChineseDomain(domainArray[0])
if err != nil {
return domain, err
}
domain.Port = defaultPort
return domain, nil
}
if len(domainArray) > 1 {
domain.Domain, err = handleChineseDomain(domainArray[0])
if err != nil {
return domain, err
}
portStr := domainArray[1]
portN, err = strconv.Atoi(portStr)
if err != nil {
return domain, buserr.WithName("ErrTypePort", portStr)
}
if portN <= 0 || portN > 65535 {
return domain, buserr.New("ErrTypePortRange")
}
domain.Port = portN
return domain, nil
}
return domain, nil
}
func handleChineseDomain(domain string) (string, error) {
if common.ContainsChinese(domain) {
return common.PunycodeEncode(domain)
@ -481,7 +446,7 @@ func delWafConfig(website model.Website, force bool) error {
return nil
}
func addListenAndServerName(website model.Website, ports []int, domains []string) error {
func addListenAndServerName(website model.Website, domains []model.WebsiteDomain) error {
nginxFull, err := getNginxFull(&website)
if err != nil {
return nil
@ -489,16 +454,20 @@ func addListenAndServerName(website model.Website, ports []int, domains []string
nginxConfig := nginxFull.SiteConfig
config := nginxFull.SiteConfig.Config
server := config.FindServers()[0]
for _, port := range ports {
server.AddListen(strconv.Itoa(port), false)
if website.IPV6 {
server.UpdateListen("[::]:"+strconv.Itoa(port), false)
}
}
for _, domain := range domains {
server.AddServerName(domain)
var params []string
if website.Protocol == constant.ProtocolHTTPS && domain.SSL {
params = append(params, "ssl", "http2")
}
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
server.AddListen(strconv.Itoa(domain.Port), false, params...)
if website.IPV6 {
server.UpdateListen("[::]:"+strconv.Itoa(domain.Port), false, params...)
}
server.UpdateServerName([]string{domain.Domain})
}
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
return err
}
return nginxCheckAndReload(nginxConfig.OldContent, nginxConfig.FilePath, nginxFull.Install.ContainerName)
@ -568,6 +537,24 @@ func createPemFile(website model.Website, websiteSSL model.WebsiteSSL) error {
return nil
}
func getHttpsPort(website *model.Website) ([]int, error) {
websiteDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(website.ID))
var httpsPorts []int
for _, domain := range websiteDomains {
if domain.SSL {
httpsPorts = append(httpsPorts, domain.Port)
}
}
if len(httpsPorts) == 0 {
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
if err != nil {
return nil, err
}
httpsPorts = append(httpsPorts, nginxInstall.HttpsPort)
}
return httpsPorts, nil
}
func applySSL(website *model.Website, websiteSSL model.WebsiteSSL, req request.WebsiteHTTPSOp) error {
nginxFull, err := getNginxFull(website)
if err != nil {
@ -587,18 +574,19 @@ func applySSL(website *model.Website, websiteSSL model.WebsiteSSL, req request.W
server := config.FindServers()[0]
httpPort := strconv.Itoa(nginxFull.Install.HttpPort)
httpsPort := nginxFull.Install.HttpsPort
if req.HttpsPort > 0 {
httpsPort = req.HttpsPort
httpsPort, err := getHttpsPort(website)
if err != nil {
return err
}
website.HttpsPort = httpsPort
httpPortIPV6 := "[::]:" + httpPort
httpsPortIPV6 := "[::]:" + strconv.Itoa(httpsPort)
server.UpdateListen(strconv.Itoa(httpsPort), website.DefaultServer, "ssl", "http2")
for _, port := range httpsPort {
httpsPortIPV6 := "[::]:" + strconv.Itoa(port)
server.UpdateListen(strconv.Itoa(port), website.DefaultServer, "ssl", "http2")
if website.IPV6 {
server.UpdateListen(httpsPortIPV6, website.DefaultServer, "ssl", "http2")
}
}
switch req.HttpConfig {
case constant.HTTPSOnly:
@ -911,30 +899,36 @@ func changeServiceName(newComposeContent, newServiceName string) (composeByte []
return yaml.Marshal(composeMap)
}
func getWebsiteDomains(domains string, defaultPort int, websiteID uint) (domainModels []model.WebsiteDomain, addPorts []int, addDomains []string, err error) {
func getWebsiteDomains(domains []request.WebsiteDomain, defaultPort int, websiteID uint) (domainModels []model.WebsiteDomain, addPorts []int, addDomains []string, err error) {
var (
ports = make(map[int]struct{})
existPort = make(map[int]struct{})
)
domainArray := strings.Split(domains, "\n")
for _, domain := range domainArray {
if domain == "" {
existDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(websiteID))
for _, domain := range existDomains {
existPort[domain.Port] = struct{}{}
}
for _, domain := range domains {
if domain.Domain == "" {
continue
}
if !common.IsValidDomain(domain) {
err = buserr.WithName("ErrDomainFormat", domain)
if !common.IsValidDomain(domain.Domain) {
err = buserr.WithName("ErrDomainFormat", domain.Domain)
return
}
var domainModel model.WebsiteDomain
domainModel, err = getDomain(domain, defaultPort)
domainModel.Domain, err = handleChineseDomain(domain.Domain)
if err != nil {
return
}
if reflect.DeepEqual(domainModel, model.WebsiteDomain{}) {
continue
domainModel.Port = domain.Port
if domain.Port == 0 {
domain.Port = defaultPort
}
domainModel.SSL = domain.SSL
domainModel.WebsiteID = websiteID
domainModels = append(domainModels, domainModel)
if domainModel.Port != defaultPort {
if _, ok := existPort[domainModel.Port]; !ok {
ports[domainModel.Port] = struct{}{}
}
if exist, _ := websiteDomainRepo.GetFirst(websiteDomainRepo.WithDomain(domainModel.Domain), websiteDomainRepo.WithWebsiteId(websiteID)); exist.ID == 0 {
@ -950,6 +944,10 @@ func getWebsiteDomains(domains string, defaultPort int, websiteID uint) (domainM
}
for port := range ports {
if port == defaultPort {
addPorts = append(addPorts, port)
continue
}
if existPorts, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithPort(port)); len(existPorts) == 0 {
errMap := make(map[string]interface{})
errMap["port"] = port

View File

@ -19,6 +19,7 @@ func Init() {
migrations.InitPHPExtensions,
migrations.AddTask,
migrations.UpdateWebsite,
migrations.UpdateWebsiteDomain,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)

View File

@ -296,3 +296,11 @@ var UpdateWebsite = &gormigrate.Migration{
&model.Website{})
},
}
var UpdateWebsiteDomain = &gormigrate.Migration{
ID: "20240808-update-website-domain",
Migrate: func(tx *gorm.DB) error {
return tx.AutoMigrate(
&model.WebsiteDomain{})
},
}

View File

@ -67,14 +67,12 @@ export namespace Website {
}
export interface WebSiteCreateReq {
primaryDomain: string;
type: string;
alias: string;
remark: string;
appType: string;
appInstallId: number;
webSiteGroupId: number;
otherDomains: string;
proxy: string;
proxyType: string;
ftpUser: string;
@ -88,6 +86,7 @@ export namespace Website {
dbFormat?: string;
dbUser?: string;
dbHost?: string;
domains: SubDomain[];
}
export interface WebSiteUpdateReq {
@ -128,7 +127,13 @@ export namespace Website {
export interface DomainCreate {
websiteID: number;
domains: string;
domains: SubDomain[];
}
interface SubDomain {
domain: string;
port: number;
ssl: boolean;
}
export interface DomainDelete {
@ -288,7 +293,7 @@ export namespace Website {
SSLProtocol: string[];
algorithm: string;
hsts: boolean;
httpsPort: number;
httpsPort?: string;
}
export interface CheckReq {

View File

@ -2130,6 +2130,8 @@ const message = {
"When the reverse proxy backend is HTTPS, you might need to set the origin SNI. Please refer to the CDN service provider's documentation for details.",
createDb: 'Create Database',
enableSSLHelper: 'Failure to enable will not affect the creation of the website',
batchAdd: 'Batch Add Domains',
generateDomain: 'Generate',
},
php: {
short_open_tag: 'Short tag support',

View File

@ -1980,6 +1980,8 @@ const message = {
sniHelper: '反代後端為 https 的時候可能需要設置回源 SNI具體需要看 CDN 服務商文檔',
createDb: '建立資料庫',
enableSSLHelper: '開啟失敗不會影響網站創建',
batchAdd: '批量添加域名',
generateDomain: '生成',
},
php: {
short_open_tag: '短標簽支持',

View File

@ -1982,6 +1982,8 @@ const message = {
sniHelper: '反代后端为 https 的时候可能需要设置回源 SNI具体需要看 CDN 服务商文档',
createDb: '创建数据库',
enableSSLHelper: '开启失败不会影响网站创建',
batchAdd: '批量添加域名',
generateDomain: '生成',
},
php: {
short_open_tag: '短标签支持',

View File

@ -1,30 +1,8 @@
<template>
<el-drawer
v-model="open"
:close-on-click-modal="false"
:close-on-press-escape="false"
:title="$t('website.addDomain')"
size="40%"
:before-close="handleClose"
>
<template #header>
<DrawerHeader :header="$t('website.addDomain')" :back="handleClose" />
</template>
<el-row v-loading="loading">
<el-col :span="22" :offset="1">
<el-form ref="domainForm" label-position="top" :model="domain" :rules="rules">
<el-form-item :label="$t('website.domain')" prop="domains">
<el-input
type="textarea"
:rows="3"
v-model="domain.domains"
:placeholder="$t('website.domainHelper')"
></el-input>
</el-form-item>
<DrawerPro v-model="open" :header="$t('website.addDomain')" :back="handleClose">
<el-form ref="domainForm" label-position="top" :model="create">
<DomainCreate v-model:form="create"></DomainCreate>
</el-form>
</el-col>
</el-row>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
@ -33,29 +11,31 @@
</el-button>
</span>
</template>
</el-drawer>
</DrawerPro>
</template>
<script lang="ts" setup>
import DrawerHeader from '@/components/drawer-header/index.vue';
import { CreateDomain } from '@/api/modules/website';
import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { FormInstance } from 'element-plus';
import { ref } from 'vue';
import { MsgSuccess } from '@/utils/message';
import DomainCreate from '@/views/website/website/domain-create/index.vue';
const domainForm = ref<FormInstance>();
const rules = ref({
domains: [Rules.requiredInput],
const initDomain = () => ({
domain: '',
port: 80,
ssl: false,
});
const open = ref(false);
const loading = ref(false);
const domain = ref({
const create = ref({
websiteID: 0,
domains: '',
domains: [initDomain()],
domainStr: '',
});
const em = defineEmits(['close']);
@ -66,7 +46,9 @@ const handleClose = () => {
};
const acceptParams = async (websiteId: number) => {
domain.value.websiteID = Number(websiteId);
create.value.websiteID = Number(websiteId);
create.value.domains = [initDomain()];
create.value.domainStr = '';
open.value = true;
};
@ -77,7 +59,7 @@ const submit = async (formEl: FormInstance | undefined) => {
return;
}
loading.value = true;
CreateDomain(domain.value)
CreateDomain(create.value)
.then(() => {
MsgSuccess(i18n.global.t('commons.msg.createSuccess'));
handleClose();

View File

@ -13,8 +13,8 @@
<el-switch v-model="form.enable" @change="changeEnable"></el-switch>
</el-form-item>
<div v-if="form.enable">
<el-form-item :label="'HTTPS ' + $t('commons.table.port')" prop="httpsPort">
<el-input v-model.number="form.httpsPort" />
<el-form-item :label="'HTTPS ' + $t('commons.table.port')" prop="HttpsPort">
<el-text>{{ form.httpsPort }}</el-text>
</el-form-item>
<el-text type="warning" class="!ml-2">{{ $t('website.ipWebsiteWarn') }}</el-text>
<el-divider content-position="left">{{ $t('website.SSLConfig') }}</el-divider>
@ -173,7 +173,7 @@ import { GetHTTPSConfig, ListSSL, SearchAcmeAccount, UpdateHTTPSConfig } from '@
import { ElMessageBox, FormInstance } from 'element-plus';
import { computed, onMounted, reactive, ref } from 'vue';
import i18n from '@/lang';
import { Rules, checkNumberRange } from '@/global/form-rules';
import { Rules } from '@/global/form-rules';
import { dateFormatSimple, getProvider, getAccountName } from '@/utils/util';
import { MsgSuccess } from '@/utils/message';
import FileList from '@/components/file-list/index.vue';
@ -204,7 +204,7 @@ const form = reactive({
algorithm:
'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED',
SSLProtocol: ['TLSv1.3', 'TLSv1.2', 'TLSv1.1', 'TLSv1'],
httpsPort: 443,
httpsPort: '443',
});
const loading = ref(false);
const ssls = ref();
@ -222,7 +222,6 @@ const rules = ref({
SSLProtocol: [Rules.requiredSelect],
algorithm: [Rules.requiredInput],
acmeAccountID: [Rules.requiredInput],
httpsPort: [Rules.requiredInput, checkNumberRange(1, 65535)],
});
const resData = ref();
const sslReq = reactive({
@ -301,10 +300,8 @@ const get = () => {
form.acmeAccountID = data.SSL.acmeAccountId;
}
form.hsts = data.hsts;
if (data.httpsPort > 0) {
form.httpsPort = data.httpsPort;
}
}
listSSL();
listAcmeAccount();
});

View File

@ -262,21 +262,7 @@
<span class="input-help">{{ $t('app.allowPortHelper') }}</span>
</el-form-item>
</div>
<el-form-item :label="$t('website.primaryDomain')" prop="primaryDomain">
<el-input
v-model.trim="website.primaryDomain"
@input="changeAlias(website.primaryDomain)"
:placeholder="$t('website.primaryDomainHelper')"
></el-input>
</el-form-item>
<el-form-item :label="$t('website.otherDomains')" prop="otherDomains">
<el-input
type="textarea"
:rows="3"
v-model="website.otherDomains"
:placeholder="$t('website.domainHelper')"
></el-input>
</el-form-item>
<DomainCreate v-model:form="website"></DomainCreate>
<el-form-item prop="IPV6">
<el-checkbox v-model="website.IPV6" :label="$t('website.ipv6')" size="large" />
</el-form-item>
@ -517,7 +503,7 @@ import { ElForm, FormInstance } from 'element-plus';
import { reactive, ref } from 'vue';
import Params from '@/views/app-store/detail/params/index.vue';
import Check from '../check/index.vue';
import { MsgError, MsgSuccess } from '@/utils/message';
import { MsgSuccess } from '@/utils/message';
import { GetGroupList } from '@/api/modules/group';
import { Group } from '@/api/interface/group';
import { SearchRuntimes } from '@/api/modules/runtime';
@ -528,6 +514,7 @@ import { GetAppService } from '@/api/modules/app';
import { v4 as uuidv4 } from 'uuid';
import { dateFormatSimple, getProvider, getAccountName } from '@/utils/util';
import { Website } from '@/api/interface/website';
import DomainCreate from '@/views/website/website/domain-create/index.vue';
const websiteForm = ref<FormInstance>();
@ -577,6 +564,7 @@ const initData = () => ({
enableSSL: false,
websiteSSLID: undefined,
acmeAccountID: undefined,
domains: [],
});
const website = ref(initData());
const rules = ref<any>({
@ -813,16 +801,6 @@ const changeAppType = (type: string) => {
}
};
function isSubsetOfStrArray(primaryDomain: string, otherDomains: string): boolean {
const arr: string[] = otherDomains.split('\n');
for (const item of arr) {
if (primaryDomain === item) {
return false;
}
}
return true;
}
const openTaskLog = (taskID: string) => {
taskLog.value.acceptParams(taskID);
};
@ -859,12 +837,6 @@ const submit = async (formEl: FormInstance | undefined) => {
return;
}
loading.value = true;
const flag = isSubsetOfStrArray(website.value.primaryDomain, website.value.otherDomains);
if (!flag) {
MsgError(i18n.global.t('website.containWarn'));
loading.value = false;
return;
}
PreCheck({})
.then((res) => {
if (res.data) {
@ -897,6 +869,17 @@ const submit = async (formEl: FormInstance | undefined) => {
});
};
watch(
() => website.value.domains,
(value) => {
if (value.length > 0) {
const firstDomain = value[0].domain;
changeAlias(firstDomain);
}
},
{ deep: true },
);
const changeAlias = (value: string) => {
const domain = value.split(':')[0];
website.value.alias = domain;

View File

@ -0,0 +1,138 @@
<template>
<div>
<el-form-item :label="$t('website.batchAdd')">
<el-row :gutter="20">
<el-col :span="20">
<el-input
class="p-w-400"
type="textarea"
:rows="3"
v-model="create.domainStr"
:placeholder="$t('website.domainHelper')"
></el-input>
</el-col>
<el-col :span="4">
<el-button @click="gengerateDomains" :disabled="create.domainStr == ''">
{{ $t('website.generateDomain') }}
</el-button>
</el-col>
</el-row>
</el-form-item>
<el-row :gutter="20" v-for="(domain, index) of create.domains" :key="index">
<el-col :span="8">
<el-form-item
:label="index == 0 ? $t('website.domain') : ''"
:prop="`domains.${index}.domain`"
:rules="rules.domain"
>
<el-input
type="string"
v-model="create.domains[index].domain"
:placeholder="index > 0 ? $t('website.domain') : ''"
></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
:label="index == 0 ? $t('commons.table.port') : ''"
:prop="`domains.${index}.port`"
:rules="rules.port"
>
<el-input type="number" v-model.number="create.domains[index].port"></el-input>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item :label="index == 0 ? 'SSL' : ''" prop="ssl">
<el-checkbox
v-model="create.domains[index].ssl"
:disabled="create.domains[index].port == 80"
></el-checkbox>
</el-form-item>
</el-col>
<el-col :span="4" v-if="index == 0">
<el-form-item :label="$t('commons.button.add') + $t('commons.table.port')">
<el-button @click="addDomain">
<el-icon><Plus /></el-icon>
</el-button>
</el-form-item>
</el-col>
<el-col :span="4" v-else>
<el-form-item>
<el-button @click="removeDomain(index)" link type="primary">
<el-icon><Delete /></el-icon>
</el-button>
</el-form-item>
</el-col>
</el-row>
</div>
</template>
<script lang="ts" setup>
import { Rules, checkNumberRange } from '@/global/form-rules';
import { ref } from 'vue';
const props = defineProps({
form: {
type: Object,
default: function () {
return {};
},
},
});
const rules = ref({
port: [Rules.requiredInput, Rules.paramPort, checkNumberRange(1, 65535)],
domain: [Rules.requiredInput, Rules.domain],
domains: {
type: Array,
},
});
const initDomain = () => ({
domain: '',
port: 80,
ssl: false,
});
const create = ref({
websiteID: 0,
domains: [initDomain()],
domainStr: '',
});
const addDomain = () => {
create.value.domains.push(initDomain());
};
const removeDomain = (index: number) => {
create.value.domains.splice(index, 1);
};
const gengerateDomains = () => {
const lines = create.value.domainStr.split(/\r?\n/);
lines.forEach((line) => {
const [domain, port] = line.split(':');
const exists = (domain: string, port: number): boolean => {
return create.value.domains.some((info) => info.domain === domain && info.port === port);
};
if (exists(domain, port ? Number(port) : 80)) {
return;
}
if (create.value.domains[0].domain == '') {
create.value.domains[0].domain = domain;
create.value.domains[0].port = port ? Number(port) : 80;
} else {
create.value.domains.push({
domain,
port: port ? Number(port) : 80,
ssl: false,
});
}
});
};
const handleParams = () => {
props.form.domains = create.value.domains;
};
onMounted(() => {
handleParams();
});
</script>