mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2024-11-27 20:49:03 +08:00
feat: OpenResty 支持新增扩展 (#6543)
This commit is contained in:
parent
6a4897b0aa
commit
3c0dca6992
@ -116,3 +116,60 @@ func (b *BaseApi) ClearNginxProxyCache(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags OpenResty
|
||||
// @Summary Build OpenResty
|
||||
// @Description 构建 OpenResty
|
||||
// @Accept json
|
||||
// @Param request body request.NginxBuildReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /openresty/build [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"构建 OpenResty","formatEN":"Build OpenResty"}
|
||||
func (b *BaseApi) BuildNginx(c *gin.Context) {
|
||||
var req request.NginxBuildReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := nginxService.Build(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags OpenResty
|
||||
// @Summary Update OpenResty module
|
||||
// @Description 更新 OpenResty 模块
|
||||
// @Accept json
|
||||
// @Param request body request.NginxModuleUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /openresty/module/update [post]
|
||||
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 OpenResty 模块","formatEN":"Update OpenResty module"}
|
||||
func (b *BaseApi) UpdateNginxModule(c *gin.Context) {
|
||||
var req request.NginxModuleUpdate
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := nginxService.UpdateModule(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithOutData(c)
|
||||
}
|
||||
|
||||
// @Tags OpenResty
|
||||
// @Summary Get OpenResty modules
|
||||
// @Description 获取 OpenResty 模块
|
||||
// @Success 200 {array} response.NginxModule
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /openresty/modules [get]
|
||||
func (b *BaseApi) GetNginxModules(c *gin.Context) {
|
||||
modules, err := nginxService.GetModules()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, modules)
|
||||
}
|
||||
|
@ -106,3 +106,16 @@ type NginxRedirectUpdate struct {
|
||||
Content string `json:"content" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
}
|
||||
|
||||
type NginxBuildReq struct {
|
||||
TaskID string `json:"taskID" validate:"required"`
|
||||
}
|
||||
|
||||
type NginxModuleUpdate struct {
|
||||
Operate string `json:"operate" validate:"required,oneof=create delete update"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Script string `json:"script"`
|
||||
Packages string `json:"packages"`
|
||||
Enable bool `json:"enable"`
|
||||
Params string `json:"params"`
|
||||
}
|
||||
|
@ -67,3 +67,11 @@ type NginxProxyCache struct {
|
||||
CacheExpire int `json:"cacheExpire" `
|
||||
CacheExpireUnit string `json:"cacheExpireUnit" `
|
||||
}
|
||||
|
||||
type NginxModule struct {
|
||||
Name string `json:"name"`
|
||||
Script string `json:"script"`
|
||||
Packages []string `json:"packages"`
|
||||
Params string `json:"params"`
|
||||
Enable bool `json:"enable"`
|
||||
}
|
||||
|
@ -1,7 +1,13 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
cmd2 "github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
||||
"github.com/subosito/gotenv"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
@ -29,6 +35,10 @@ type INginxService interface {
|
||||
GetStatus() (response.NginxStatus, error)
|
||||
UpdateConfigFile(req request.NginxConfigFileUpdate) error
|
||||
ClearProxyCache() error
|
||||
|
||||
Build(req request.NginxBuildReq) error
|
||||
GetModules() ([]response.NginxModule, error)
|
||||
UpdateModule(req request.NginxModuleUpdate) error
|
||||
}
|
||||
|
||||
func NewINginxService() INginxService {
|
||||
@ -152,3 +162,157 @@ func (n NginxService) ClearProxyCache() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n NginxService) Build(req request.NginxBuildReq) error {
|
||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fileOp := files.NewFileOp()
|
||||
buildPath := path.Join(nginxInstall.GetPath(), "build")
|
||||
if !fileOp.Stat(buildPath) {
|
||||
return buserr.New("ErrBuildDirNotFound")
|
||||
}
|
||||
moduleConfigPath := path.Join(buildPath, "module.json")
|
||||
moduleContent, err := fileOp.GetContent(moduleConfigPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
modules []response.NginxModule
|
||||
addModuleParams []string
|
||||
addPackages []string
|
||||
)
|
||||
if len(moduleContent) > 0 {
|
||||
_ = json.Unmarshal(moduleContent, &modules)
|
||||
bashFile, err := os.OpenFile(path.Join(buildPath, "tmp", "pre.sh"), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer bashFile.Close()
|
||||
bashFileWriter := bufio.NewWriter(bashFile)
|
||||
for _, module := range modules {
|
||||
if !module.Enable {
|
||||
continue
|
||||
}
|
||||
_, err = bashFileWriter.WriteString(module.Script + "\n")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addModuleParams = append(addModuleParams, module.Params)
|
||||
addPackages = append(addPackages, module.Packages...)
|
||||
}
|
||||
err = bashFileWriter.Flush()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
envs, err := gotenv.Read(nginxInstall.GetEnvPath())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
envs["RESTY_CONFIG_OPTIONS_MORE"] = ""
|
||||
envs["RESTY_ADD_PACKAGE_BUILDDEPS"] = ""
|
||||
if len(addModuleParams) > 0 {
|
||||
envs["RESTY_CONFIG_OPTIONS_MORE"] = strings.Join(addModuleParams, " ")
|
||||
}
|
||||
if len(addPackages) > 0 {
|
||||
envs["RESTY_ADD_PACKAGE_BUILDDEPS"] = strings.Join(addPackages, " ")
|
||||
}
|
||||
_ = gotenv.Write(envs, nginxInstall.GetEnvPath())
|
||||
|
||||
buildTask, err := task.NewTaskWithOps(nginxInstall.Name, task.TaskBuild, task.TaskScopeApp, req.TaskID, nginxInstall.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buildTask.AddSubTask("", func(t *task.Task) error {
|
||||
if err = cmd2.ExecWithLogFile(fmt.Sprintf("docker compose -f %s build", nginxInstall.GetComposePath()), 15*time.Minute, t.Task.LogFile); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = compose.DownAndUp(nginxInstall.GetComposePath())
|
||||
return err
|
||||
}, nil)
|
||||
|
||||
go func() {
|
||||
_ = buildTask.Execute()
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n NginxService) GetModules() ([]response.NginxModule, error) {
|
||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fileOp := files.NewFileOp()
|
||||
var modules []response.NginxModule
|
||||
moduleConfigPath := path.Join(nginxInstall.GetPath(), "build", "module.json")
|
||||
if !fileOp.Stat(moduleConfigPath) {
|
||||
return modules, nil
|
||||
}
|
||||
moduleContent, err := fileOp.GetContent(moduleConfigPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(moduleContent) > 0 {
|
||||
_ = json.Unmarshal(moduleContent, &modules)
|
||||
}
|
||||
return modules, nil
|
||||
}
|
||||
|
||||
func (n NginxService) UpdateModule(req request.NginxModuleUpdate) error {
|
||||
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fileOp := files.NewFileOp()
|
||||
var modules []response.NginxModule
|
||||
moduleConfigPath := path.Join(nginxInstall.GetPath(), "build", "module.json")
|
||||
if !fileOp.Stat(moduleConfigPath) {
|
||||
_ = fileOp.CreateFile(moduleConfigPath)
|
||||
}
|
||||
moduleContent, err := fileOp.GetContent(moduleConfigPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(moduleContent) > 0 {
|
||||
_ = json.Unmarshal(moduleContent, &modules)
|
||||
}
|
||||
switch req.Operate {
|
||||
case "create":
|
||||
for _, module := range modules {
|
||||
if module.Name == req.Name {
|
||||
return buserr.New("ErrNameIsExist")
|
||||
}
|
||||
}
|
||||
modules = append(modules, response.NginxModule{
|
||||
Name: req.Name,
|
||||
Script: req.Script,
|
||||
Packages: strings.Split(req.Packages, " "),
|
||||
Params: req.Params,
|
||||
Enable: true,
|
||||
})
|
||||
case "update":
|
||||
for i, module := range modules {
|
||||
if module.Name == req.Name {
|
||||
modules[i].Script = req.Script
|
||||
modules[i].Packages = strings.Split(req.Packages, " ")
|
||||
modules[i].Params = req.Params
|
||||
modules[i].Enable = req.Enable
|
||||
break
|
||||
}
|
||||
}
|
||||
case "delete":
|
||||
for i, module := range modules {
|
||||
if module.Name == req.Name {
|
||||
modules = append(modules[:i], modules[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
moduleByte, err := json.Marshal(modules)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fileOp.SaveFileWithByte(moduleConfigPath, moduleByte, 0644)
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ const (
|
||||
TaskRestart = "TaskRestart"
|
||||
TaskBackup = "TaskBackup"
|
||||
TaskSync = "TaskSync"
|
||||
TaskBuild = "TaskBuild"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -99,6 +99,7 @@ ErrDomainIsUsed: "Domain is already used by website {{ .name }}"
|
||||
ErrDomainFormat: "{{ .name }} domain format error"
|
||||
ErrDefaultAlias: "default is a reserved code name, please use another code name"
|
||||
ErrParentWebsite: "You need to delete the subsite(s) {{ .name }} first"
|
||||
ErrBuildDirNotFound: "Build directory does not exist"
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "The certificate {{ .name }} is being used by the website and cannot be removed"
|
||||
@ -244,4 +245,5 @@ TaskSync: "Sync"
|
||||
LocalApp: "Local App"
|
||||
SubTask: "Subtask"
|
||||
RuntimeExtension: "Runtime Extension"
|
||||
TaskBuild: "Build"
|
||||
|
||||
|
@ -99,6 +99,7 @@ ErrDomainIsUsed: "域名已被網站【{{ .name }}】使用"
|
||||
ErrDomainFormat: "{{ .name }} 域名格式不正確"
|
||||
ErrDefaultAlias: "default 為保留代號,請使用其他代號"
|
||||
ErrParentWebsite: "需要先刪除子網站 {{ .name }}"
|
||||
ErrBuildDirNotFound: "編譯目錄不存在"
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "{{ .name }} 證書正在被網站使用,無法刪除"
|
||||
@ -246,4 +247,6 @@ TaskSync: "同步"
|
||||
LocalApp: "本地應用"
|
||||
SubTask: "子任務"
|
||||
RuntimeExtension: "運行環境擴展"
|
||||
TaskBuild: "構建"
|
||||
|
||||
|
||||
|
@ -99,6 +99,7 @@ ErrDomainIsUsed: "域名已被网站【{{ .name }}】使用"
|
||||
ErrDomainFormat: "{{ .name }} 域名格式不正确"
|
||||
ErrDefaultAlias: "default 为保留代号,请使用其他代号"
|
||||
ErrParentWebsite: "需要先删除子网站 {{ .name }}"
|
||||
ErrBuildDirNotFound: "构建目录不存在"
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "{{ .name }} 证书正在被网站使用,无法删除"
|
||||
@ -247,4 +248,5 @@ AppStore: "应用商店"
|
||||
TaskSync: "同步"
|
||||
LocalApp: "本地应用"
|
||||
SubTask: "子任务"
|
||||
RuntimeExtension: "运行环境扩展"
|
||||
RuntimeExtension: "运行环境扩展"
|
||||
TaskBuild: "构建"
|
@ -19,5 +19,8 @@ func (a *NginxRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
groupRouter.GET("/status", baseApi.GetNginxStatus)
|
||||
groupRouter.POST("/file", baseApi.UpdateNginxFile)
|
||||
groupRouter.POST("/clear", baseApi.ClearNginxProxyCache)
|
||||
groupRouter.POST("/build", baseApi.BuildNginx)
|
||||
groupRouter.POST("/modules/update", baseApi.UpdateNginxModule)
|
||||
groupRouter.GET("/modules", baseApi.GetNginxModules)
|
||||
}
|
||||
}
|
||||
|
@ -28,4 +28,25 @@ export namespace Nginx {
|
||||
content: string;
|
||||
backup: boolean;
|
||||
}
|
||||
|
||||
export interface NginxBuildReq {
|
||||
taskID: string;
|
||||
}
|
||||
|
||||
export interface NginxModule {
|
||||
name: string;
|
||||
script?: string;
|
||||
packages?: string[];
|
||||
enable: boolean;
|
||||
params: string;
|
||||
}
|
||||
|
||||
export interface NginxModuleUpdate {
|
||||
operate: string;
|
||||
name: string;
|
||||
script?: string;
|
||||
packages?: string;
|
||||
enable: boolean;
|
||||
params: string;
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ export const GetNginxConfigByScope = (req: Nginx.NginxScopeReq) => {
|
||||
};
|
||||
|
||||
export const UpdateNginxConfigByScope = (req: Nginx.NginxConfigReq) => {
|
||||
return http.post<any>(`/openresty/update`, req);
|
||||
return http.post(`/openresty/update`, req);
|
||||
};
|
||||
|
||||
export const GetNginxStatus = () => {
|
||||
@ -19,9 +19,21 @@ export const GetNginxStatus = () => {
|
||||
};
|
||||
|
||||
export const UpdateNginxConfigFile = (req: Nginx.NginxFileUpdate) => {
|
||||
return http.post<any>(`/openresty/file`, req);
|
||||
return http.post(`/openresty/file`, req);
|
||||
};
|
||||
|
||||
export const ClearNginxCache = () => {
|
||||
return http.post<any>(`/openresty/clear`);
|
||||
return http.post(`/openresty/clear`);
|
||||
};
|
||||
|
||||
export const BuildNginx = (req: Nginx.NginxBuildReq) => {
|
||||
return http.post(`/openresty/build`, req);
|
||||
};
|
||||
|
||||
export const GetNginxModules = () => {
|
||||
return http.get<Nginx.NginxModule[]>(`/openresty/modules`);
|
||||
};
|
||||
|
||||
export const UpdateNginxModule = (req: Nginx.NginxModuleUpdate) => {
|
||||
return http.post(`/openresty/modules/update`, req);
|
||||
};
|
||||
|
@ -9,13 +9,7 @@
|
||||
:width="width"
|
||||
>
|
||||
<div>
|
||||
<highlightjs
|
||||
class="editor-main"
|
||||
ref="editorRef"
|
||||
language="JavaScript"
|
||||
:autodetect="false"
|
||||
:code="content"
|
||||
></highlightjs>
|
||||
<highlightjs class="editor-main" ref="editorRef" :autodetect="false" :code="content"></highlightjs>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@ -98,7 +92,7 @@ const getContent = (pre: boolean) => {
|
||||
});
|
||||
data.value = res.data;
|
||||
if (res.data.content != '') {
|
||||
if (stopSignals.some((signal) => res.data.content.endsWith(signal))) {
|
||||
if (stopSignals.some((signal) => res.data.content.includes(signal))) {
|
||||
onCloseLog();
|
||||
}
|
||||
if (end.value) {
|
||||
|
@ -2251,6 +2251,15 @@ const message = {
|
||||
clearProxyCache: 'Clear reverse proxy cache',
|
||||
clearProxyCacheWarn:
|
||||
'Clearing the reverse proxy cache will affect all websites configured with cache and requires restarting OpenResty. Do you want to continue? ',
|
||||
create: 'Add a new module',
|
||||
update: 'Edit a module',
|
||||
params: 'Parameters',
|
||||
packages: 'Packages',
|
||||
script: 'Scripts',
|
||||
module: 'Modules',
|
||||
build: 'Build',
|
||||
buildWarn:
|
||||
'Building OpenResty requires reserving a certain amount of CPU and memory, which may take a long time, please be patient',
|
||||
},
|
||||
ssl: {
|
||||
create: 'Apply',
|
||||
|
@ -2096,6 +2096,14 @@ const message = {
|
||||
saveAndReload: '保存並重載',
|
||||
clearProxyCache: '清除反代快取',
|
||||
clearProxyCacheWarn: '清除反代快取會影響所有配置快取的網站,並且需要重新啟動 OpenResty, 是否繼續? ',
|
||||
create: '新增模組',
|
||||
update: '編輯模組',
|
||||
params: '參數',
|
||||
packages: '軟體包',
|
||||
script: '腳本',
|
||||
module: '模組',
|
||||
build: '建構',
|
||||
buildWarn: '建構 OpenResty 需要預留一定的 CPU 和內存,時間較長,請耐心等待',
|
||||
},
|
||||
ssl: {
|
||||
create: '申請證書',
|
||||
|
@ -2097,6 +2097,14 @@ const message = {
|
||||
saveAndReload: '保存并重载',
|
||||
clearProxyCache: '清除反代缓存',
|
||||
clearProxyCacheWarn: '清除反代缓存会影响所有配置缓存的网站,并且需要重启 OpenResty, 是否继续?',
|
||||
create: '新增模块',
|
||||
update: '编辑模块',
|
||||
params: '参数',
|
||||
packages: '软件包',
|
||||
script: '脚本',
|
||||
module: '模块',
|
||||
build: '构建',
|
||||
buildWarn: '构建 OpenResty 需要预留一定的 CPU 和内存,时间较长,请耐心等待',
|
||||
},
|
||||
ssl: {
|
||||
create: '申请证书',
|
||||
|
@ -23,6 +23,9 @@
|
||||
<div v-if="row.status === 'Success'">
|
||||
<el-tag type="success">{{ $t('commons.status.success') }}</el-tag>
|
||||
</div>
|
||||
<div v-else-if="row.status === 'Running'">
|
||||
<el-tag type="primary">{{ $t('process.running') }}</el-tag>
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-tooltip
|
||||
class="box-item"
|
||||
|
@ -83,7 +83,12 @@
|
||||
<el-text type="primary" class="cursor-pointer" @click="openConfig(row.id)">
|
||||
{{ row.primaryDomain }}
|
||||
</el-text>
|
||||
<el-popover placement="top-start" trigger="hover" @before-enter="searchDomains(row.id)">
|
||||
<el-popover
|
||||
placement="left"
|
||||
trigger="hover"
|
||||
:width="300"
|
||||
@before-enter="searchDomains(row.id)"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button link icon="Promotion" class="ml-2.5"></el-button>
|
||||
</template>
|
||||
@ -95,6 +100,9 @@
|
||||
{{ getUrl(domain, row) }}
|
||||
</el-button>
|
||||
</td>
|
||||
<td>
|
||||
<CopyButton :content="getUrl(domain, row)" type="icon" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -23,12 +23,16 @@
|
||||
>
|
||||
{{ $t('website.log') }}
|
||||
</el-button>
|
||||
<el-button type="primary" :plain="activeName !== '5'" @click="changeTab('5')">
|
||||
{{ $t('runtime.module') }}
|
||||
</el-button>
|
||||
</template>
|
||||
<template #main>
|
||||
<Status v-if="activeName === '1'" :status="status" />
|
||||
<Source v-if="activeName === '2'" />
|
||||
<NginxPer v-if="activeName === '3'" />
|
||||
<ContainerLog v-if="activeName === '4'" ref="dialogContainerLogRef" />
|
||||
<Module v-if="activeName === '5'" />
|
||||
</template>
|
||||
</LayoutContent>
|
||||
</template>
|
||||
@ -39,6 +43,7 @@ import { nextTick, ref } from 'vue';
|
||||
import ContainerLog from '@/components/container-log/index.vue';
|
||||
import NginxPer from './performance/index.vue';
|
||||
import Status from './status/index.vue';
|
||||
import Module from './module/index.vue';
|
||||
|
||||
const activeName = ref('1');
|
||||
const dialogContainerLogRef = ref();
|
||||
|
105
frontend/src/views/website/website/nginx/module/index.vue
Normal file
105
frontend/src/views/website/website/nginx/module/index.vue
Normal file
@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<div>
|
||||
<ComplexTable :data="data" @search="search()" :heightDiff="350" v-loading="loading">
|
||||
<template #toolbar>
|
||||
<el-button type="primary" @click="openOperate">{{ $t('commons.button.create') }}</el-button>
|
||||
<el-button type="primary" plain @click="buildNginx">{{ $t('nginx.build') }}</el-button>
|
||||
</template>
|
||||
<el-table-column prop="name" :label="$t('commons.table.name')" />
|
||||
<el-table-column prop="params" :label="$t('nginx.params')" />
|
||||
<el-table-column :label="$t('commons.table.status')" fix>
|
||||
<template #default="{ row }">
|
||||
<el-switch v-model="row.enable" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<fu-table-operations
|
||||
:ellipsis="2"
|
||||
width="100px"
|
||||
:buttons="buttons"
|
||||
:label="$t('commons.table.operate')"
|
||||
fixed="right"
|
||||
fix
|
||||
/>
|
||||
</ComplexTable>
|
||||
<TaskLog ref="taskLogRef" />
|
||||
<Operate ref="operateRef" @close="search" />
|
||||
<OpDialog ref="deleteRef" @search="search" @cancel="search" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { BuildNginx, GetNginxModules, UpdateNginxModule } from '@/api/modules/nginx';
|
||||
import { newUUID } from '@/utils/util';
|
||||
import TaskLog from '@/components/task-log/index.vue';
|
||||
import Operate from './operate/index.vue';
|
||||
import i18n from '@/lang';
|
||||
import { Nginx } from '@/api/interface/nginx';
|
||||
|
||||
const taskLogRef = ref();
|
||||
const data = ref([]);
|
||||
const loading = ref(false);
|
||||
const buttons = [
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
click: function (row: Nginx.NginxModule) {
|
||||
deleteModule(row);
|
||||
},
|
||||
},
|
||||
];
|
||||
const operateRef = ref();
|
||||
const deleteRef = ref();
|
||||
|
||||
const buildNginx = async () => {
|
||||
ElMessageBox.confirm(i18n.global.t('nginx.buildWarn'), i18n.global.t('nginx.build'), {
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
}).then(async () => {
|
||||
const taskID = newUUID();
|
||||
try {
|
||||
await BuildNginx({
|
||||
taskID: taskID,
|
||||
});
|
||||
openTaskLog(taskID);
|
||||
} catch (error) {}
|
||||
});
|
||||
};
|
||||
|
||||
const search = () => {
|
||||
loading.value = true;
|
||||
GetNginxModules()
|
||||
.then((res) => {
|
||||
data.value = res.data;
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const openTaskLog = (taskID: string) => {
|
||||
taskLogRef.value.openWithTaskID(taskID);
|
||||
};
|
||||
|
||||
const openOperate = () => {
|
||||
operateRef.value.acceptParams();
|
||||
};
|
||||
|
||||
const deleteModule = async (row: Nginx.NginxModule) => {
|
||||
const data = {
|
||||
name: row.name,
|
||||
operate: 'delete',
|
||||
};
|
||||
deleteRef.value.acceptParams({
|
||||
title: i18n.global.t('commons.button.delete'),
|
||||
names: [row.name],
|
||||
msg: i18n.global.t('commons.msg.operatorHelper', [
|
||||
i18n.global.t('nginx.module'),
|
||||
i18n.global.t('commons.button.delete'),
|
||||
]),
|
||||
api: UpdateNginxModule,
|
||||
params: data,
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
search();
|
||||
});
|
||||
</script>
|
@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<DrawerPro
|
||||
v-model="open"
|
||||
:header="$t('nginx.' + mode)"
|
||||
size="large"
|
||||
:resource="mode === 'edit' ? module.name : ''"
|
||||
:back="handleClose"
|
||||
>
|
||||
<el-form ref="moduleForm" label-position="top" :model="module" :rules="rules">
|
||||
<el-form-item :label="$t('commons.table.name')" prop="name">
|
||||
<el-input v-model.trim="module.name" :disabled="mode === 'edit'"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('nginx.params')" prop="params">
|
||||
<el-input v-model.trim="module.params"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('nginx.packages')" prop="packages">
|
||||
<el-input v-model.trim="module.packages"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('nginx.script')" prop="script">
|
||||
<el-input v-model="module.script" type="textarea" :rows="10"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submit(moduleForm)" :disabled="loading">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</DrawerPro>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { UpdateNginxModule } from '@/api/modules/nginx';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { FormInstance } from 'element-plus';
|
||||
|
||||
const moduleForm = ref<FormInstance>();
|
||||
const open = ref(false);
|
||||
const em = defineEmits(['close']);
|
||||
const mode = ref('create');
|
||||
const loading = ref(false);
|
||||
const module = ref({
|
||||
name: '',
|
||||
operate: 'create',
|
||||
script: '',
|
||||
enable: true,
|
||||
params: '',
|
||||
packages: '',
|
||||
});
|
||||
const rules = ref({
|
||||
name: [Rules.requiredInput, Rules.simpleName],
|
||||
params: [Rules.requiredInput],
|
||||
});
|
||||
|
||||
const handleClose = () => {
|
||||
open.value = false;
|
||||
em('close', false);
|
||||
};
|
||||
|
||||
const acceptParams = async () => {
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const submit = async (form: FormInstance) => {
|
||||
await form.validate();
|
||||
if (form.validate()) {
|
||||
loading.value = true;
|
||||
const data = {
|
||||
...module.value,
|
||||
operate: mode.value,
|
||||
};
|
||||
UpdateNginxModule(data)
|
||||
.then(() => {
|
||||
if (mode.value === 'edit') {
|
||||
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
|
||||
} else if (mode.value === 'create') {
|
||||
MsgSuccess(i18n.global.t('commons.msg.createSuccess'));
|
||||
}
|
||||
handleClose();
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user