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

feat: Runtime environment supports running without port configuration (#7775)

This commit is contained in:
zhengkunwang 2025-01-26 22:29:20 +08:00 committed by GitHub
parent 90354451d2
commit edf24dbc49
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 171 additions and 146 deletions

View File

@ -42,8 +42,9 @@ type Volume struct {
} }
type ExposedPort struct { type ExposedPort struct {
HostPort int `json:"hostPort"` HostPort int `json:"hostPort"`
ContainerPort int `json:"containerPort"` ContainerPort int `json:"containerPort"`
HostIP string `json:"hostIP"`
} }
type RuntimeDelete struct { type RuntimeDelete struct {

View File

@ -23,7 +23,7 @@ type RuntimeDTO struct {
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
CodeDir string `json:"codeDir"` CodeDir string `json:"codeDir"`
AppParams []AppParam `json:"appParams"` AppParams []AppParam `json:"appParams"`
Port int `json:"port"` Port string `json:"port"`
Path string `json:"path"` Path string `json:"path"`
ExposedPorts []request.ExposedPort `json:"exposedPorts"` ExposedPorts []request.ExposedPort `json:"exposedPorts"`
Environments []request.Environment `json:"environments"` Environments []request.Environment `json:"environments"`

View File

@ -19,7 +19,7 @@ type Runtime struct {
Type string `gorm:"not null" json:"type"` Type string `gorm:"not null" json:"type"`
Status string `gorm:"not null" json:"status"` Status string `gorm:"not null" json:"status"`
Resource string `gorm:"not null" json:"resource"` Resource string `gorm:"not null" json:"resource"`
Port int `json:"port"` Port string `json:"port"`
Message string `json:"message"` Message string `json:"message"`
CodeDir string `json:"codeDir"` CodeDir string `json:"codeDir"`
ContainerName string `json:"containerName"` ContainerName string `json:"containerName"`

View File

@ -18,6 +18,12 @@ func WithByID(id uint) DBOption {
} }
} }
func WithByNOTID(id uint) DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("id != ?", id)
}
}
func WithByIDs(ids []uint) DBOption { func WithByIDs(ids []uint) DBOption {
return func(g *gorm.DB) *gorm.DB { return func(g *gorm.DB) *gorm.DB {
return g.Where("id in (?)", ids) return g.Where("id in (?)", ids)

View File

@ -2,6 +2,7 @@ package repo
import ( import (
"context" "context"
"fmt"
"github.com/1Panel-dev/1Panel/agent/app/model" "github.com/1Panel-dev/1Panel/agent/app/model"
"github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/global"
@ -55,7 +56,9 @@ func (r *RuntimeRepo) WithNotId(id uint) DBOption {
func (r *RuntimeRepo) WithPort(port int) DBOption { func (r *RuntimeRepo) WithPort(port int) DBOption {
return func(g *gorm.DB) *gorm.DB { return func(g *gorm.DB) *gorm.DB {
return g.Where("port = ?", port) portStr := fmt.Sprintf("%d", port)
regexPattern := fmt.Sprintf("(^|,)%s(,|$)", portStr)
return g.Where("port REGEXP ?", regexPattern)
} }
} }

View File

@ -93,7 +93,7 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) (*model.Runtime, e
return nil, err return nil, err
} }
} }
var hostPorts []string
switch create.Type { switch create.Type {
case constant.RuntimePHP: case constant.RuntimePHP:
if create.Resource == constant.ResourceLocal { if create.Resource == constant.ResourceLocal {
@ -116,17 +116,12 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) (*model.Runtime, e
} }
create.Install = true create.Install = true
for _, export := range create.ExposedPorts { for _, export := range create.ExposedPorts {
hostPorts = append(hostPorts, strconv.Itoa(export.HostPort))
if err := checkPortExist(export.HostPort); err != nil { if err := checkPortExist(export.HostPort); err != nil {
return nil, err return nil, err
} }
} }
} }
portValue, _ := create.Params["PANEL_APP_PORT_HTTP"]
if portValue != nil {
if err := checkPortExist(int(portValue.(float64))); err != nil {
return nil, err
}
}
containerName, ok := create.Params["CONTAINER_NAME"] containerName, ok := create.Params["CONTAINER_NAME"]
if !ok { if !ok {
return nil, buserr.New("ErrContainerNameIsNull") return nil, buserr.New("ErrContainerNameIsNull")
@ -159,7 +154,7 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) (*model.Runtime, e
Resource: create.Resource, Resource: create.Resource,
Version: create.Version, Version: create.Version,
ContainerName: containerName.(string), ContainerName: containerName.(string),
Port: int(portValue.(float64)), Port: strings.Join(hostPorts, ","),
} }
switch create.Type { switch create.Type {
@ -352,34 +347,30 @@ func (r *RuntimeService) Get(id uint) (*response.RuntimeDTO, error) {
return nil, err return nil, err
} }
for k, v := range envs { for k, v := range envs {
switch k { if strings.Contains(k, "CONTAINER_PORT") || strings.Contains(k, "HOST_PORT") {
case "APP_PORT", "PANEL_APP_PORT_HTTP": if strings.Contains(k, "CONTAINER_PORT") {
port, err := strconv.Atoi(v) r := regexp.MustCompile(`_(\d+)$`)
if err != nil { matches := r.FindStringSubmatch(k)
return nil, err containerPort, err := strconv.Atoi(v)
} if err != nil {
res.Params[k] = port return nil, err
default:
if strings.Contains(k, "CONTAINER_PORT") || strings.Contains(k, "HOST_PORT") {
if strings.Contains(k, "CONTAINER_PORT") {
r := regexp.MustCompile(`_(\d+)$`)
matches := r.FindStringSubmatch(k)
containerPort, err := strconv.Atoi(v)
if err != nil {
return nil, err
}
hostPort, err := strconv.Atoi(envs[fmt.Sprintf("HOST_PORT_%s", matches[1])])
if err != nil {
return nil, err
}
res.ExposedPorts = append(res.ExposedPorts, request.ExposedPort{
ContainerPort: containerPort,
HostPort: hostPort,
})
} }
} else { hostPort, err := strconv.Atoi(envs[fmt.Sprintf("HOST_PORT_%s", matches[1])])
res.Params[k] = v if err != nil {
return nil, err
}
hostIP := envs[fmt.Sprintf("HOST_IP_%s", matches[1])]
if hostIP == "" {
hostIP = "0.0.0.0"
}
res.ExposedPorts = append(res.ExposedPorts, request.ExposedPort{
ContainerPort: containerPort,
HostPort: hostPort,
HostIP: hostIP,
})
} }
} else {
res.Params[k] = v
} }
} }
if v, ok := envs["CONTAINER_PACKAGE_URL"]; ok { if v, ok := envs["CONTAINER_PACKAGE_URL"]; ok {
@ -437,7 +428,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
} }
oldImage := runtime.Image oldImage := runtime.Image
oldEnv := runtime.Env oldEnv := runtime.Env
port := int(req.Params["PANEL_APP_PORT_HTTP"].(float64)) var hostPorts []string
switch runtime.Type { switch runtime.Type {
case constant.RuntimePHP: case constant.RuntimePHP:
exist, _ := runtimeRepo.GetFirst(runtimeRepo.WithImage(req.Name), runtimeRepo.WithNotId(req.ID)) exist, _ := runtimeRepo.GetFirst(runtimeRepo.WithImage(req.Name), runtimeRepo.WithNotId(req.ID))
@ -445,14 +436,9 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
return buserr.New("ErrImageExist") return buserr.New("ErrImageExist")
} }
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo, constant.RuntimePython, constant.RuntimeDotNet: case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo, constant.RuntimePython, constant.RuntimeDotNet:
if runtime.Port != port {
if err = checkPortExist(port); err != nil {
return err
}
runtime.Port = port
}
for _, export := range req.ExposedPorts { for _, export := range req.ExposedPorts {
if err = checkPortExist(export.HostPort); err != nil { hostPorts = append(hostPorts, strconv.Itoa(export.HostPort))
if err = checkRuntimePortExist(export.HostPort, false, runtime.ID); err != nil {
return err return err
} }
} }
@ -522,7 +508,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo, constant.RuntimePython, constant.RuntimeDotNet: case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo, constant.RuntimePython, constant.RuntimeDotNet:
runtime.Version = req.Version runtime.Version = req.Version
runtime.CodeDir = req.CodeDir runtime.CodeDir = req.CodeDir
runtime.Port = port runtime.Port = strings.Join(hostPorts, ",")
runtime.Status = constant.RuntimeReCreating runtime.Status = constant.RuntimeReCreating
_ = runtimeRepo.Save(runtime) _ = runtimeRepo.Save(runtime)
go reCreateRuntime(runtime) go reCreateRuntime(runtime)

View File

@ -6,6 +6,8 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/1Panel-dev/1Panel/agent/i18n"
"github.com/1Panel-dev/1Panel/agent/utils/common"
"io" "io"
"os" "os"
"os/exec" "os/exec"
@ -319,7 +321,7 @@ func handleParams(create request.RuntimeCreate, projectDir string) (composeConte
return return
} }
for k := range env { for k := range env {
if strings.HasPrefix(k, "CONTAINER_PORT_") || strings.HasPrefix(k, "HOST_PORT_") { if strings.HasPrefix(k, "CONTAINER_PORT_") || strings.HasPrefix(k, "HOST_PORT_") || strings.HasPrefix(k, "HOST_IP_") || strings.Contains(k, "APP_PORT") {
delete(env, k) delete(env, k)
} }
} }
@ -431,18 +433,19 @@ func handleCompose(env gotenv.Env, composeContent []byte, create request.Runtime
for name, service := range services { for name, service := range services {
serviceName = name serviceName = name
serviceValue = service.(map[string]interface{}) serviceValue = service.(map[string]interface{})
_, ok := serviceValue["ports"].([]interface{}) delete(serviceValue, "ports")
if ok { if create.ExposedPorts != nil && len(create.ExposedPorts) > 0 {
var ports []interface{} var ports []interface{}
ports = append(ports, "${HOST_IP}:${PANEL_APP_PORT_HTTP}:${APP_PORT}")
for i, port := range create.ExposedPorts { for i, port := range create.ExposedPorts {
containerPortStr := fmt.Sprintf("CONTAINER_PORT_%d", i) containerPortStr := fmt.Sprintf("CONTAINER_PORT_%d", i)
hostPortStr := fmt.Sprintf("HOST_PORT_%d", i) hostPortStr := fmt.Sprintf("HOST_PORT_%d", i)
existMap[containerPortStr] = struct{}{} existMap[containerPortStr] = struct{}{}
existMap[hostPortStr] = struct{}{} existMap[hostPortStr] = struct{}{}
ports = append(ports, fmt.Sprintf("${HOST_IP}:${%s}:${%s}", hostPortStr, containerPortStr)) hostIPStr := fmt.Sprintf("HOST_IP_%d", i)
ports = append(ports, fmt.Sprintf("${%s}:${%s}:${%s}", hostIPStr, hostPortStr, containerPortStr))
create.Params[containerPortStr] = port.ContainerPort create.Params[containerPortStr] = port.ContainerPort
create.Params[hostPortStr] = port.HostPort create.Params[hostPortStr] = port.HostPort
create.Params[hostIPStr] = port.HostIP
} }
serviceValue["ports"] = ports serviceValue["ports"] = ports
} }
@ -667,3 +670,34 @@ func getDockerComposeVolumes(yml []byte) ([]request.Volume, error) {
} }
return res, nil return res, nil
} }
func checkRuntimePortExist(port int, scanPort bool, runtimeID uint) error {
errMap := make(map[string]interface{})
errMap["port"] = port
appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithPort(port))
if appInstall.ID > 0 {
errMap["type"] = i18n.GetMsgByKey("TYPE_APP")
errMap["name"] = appInstall.Name
return buserr.WithMap("ErrPortExist", errMap, nil)
}
opts := []repo.DBOption{runtimeRepo.WithPort(port)}
if runtimeID > 0 {
opts = append(opts, repo.WithByNOTID(runtimeID))
}
runtime, _ := runtimeRepo.GetFirst(opts...)
if runtime != nil {
errMap["type"] = i18n.GetMsgByKey("TYPE_RUNTIME")
errMap["name"] = runtime.Name
return buserr.WithMap("ErrPortExist", errMap, nil)
}
domain, _ := websiteDomainRepo.GetFirst(websiteDomainRepo.WithPort(port))
if domain.ID > 0 {
errMap["type"] = i18n.GetMsgByKey("TYPE_DOMAIN")
errMap["name"] = domain.Domain
return buserr.WithMap("ErrPortExist", errMap, nil)
}
if scanPort && common.ScanPort(port) {
return buserr.WithDetail("ErrPortInUsed", port, nil)
}
return nil
}

View File

@ -2,7 +2,7 @@ base:
install_dir: /opt install_dir: /opt
mode: dev mode: dev
remote_rul: remote_url:
repo_url: https://resource.fit2cloud.com/1panel/package repo_url: https://resource.fit2cloud.com/1panel/package
resource_url: https://resource.fit2cloud.com/1panel/resource resource_url: https://resource.fit2cloud.com/1panel/resource
app_repo: https://apps-assets.fit2cloud.com app_repo: https://apps-assets.fit2cloud.com

View File

@ -65,6 +65,7 @@ export namespace Runtime {
export interface ExposedPort { export interface ExposedPort {
hostPort: number; hostPort: number;
containerPort: number; containerPort: number;
hostIP: string;
} }
export interface Environment { export interface Environment {

View File

@ -1,5 +1,5 @@
<template> <template>
<el-drawer v-model="localOpenPage" :destroy-on-close="true" :close-on-click-modal="false" :size="size"> <el-drawer v-model="localOpenPage" :destroy-on-close="true" :size="size">
<template #header> <template #header>
<el-page-header @back="handleBack"> <el-page-header @back="handleBack">
<template #content> <template #content>

View File

@ -47,11 +47,8 @@ import { FormRules } from 'element-plus';
import CustomSetting from '@/xpack/views/appstore/index.vue'; import CustomSetting from '@/xpack/views/appstore/index.vue';
import DefaultDomain from './default-domain/index.vue'; import DefaultDomain from './default-domain/index.vue';
import { GlobalStore } from '@/store'; import { GlobalStore } from '@/store';
import { storeToRefs } from 'pinia';
const globalStore = GlobalStore(); const globalStore = GlobalStore();
const { isProductPro } = storeToRefs(globalStore);
const rules = ref<FormRules>({ const rules = ref<FormRules>({
defaultDomain: [Rules.domainOrIP], defaultDomain: [Rules.domainOrIP],
}); });

View File

@ -43,8 +43,12 @@
<el-table-column :label="$t('runtime.version')" prop="version"></el-table-column> <el-table-column :label="$t('runtime.version')" prop="version"></el-table-column>
<el-table-column :label="$t('runtime.externalPort')" prop="port" min-width="110px"> <el-table-column :label="$t('runtime.externalPort')" prop="port" min-width="110px">
<template #default="{ row }"> <template #default="{ row }">
{{ row.port }} <span v-for="(port, index) in row.port.split(',')" :key="index">
<el-button link :icon="Promotion" @click="goDashboard(row.port, 'http')"></el-button> <el-button link @click="goDashboard(port, 'http')">
{{ port }}
<el-icon class="el-icon--right"><Promotion /></el-icon>
</el-button>
</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="status"> <el-table-column :label="$t('commons.table.status')" prop="status">

View File

@ -122,8 +122,6 @@ const submit = async (formEl: FormInstance | undefined) => {
if (runtime.exposedPorts && runtime.exposedPorts.length > 0) { if (runtime.exposedPorts && runtime.exposedPorts.length > 0) {
const containerPortMap = new Map(); const containerPortMap = new Map();
const hostPortMap = new Map(); const hostPortMap = new Map();
containerPortMap[runtime.params['APP_PORT']] = true;
hostPortMap[runtime.port] = true;
for (const port of runtime.exposedPorts) { for (const port of runtime.exposedPorts) {
if (containerPortMap[port.containerPort]) { if (containerPortMap[port.containerPort]) {
MsgError(i18n.global.t('runtime.portError')); MsgError(i18n.global.t('runtime.portError'));

View File

@ -15,7 +15,7 @@
</el-col> </el-col>
<el-col :span="4"> <el-col :span="4">
<el-form-item> <el-form-item>
<el-button type="primary" @click="removeEnv(index)" link> <el-button type="primary" @click="removeEnv(index)" link class="mt-1">
{{ $t('commons.button.delete') }} {{ $t('commons.button.delete') }}
</el-button> </el-button>
</el-form-item> </el-form-item>
@ -23,7 +23,7 @@
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="4"> <el-col :span="4">
<el-button @click="addEnv">{{ $t('commons.button.add') }}{{ $t('runtime.environment') }}</el-button> <el-button @click="addEnv">{{ $t('commons.button.add') }}</el-button>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>

View File

@ -43,8 +43,12 @@
<el-table-column :label="$t('runtime.version')" prop="version"></el-table-column> <el-table-column :label="$t('runtime.version')" prop="version"></el-table-column>
<el-table-column :label="$t('runtime.externalPort')" prop="port" min-width="110px"> <el-table-column :label="$t('runtime.externalPort')" prop="port" min-width="110px">
<template #default="{ row }"> <template #default="{ row }">
{{ row.port }} <span v-for="(port, index) in row.port.split(',')" :key="index">
<el-button link :icon="Promotion" @click="goDashboard(row.port, 'http')"></el-button> <el-button link @click="goDashboard(port, 'http')">
{{ port }}
<el-icon class="el-icon--right"><Promotion /></el-icon>
</el-button>
</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="status"> <el-table-column :label="$t('commons.table.status')" prop="status">

View File

@ -144,8 +144,6 @@ const submit = async (formEl: FormInstance | undefined) => {
if (runtime.exposedPorts && runtime.exposedPorts.length > 0) { if (runtime.exposedPorts && runtime.exposedPorts.length > 0) {
const containerPortMap = new Map(); const containerPortMap = new Map();
const hostPortMap = new Map(); const hostPortMap = new Map();
containerPortMap[runtime.params['APP_PORT']] = true;
hostPortMap[runtime.port] = true;
for (const port of runtime.exposedPorts) { for (const port of runtime.exposedPorts) {
if (containerPortMap[port.containerPort]) { if (containerPortMap[port.containerPort]) {
MsgError(i18n.global.t('runtime.portError')); MsgError(i18n.global.t('runtime.portError'));

View File

@ -43,8 +43,12 @@
<el-table-column :label="$t('runtime.version')" prop="version"></el-table-column> <el-table-column :label="$t('runtime.version')" prop="version"></el-table-column>
<el-table-column :label="$t('runtime.externalPort')" prop="port" min-width="110px"> <el-table-column :label="$t('runtime.externalPort')" prop="port" min-width="110px">
<template #default="{ row }"> <template #default="{ row }">
{{ row.port }} <span v-for="(port, index) in row.port.split(',')" :key="index">
<el-button link :icon="Promotion" @click="goDashboard(row.port, 'http')"></el-button> <el-button link @click="goDashboard(port, 'http')">
{{ port }}
<el-icon class="el-icon--right"><Promotion /></el-icon>
</el-button>
</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="status"> <el-table-column :label="$t('commons.table.status')" prop="status">

View File

@ -135,8 +135,6 @@ const submit = async (formEl: FormInstance | undefined) => {
if (runtime.exposedPorts && runtime.exposedPorts.length > 0) { if (runtime.exposedPorts && runtime.exposedPorts.length > 0) {
const containerPortMap = new Map(); const containerPortMap = new Map();
const hostPortMap = new Map(); const hostPortMap = new Map();
containerPortMap[runtime.params['APP_PORT']] = true;
hostPortMap[runtime.port] = true;
for (const port of runtime.exposedPorts) { for (const port of runtime.exposedPorts) {
if (containerPortMap[port.containerPort]) { if (containerPortMap[port.containerPort]) {
MsgError(i18n.global.t('runtime.portError')); MsgError(i18n.global.t('runtime.portError'));

View File

@ -43,8 +43,12 @@
<el-table-column :label="$t('runtime.version')" prop="version"></el-table-column> <el-table-column :label="$t('runtime.version')" prop="version"></el-table-column>
<el-table-column :label="$t('runtime.externalPort')" prop="port" min-width="110px"> <el-table-column :label="$t('runtime.externalPort')" prop="port" min-width="110px">
<template #default="{ row }"> <template #default="{ row }">
{{ row.port }} <span v-for="(port, index) in row.port.split(',')" :key="index">
<el-button link :icon="Promotion" @click="goDashboard(row.port, 'http')"></el-button> <el-button link @click="goDashboard(port, 'http')">
{{ port }}
<el-icon class="el-icon--right"><Promotion /></el-icon>
</el-button>
</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="status"> <el-table-column :label="$t('commons.table.status')" prop="status">

View File

@ -167,8 +167,6 @@ const submit = async (formEl: FormInstance | undefined) => {
if (runtime.exposedPorts && runtime.exposedPorts.length > 0) { if (runtime.exposedPorts && runtime.exposedPorts.length > 0) {
const containerPortMap = new Map(); const containerPortMap = new Map();
const hostPortMap = new Map(); const hostPortMap = new Map();
containerPortMap[runtime.params['APP_PORT']] = true;
hostPortMap[runtime.port] = true;
for (const port of runtime.exposedPorts) { for (const port of runtime.exposedPorts) {
if (containerPortMap[port.containerPort]) { if (containerPortMap[port.containerPort]) {
MsgError(i18n.global.t('runtime.portError')); MsgError(i18n.global.t('runtime.portError'));

View File

@ -1,49 +1,42 @@
<template> <template>
<el-row :gutter="20"> <div class="mt-1.5">
<el-col :span="7"> <el-text>{{ $t('commons.table.port') }}</el-text>
<el-form-item :label="$t('runtime.appPort')" prop="params.APP_PORT" :rules="rules.port"> <div class="mt-1.5">
<el-input v-model.number="runtime.params.APP_PORT" /> <el-row :gutter="20" v-for="(port, index) in runtime.exposedPorts" :key="index">
<span class="input-help">{{ $t('runtime.appPortHelper') }}</span> <el-col :span="7">
</el-form-item> <el-form-item :prop="`exposedPorts.${index}.hostPort`" :rules="rules.port">
</el-col> <el-input v-model.number="port.hostPort" :placeholder="$t('runtime.externalPort')" />
<el-col :span="7"> </el-form-item>
<el-form-item :label="$t('runtime.externalPort')" prop="params.PANEL_APP_PORT_HTTP" :rules="rules.port"> </el-col>
<el-input v-model.number="runtime.params.PANEL_APP_PORT_HTTP" /> <el-col :span="7">
<span class="input-help">{{ $t('runtime.externalPortHelper') }}</span> <el-form-item :prop="`exposedPorts.${index}.containerPort`" :rules="rules.port">
</el-form-item> <el-input v-model.number="port.containerPort" :placeholder="$t('runtime.appPort')" />
</el-col> </el-form-item>
<el-col :span="4"> </el-col>
<el-form-item :label="$t('commons.button.add') + $t('commons.table.port')"> <el-col :span="7">
<el-button @click="addPort"> <el-text>{{ $t('app.allowPort') }}</el-text>
<el-icon><Plus /></el-icon> <el-switch
</el-button> class="ml-1"
</el-form-item> v-model="port.hostIP"
</el-col> :active-value="'0.0.0.0'"
<el-col :span="6"> :inactive-value="'127.0.0.1'"
<el-form-item :label="$t('app.allowPort')"> />
<el-switch v-model="runtime.params.HOST_IP" :active-value="'0.0.0.0'" :inactive-value="'127.0.0.1'" /> </el-col>
</el-form-item> <el-col :span="2">
</el-col> <el-form-item>
</el-row> <el-button type="primary" @click="removePort(index)" link class="mt-1">
<el-row :gutter="20" v-for="(port, index) in runtime.exposedPorts" :key="index"> {{ $t('commons.button.delete') }}
<el-col :span="7"> </el-button>
<el-form-item :prop="`exposedPorts.${index}.containerPort`" :rules="rules.port"> </el-form-item>
<el-input v-model.number="port.containerPort" :placeholder="$t('runtime.appPort')" /> </el-col>
</el-form-item> </el-row>
</el-col> </div>
<el-col :span="7"> <el-row :gutter="20">
<el-form-item :prop="`exposedPorts.${index}.hostPort`" :rules="rules.port"> <el-col :span="4">
<el-input v-model.number="port.hostPort" :placeholder="$t('runtime.externalPort')" /> <el-button @click="addPort">{{ $t('commons.button.add') }}</el-button>
</el-form-item> </el-col>
</el-col> </el-row>
<el-col :span="4"> </div>
<el-form-item>
<el-button type="primary" @click="removePort(index)" link>
{{ $t('commons.button.delete') }}
</el-button>
</el-form-item>
</el-col>
</el-row>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -65,16 +58,6 @@ const props = defineProps({
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
const runtime = useVModel(props, 'modelValue', emit); const runtime = useVModel(props, 'modelValue', emit);
watch(
() => runtime.value.params['APP_PORT'],
(newVal) => {
if (newVal) {
runtime.value.params['PANEL_APP_PORT_HTTP'] = newVal;
}
},
{ deep: true },
);
const rules = reactive<FormRules>({ const rules = reactive<FormRules>({
port: [Rules.requiredInput, Rules.paramPort, checkNumberRange(1, 65535)], port: [Rules.requiredInput, Rules.paramPort, checkNumberRange(1, 65535)],
}); });
@ -83,6 +66,7 @@ const addPort = () => {
runtime.value.exposedPorts.push({ runtime.value.exposedPorts.push({
hostPort: undefined, hostPort: undefined,
containerPort: undefined, containerPort: undefined,
hostIP: '0.0.0.0',
}); });
}; };

View File

@ -43,8 +43,12 @@
<el-table-column :label="$t('runtime.version')" prop="version"></el-table-column> <el-table-column :label="$t('runtime.version')" prop="version"></el-table-column>
<el-table-column :label="$t('runtime.externalPort')" prop="port" min-width="110px"> <el-table-column :label="$t('runtime.externalPort')" prop="port" min-width="110px">
<template #default="{ row }"> <template #default="{ row }">
{{ row.port }} <span v-for="(port, index) in row.port.split(',')" :key="index">
<el-button link :icon="Promotion" @click="goDashboard(row.port, 'http')"></el-button> <el-button link @click="goDashboard(port, 'http')">
{{ port }}
<el-icon class="el-icon--right"><Promotion /></el-icon>
</el-button>
</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="status"> <el-table-column :label="$t('commons.table.status')" prop="status">

View File

@ -111,8 +111,6 @@ const submit = async (formEl: FormInstance | undefined) => {
if (runtime.exposedPorts && runtime.exposedPorts.length > 0) { if (runtime.exposedPorts && runtime.exposedPorts.length > 0) {
const containerPortMap = new Map(); const containerPortMap = new Map();
const hostPortMap = new Map(); const hostPortMap = new Map();
containerPortMap[runtime.params['APP_PORT']] = true;
hostPortMap[runtime.port] = true;
for (const port of runtime.exposedPorts) { for (const port of runtime.exposedPorts) {
if (containerPortMap[port.containerPort]) { if (containerPortMap[port.containerPort]) {
MsgError(i18n.global.t('runtime.portError')); MsgError(i18n.global.t('runtime.portError'));

View File

@ -15,7 +15,7 @@
</el-col> </el-col>
<el-col :span="4"> <el-col :span="4">
<el-form-item> <el-form-item>
<el-button type="primary" @click="removeEnv(index)" link> <el-button type="primary" @click="removeEnv(index)" link class="mt-1">
{{ $t('commons.button.delete') }} {{ $t('commons.button.delete') }}
</el-button> </el-button>
</el-form-item> </el-form-item>
@ -23,7 +23,7 @@
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="4"> <el-col :span="4">
<el-button @click="addEnv">{{ $t('commons.button.add') }}{{ $t('container.mount') }}</el-button> <el-button @click="addEnv">{{ $t('commons.button.add') }}</el-button>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>

View File

@ -164,7 +164,7 @@
</div> </div>
<div v-if="website.type === 'subsite'"> <div v-if="website.type === 'subsite'">
<el-form-item :label="$t('website.parentWbeiste')" prop="parentWebsiteID"> <el-form-item :label="$t('website.parentWbeiste')" prop="parentWebsiteID">
<el-select v-model="website.parentWebsiteID" @change="getDirConfig(website.parentWebsiteID)"> <el-select v-model="website.parentWebsiteID" @change="getDir(website.parentWebsiteID)">
<el-option <el-option
v-for="(site, index) in parentWebsites" v-for="(site, index) in parentWebsites"
:key="index" :key="index"
@ -521,7 +521,7 @@ import {
listSSL, listSSL,
preCheck, preCheck,
searchAcmeAccount, searchAcmeAccount,
GetDirConfig, getDirConfig,
} from '@/api/modules/website'; } from '@/api/modules/website';
import { Rules, checkNumberRange } from '@/global/form-rules'; import { Rules, checkNumberRange } from '@/global/form-rules';
import i18n from '@/lang'; import i18n from '@/lang';
@ -923,14 +923,14 @@ const listWebsites = async () => {
parentWebsites.value = res.data; parentWebsites.value = res.data;
if (res.data.length > 0) { if (res.data.length > 0) {
website.value.parentWebsiteID = res.data[0].id; website.value.parentWebsiteID = res.data[0].id;
getDirConfig(res.data[0].id); getDir(res.data[0].id);
} }
} catch (error) {} } catch (error) {}
}; };
const getDirConfig = async (websiteID: number) => { const getDir = async (websiteID: number) => {
try { try {
const res = await GetDirConfig({ id: websiteID }); const res = await getDirConfig({ id: websiteID });
dirs.value = res.data.dirs; dirs.value = res.data.dirs;
if (res.data.dirs.length > 0) { if (res.data.dirs.length > 0) {
website.value.siteDir = res.data.dirs[0]; website.value.siteDir = res.data.dirs[0];

View File

@ -548,8 +548,11 @@ const getUrl = (domain: Website.Domain, website: Website.Website): string => {
return url; return url;
}; };
onMounted(() => { onBeforeMount(() => {
search(); console.log('1111');
listGroup(); }),
}); onMounted(() => {
search();
listGroup();
});
</script> </script>