fix: Fix issue where website group can still be deleted even if it contains other websites (#8049)

This commit is contained in:
zhengkunwang 2025-03-03 16:18:47 +08:00 committed by GitHub
parent 451b69072d
commit adbf44a176
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 619 additions and 13 deletions

View file

@ -67,4 +67,5 @@ var (
websiteCAService = service.NewIWebsiteCAService() websiteCAService = service.NewIWebsiteCAService()
taskService = service.NewITaskService() taskService = service.NewITaskService()
groupService = service.NewIGroupService()
) )

96
agent/app/api/v2/group.go Normal file
View file

@ -0,0 +1,96 @@
package v2
import (
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/gin-gonic/gin"
)
// @Tags System Group
// @Summary Create group
// @Accept json
// @Param request body dto.GroupCreate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /agent/groups [post]
// @x-panel-log {"bodyKeys":["name","type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建组 [name][type]","formatEN":"create group [name][type]"}
func (b *BaseApi) CreateGroup(c *gin.Context) {
var req dto.GroupCreate
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := groupService.Create(req); err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags System Group
// @Summary Delete group
// @Accept json
// @Param request body dto.OperateByID true "request"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /agent/groups/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"groups","output_column":"name","output_value":"name"},{"input_column":"id","input_value":"id","isList":false,"db":"groups","output_column":"type","output_value":"type"}],"formatZH":"删除组 [type][name]","formatEN":"delete group [type][name]"}
func (b *BaseApi) DeleteGroup(c *gin.Context) {
var req dto.OperateByID
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := groupService.Delete(req.ID); err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags System Group
// @Summary Update group
// @Accept json
// @Param request body dto.GroupUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /agent/groups/update [post]
// @x-panel-log {"bodyKeys":["name","type"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新组 [name][type]","formatEN":"update group [name][type]"}
func (b *BaseApi) UpdateGroup(c *gin.Context) {
var req dto.GroupUpdate
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := groupService.Update(req); err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags System Group
// @Summary List groups
// @Accept json
// @Param request body dto.GroupSearch true "request"
// @Success 200 {array} dto.OperateByType
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /agent/groups/search [post]
func (b *BaseApi) ListGroup(c *gin.Context) {
var req dto.OperateByType
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
list, err := groupService.List(req)
if err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, list)
}

29
agent/app/dto/group.go Normal file
View file

@ -0,0 +1,29 @@
package dto
type GroupCreate struct {
ID uint `json:"id"`
Name string `json:"name" validate:"required"`
Type string `json:"type" validate:"required"`
}
type GroupSearch struct {
Type string `json:"type" validate:"required"`
}
type GroupUpdate struct {
ID uint `json:"id"`
Name string `json:"name"`
Type string `json:"type" validate:"required"`
IsDefault bool `json:"isDefault"`
}
type GroupInfo struct {
ID uint `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
IsDefault bool `json:"isDefault"`
}
type OperateByType struct {
Type string `json:"type"`
}

8
agent/app/model/group.go Normal file
View file

@ -0,0 +1,8 @@
package model
type Group struct {
BaseModel
IsDefault bool `json:"isDefault"`
Name string `json:"name"`
Type string `json:"type"`
}

56
agent/app/repo/group.go Normal file
View file

@ -0,0 +1,56 @@
package repo
import (
"github.com/1Panel-dev/1Panel/agent/app/model"
"github.com/1Panel-dev/1Panel/agent/global"
)
type GroupRepo struct{}
type IGroupRepo interface {
Get(opts ...DBOption) (model.Group, error)
GetList(opts ...DBOption) ([]model.Group, error)
Create(group *model.Group) error
Update(id uint, vars map[string]interface{}) error
Delete(opts ...DBOption) error
}
func NewIGroupRepo() IGroupRepo {
return &GroupRepo{}
}
func (g *GroupRepo) Get(opts ...DBOption) (model.Group, error) {
var group model.Group
db := global.DB
for _, opt := range opts {
db = opt(db)
}
err := db.First(&group).Error
return group, err
}
func (g *GroupRepo) GetList(opts ...DBOption) ([]model.Group, error) {
var groups []model.Group
db := global.DB.Model(&model.Group{})
for _, opt := range opts {
db = opt(db)
}
err := db.Find(&groups).Error
return groups, err
}
func (g *GroupRepo) Create(group *model.Group) error {
return global.DB.Create(group).Error
}
func (g *GroupRepo) Update(id uint, vars map[string]interface{}) error {
return global.DB.Model(&model.Group{}).Where("id = ?", id).Updates(vars).Error
}
func (g *GroupRepo) Delete(opts ...DBOption) error {
db := global.DB
for _, opt := range opts {
db = opt(db)
}
return db.Delete(&model.Group{}).Error
}

View file

@ -45,4 +45,6 @@ var (
favoriteRepo = repo.NewIFavoriteRepo() favoriteRepo = repo.NewIFavoriteRepo()
taskRepo = repo.NewITaskRepo() taskRepo = repo.NewITaskRepo()
groupRepo = repo.NewIGroupRepo()
) )

View file

@ -0,0 +1,87 @@
package service
import (
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/app/model"
"github.com/1Panel-dev/1Panel/agent/app/repo"
"github.com/1Panel-dev/1Panel/agent/buserr"
"github.com/jinzhu/copier"
)
type GroupService struct{}
type IGroupService interface {
List(req dto.OperateByType) ([]dto.GroupInfo, error)
Create(req dto.GroupCreate) error
Update(req dto.GroupUpdate) error
Delete(id uint) error
}
func NewIGroupService() IGroupService {
return &GroupService{}
}
func (u *GroupService) List(req dto.OperateByType) ([]dto.GroupInfo, error) {
options := []repo.DBOption{
repo.WithOrderBy("is_default desc"),
repo.WithOrderBy("created_at desc"),
}
if len(req.Type) != 0 {
options = append(options, repo.WithByType(req.Type))
}
var (
groups []model.Group
err error
)
groups, err = groupRepo.GetList(options...)
if err != nil {
return nil, buserr.New("ErrRecordNotFound")
}
var dtoUsers []dto.GroupInfo
for _, group := range groups {
var item dto.GroupInfo
if err := copier.Copy(&item, &group); err != nil {
return nil, buserr.WithDetail("ErrStructTransform", err.Error(), nil)
}
dtoUsers = append(dtoUsers, item)
}
return dtoUsers, err
}
func (u *GroupService) Create(req dto.GroupCreate) error {
group, _ := groupRepo.Get(repo.WithByName(req.Name), repo.WithByType(req.Type))
if group.ID != 0 {
return buserr.New("ErrRecordExist")
}
if err := copier.Copy(&group, &req); err != nil {
return buserr.WithDetail("ErrStructTransform", err.Error(), nil)
}
if err := groupRepo.Create(&group); err != nil {
return err
}
return nil
}
func (u *GroupService) Delete(id uint) error {
group, _ := groupRepo.Get(repo.WithByID(id))
if group.ID == 0 {
return buserr.New("ErrRecordNotFound")
}
if group.IsDefault {
return buserr.New("ErrGroupIsDefault")
}
if group.Type == "website" {
websites, _ := websiteRepo.List(websiteRepo.WithGroupID(group.ID))
if len(websites) > 0 {
return buserr.New("ErrGroupIsInWebsiteUse")
}
}
return groupRepo.Delete(repo.WithByID(id))
}
func (u *GroupService) Update(req dto.GroupUpdate) error {
upMap := make(map[string]interface{})
upMap["name"] = req.Name
upMap["is_default"] = req.IsDefault
return groupRepo.Update(req.ID, upMap)
}

View file

@ -19,6 +19,8 @@ ErrTypePort: "Port {{ .name }} format error"
Success: "Success" Success: "Success"
Failed: "Failed" Failed: "Failed"
SystemRestart: "System restart causes task interruption" SystemRestart: "System restart causes task interruption"
ErrGroupIsDefault: "Default group, cannot be deleted"
ErrGroupIsInWebsiteUse: "Group is being used by other websites, cannot be deleted"
#backup #backup
ErrBackupLocalDelete: "Deleting local server backup accounts is not currently supported." ErrBackupLocalDelete: "Deleting local server backup accounts is not currently supported."

View file

@ -28,6 +28,8 @@ ErrTypePortRange: 'ポートレンジは1-65535の間である必要がありま
Success: "成功" Success: "成功"
Failed: "失敗した" Failed: "失敗した"
SystemRestart: "システムの再起動により、タスクが中断されます" SystemRestart: "システムの再起動により、タスクが中断されます"
ErrGroupIsDefault: "デフォルトグループ、削除できません"
ErrGroupIsInWebsiteUse: "グループは他のウェブサイトで使用されています、削除できません"
#app #app
ErrPortInUsed: "{{.Detail}}ポートはすでに使用されています" ErrPortInUsed: "{{.Detail}}ポートはすでに使用されています"

View file

@ -29,6 +29,8 @@ ErrTypePortRange: '포트 범위는 1-65535 사이여야 합니다'
Success: "성공" Success: "성공"
Failed: "실패" Failed: "실패"
SystemRestart: "시스템 재시작으로 인해 작업이 중단되었습니다" SystemRestart: "시스템 재시작으로 인해 작업이 중단되었습니다"
ErrGroupIsDefault: "기본 그룹, 삭제할 수 없습니다"
ErrGroupIsInWebsiteUse: "그룹이 다른 웹사이트에서 사용 중입니다, 삭제할 수 없습니다"
# 애플리케이션 # 애플리케이션
ErrPortInUsed: "{{ .detail }} 포트가 이미 사용 중입니다" ErrPortInUsed: "{{ .detail }} 포트가 이미 사용 중입니다"

View file

@ -29,6 +29,8 @@ ErrTypePortRange: 'Julat port perlu berada di antara 1-65535'
Success: "Berjaya" Success: "Berjaya"
Failed: "Gagal" Failed: "Gagal"
SystemRestart: "Mulakan semula sistem menyebabkan gangguan tugas" SystemRestart: "Mulakan semula sistem menyebabkan gangguan tugas"
ErrGroupIsDefault: "Kumpulan lalai, tidak boleh dipadam"
ErrGroupIsInWebsiteUse: "Kumpulan sedang digunakan oleh laman web lain, tidak boleh dipadam"
#app #app
ErrPortInUsed: "Port {{ .detail }} sudah digunakan" ErrPortInUsed: "Port {{ .detail }} sudah digunakan"

View file

@ -28,6 +28,8 @@ ErrTypePortRange: 'O intervalo da porta deve estar entre 1-65535'
Success: "Sucesso" Success: "Sucesso"
Failed: "Falhou" Failed: "Falhou"
SystemRestart: "A reinicialização do sistema causa interrupção da tarefa" SystemRestart: "A reinicialização do sistema causa interrupção da tarefa"
ErrGroupIsDefault: "Grupo padrão, não pode ser excluído"
ErrGroupIsInWebsiteUse: "O grupo está sendo usado por outros sites, não pode ser excluído"
#app #app
ErrPortInUsed: "A porta {{ .detail }} já está em uso" ErrPortInUsed: "A porta {{ .detail }} já está em uso"

View file

@ -29,6 +29,8 @@ ErrTypePortRange: "Диапазон портов должен быть межд
Success: "Успех" Success: "Успех"
Failed: "Неудача" Failed: "Неудача"
SystemRestart: "Перезагрузка системы приводит к прерыванию задачи" SystemRestart: "Перезагрузка системы приводит к прерыванию задачи"
ErrGroupIsDefault: "Группа по умолчанию, невозможно удалить"
ErrGroupIsInWebsiteUse: "Группа используется другими сайтами, невозможно удалить"
#app #app
ErrPortInUsed: "Порт {{ .detail }} уже используется" ErrPortInUsed: "Порт {{ .detail }} уже используется"

View file

@ -24,6 +24,8 @@ Success: "成功"
Failed: "失敗" Failed: "失敗"
SystemRestart: "系統重啟導致任務中斷" SystemRestart: "系統重啟導致任務中斷"
ErrInvalidChar: "禁止使用非法字元" ErrInvalidChar: "禁止使用非法字元"
ErrGroupIsDefault: "預設分組,無法刪除"
ErrGroupIsInWebsiteUse: "分組正在被其他網站使用,無法刪除"
#backup #backup
ErrBackupLocalDelete: "暫不支持刪除本地伺服器備份帳號" ErrBackupLocalDelete: "暫不支持刪除本地伺服器備份帳號"

View file

@ -30,6 +30,8 @@ ErrTypePortRange: '端口范围需要在 1-65535 之间'
Success: "成功" Success: "成功"
Failed: "失败" Failed: "失败"
SystemRestart: "系统重启导致任务中断" SystemRestart: "系统重启导致任务中断"
ErrGroupIsDefault: "默认分组,无法删除"
ErrGroupIsInWebsiteUse: "分组正在被其他网站使用,无法删除"
#backup #backup
ErrBackupInUsed: "该备份账号已在计划任务中使用,无法删除" ErrBackupInUsed: "该备份账号已在计划任务中使用,无法删除"

View file

@ -26,6 +26,7 @@ func InitAgentDB() {
migrations.UpdateApp, migrations.UpdateApp,
migrations.AddOllamaModel, migrations.AddOllamaModel,
migrations.UpdateSettingStatus, migrations.UpdateSettingStatus,
migrations.InitDefault,
}) })
if err := m.Migrate(); err != nil { if err := m.Migrate(); err != nil {
global.LOG.Error(err) global.LOG.Error(err)

View file

@ -57,6 +57,7 @@ var AddTable = &gormigrate.Migration{
&model.WebsiteDnsAccount{}, &model.WebsiteDnsAccount{},
&model.WebsiteDomain{}, &model.WebsiteDomain{},
&model.WebsiteSSL{}, &model.WebsiteSSL{},
&model.Group{},
) )
}, },
} }
@ -285,3 +286,13 @@ var UpdateSettingStatus = &gormigrate.Migration{
return nil return nil
}, },
} }
var InitDefault = &gormigrate.Migration{
ID: "20250301-init-default",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Group{Name: "Default", Type: "website", IsDefault: true}).Error; err != nil {
return err
}
return nil
},
}

View file

@ -22,5 +22,6 @@ func commonGroups() []CommonRouter {
&ProcessRouter{}, &ProcessRouter{},
&WebsiteCARouter{}, &WebsiteCARouter{},
&AIToolsRouter{}, &AIToolsRouter{},
&GroupRouter{},
} }
} }

20
agent/router/ro_group.go Normal file
View file

@ -0,0 +1,20 @@
package router
import (
v2 "github.com/1Panel-dev/1Panel/agent/app/api/v2"
"github.com/gin-gonic/gin"
)
type GroupRouter struct {
}
func (a *GroupRouter) InitRouter(Router *gin.RouterGroup) {
groupRouter := Router.Group("groups")
baseApi := v2.ApiGroupApp.BaseApi
{
groupRouter.POST("", baseApi.CreateGroup)
groupRouter.POST("/del", baseApi.DeleteGroup)
groupRouter.POST("/update", baseApi.UpdateGroup)
groupRouter.POST("/search", baseApi.ListGroup)
}
}

View file

@ -15,7 +15,7 @@ type IGroupRepo interface {
Update(id uint, vars map[string]interface{}) error Update(id uint, vars map[string]interface{}) error
Delete(opts ...global.DBOption) error Delete(opts ...global.DBOption) error
WithByDefault(isDefalut bool) global.DBOption WithByDefault(isDefault bool) global.DBOption
CancelDefault(groupType string) error CancelDefault(groupType string) error
} }
@ -23,9 +23,9 @@ func NewIGroupRepo() IGroupRepo {
return &GroupRepo{} return &GroupRepo{}
} }
func (c *GroupRepo) WithByDefault(isDefalut bool) global.DBOption { func (c *GroupRepo) WithByDefault(isDefault bool) global.DBOption {
return func(g *gorm.DB) *gorm.DB { return func(g *gorm.DB) *gorm.DB {
return g.Where("is_default = ?", isDefalut) return g.Where("is_default = ?", isDefault)
} }
} }

View file

@ -166,20 +166,20 @@ var InitSetting = &gormigrate.Migration{
var InitHost = &gormigrate.Migration{ var InitHost = &gormigrate.Migration{
ID: "20240816-init-host", ID: "20240816-init-host",
Migrate: func(tx *gorm.DB) error { Migrate: func(tx *gorm.DB) error {
hostGroup := &model.Group{Name: "default", Type: "host", IsDefault: true} hostGroup := &model.Group{Name: "Default", Type: "host", IsDefault: true}
if err := tx.Create(hostGroup).Error; err != nil { if err := tx.Create(hostGroup).Error; err != nil {
return err return err
} }
if err := tx.Create(&model.Group{Name: "default", Type: "node", IsDefault: true}).Error; err != nil { if err := tx.Create(&model.Group{Name: "Default", Type: "node", IsDefault: true}).Error; err != nil {
return err return err
} }
if err := tx.Create(&model.Group{Name: "default", Type: "command", IsDefault: true}).Error; err != nil { if err := tx.Create(&model.Group{Name: "Default", Type: "command", IsDefault: true}).Error; err != nil {
return err return err
} }
if err := tx.Create(&model.Group{Name: "default", Type: "website", IsDefault: true}).Error; err != nil { if err := tx.Create(&model.Group{Name: "Default", Type: "website", IsDefault: true}).Error; err != nil {
return err return err
} }
if err := tx.Create(&model.Group{Name: "default", Type: "redis", IsDefault: true}).Error; err != nil { if err := tx.Create(&model.Group{Name: "Default", Type: "redis", IsDefault: true}).Error; err != nil {
return err return err
} }
host := model.Host{ host := model.Host{

View file

@ -13,3 +13,16 @@ export const updateGroup = (params: Group.GroupUpdate) => {
export const deleteGroup = (id: number) => { export const deleteGroup = (id: number) => {
return http.post(`/core/groups/del`, { id: id }); return http.post(`/core/groups/del`, { id: id });
}; };
export const getAgentGroupList = (type: string) => {
return http.post<Array<Group.GroupInfo>>(`/groups/search`, { type: type });
};
export const createAgentGroup = (params: Group.GroupCreate) => {
return http.post<Group.GroupCreate>(`/groups`, params);
};
export const updateAgentGroup = (params: Group.GroupUpdate) => {
return http.post(`/groups/update`, params);
};
export const deleteAgentGroup = (id: number) => {
return http.post(`/groups/del`, { id: id });
};

View file

@ -0,0 +1,83 @@
<template>
<div v-loading="loading">
<DrawerPro v-model="drawerVisible" :header="$t('terminal.groupChange')" :back="handleClose" size="small">
<el-form @submit.prevent ref="hostInfoRef" label-position="top" :model="dialogData" :rules="rules">
<el-form-item :label="$t('commons.table.group')" prop="group">
<el-select filterable v-model="dialogData.groupID" clearable style="width: 100%">
<div v-for="item in groupList" :key="item.id">
<el-option :label="item.name" :value="item.id" />
</div>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button>
<el-button type="primary" @click="onSubmit(hostInfoRef)">
{{ $t('commons.button.confirm') }}
</el-button>
</template>
</DrawerPro>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive } from 'vue';
import type { ElForm } from 'element-plus';
import { Rules } from '@/global/form-rules';
import { getGroupList } from '@/api/modules/group';
const loading = ref();
interface DialogProps {
group: string;
groupType: string;
}
const drawerVisible = ref(false);
const dialogData = ref({
groupID: 0,
groupType: '',
});
const groupList = ref();
const acceptParams = (params: DialogProps): void => {
dialogData.value.groupType = params.groupType;
loadGroups(params.group);
drawerVisible.value = true;
};
const emit = defineEmits(['search', 'change']);
const handleClose = () => {
drawerVisible.value = false;
};
type FormInstance = InstanceType<typeof ElForm>;
const hostInfoRef = ref<FormInstance>();
const rules = reactive({
groupID: [Rules.requiredSelect],
});
const loadGroups = async (groupName: string) => {
const res = await getGroupList(dialogData.value.groupType);
groupList.value = res.data;
for (const group of groupList.value) {
if (group.name === groupName) {
dialogData.value.groupID = group.id;
break;
}
}
};
const onSubmit = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
loading.value = true;
emit('change', Number(dialogData.value.groupID));
loading.value = false;
drawerVisible.value = false;
});
};
defineExpose({
acceptParams,
});
</script>

View file

@ -0,0 +1,179 @@
<template>
<DrawerPro v-model="open" :header="$t('commons.table.group')" @close="handleClose" size="large" :back="handleClose">
<template #content>
<ComplexTable :data="data" @search="search()">
<template #toolbar>
<el-button type="primary" @click="openCreate">{{ $t('website.createGroup') }}</el-button>
</template>
<el-table-column :label="$t('commons.table.name')" prop="name">
<template #default="{ row }">
<div v-if="!row.edit">
<span v-if="row.name === 'default'">
{{ $t('commons.table.default') }}
</span>
<span v-if="row.name !== 'default'">{{ row.name }}</span>
<el-tag v-if="row.isDefault" type="success" class="ml-2" size="small">
({{ $t('commons.table.default') }})
</el-tag>
<el-tag type="warning" size="small" class="ml-4" v-if="row.isDelete">
{{ $t('app.takeDown') }}
</el-tag>
</div>
<el-form @submit.prevent ref="groupForm" v-if="row.edit" :model="row">
<el-form-item prop="name" v-if="row.edit" :rules="Rules.name">
<div style="margin-top: 20px; width: 100%"><el-input v-model="row.name" /></div>
</el-form-item>
</el-form>
</template>
</el-table-column>
<el-table-column :label="$t('commons.table.operate')">
<template #default="{ row, $index }">
<div>
<el-button link v-if="row.edit" type="primary" @click="saveGroup(groupForm, row)">
{{ $t('commons.button.save') }}
</el-button>
<el-button link v-if="!row.edit" type="primary" @click="editGroup($index)">
{{ $t('commons.button.edit') }}
</el-button>
<el-button
link
v-if="!row.edit"
:disabled="row.isDefault"
type="primary"
@click="removeGroup($index)"
>
{{ $t('commons.button.delete') }}
</el-button>
<el-button link v-if="row.edit" type="primary" @click="search()">
{{ $t('commons.button.cancel') }}
</el-button>
<el-button
link
v-if="!row.edit && !row.isDefault && !row.isDelete"
type="primary"
@click="setDefault(row)"
>
{{ $t('website.setDefault') }}
</el-button>
</div>
</template>
</el-table-column>
</ComplexTable>
</template>
</DrawerPro>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import i18n from '@/lang';
import { createAgentGroup, deleteAgentGroup, getAgentGroupList, updateAgentGroup } from '@/api/modules/group';
import { MsgSuccess } from '@/utils/message';
import { Group } from '@/api/interface/group';
import { Rules } from '@/global/form-rules';
import { FormInstance } from 'element-plus';
const open = ref(false);
const type = ref();
const data = ref();
const handleClose = () => {
open.value = false;
data.value = [];
emit('search');
};
interface DialogProps {
type: string;
}
const groupForm = ref<FormInstance>();
const acceptParams = (params: DialogProps): void => {
type.value = params.type;
open.value = true;
search();
};
const emit = defineEmits<{ (e: 'search'): void }>();
const search = () => {
getAgentGroupList(type.value).then((res) => {
data.value = res.data || [];
});
};
const saveGroup = async (formEl: FormInstance, group: Group.GroupInfo) => {
if (!formEl) return;
await formEl.validate((valid) => {
if (!valid) {
return;
}
group.type = type.value;
if (group.id == 0) {
createAgentGroup(group).then(() => {
MsgSuccess(i18n.global.t('commons.msg.createSuccess'));
search();
});
} else {
updateAgentGroup(group).then(() => {
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
search();
});
}
});
};
const setDefault = (group: Group.GroupInfo) => {
group.isDefault = true;
group.type = type.value;
updateAgentGroup(group).then(() => {
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
search();
});
};
const openCreate = () => {
for (const d of data.value) {
if (d.name == '') {
return;
}
if (d.edit) {
d.edit = false;
}
}
const g = {
id: 0,
name: '',
isDefault: false,
edit: true,
status: 'Enable',
};
data.value.unshift(g);
};
const removeGroup = (index: number) => {
const group = data.value[index];
if (group.id > 0) {
deleteAgentGroup(group.id).then(() => {
data.value.splice(index, 1);
MsgSuccess(i18n.global.t('commons.msg.deleteSuccess'));
});
} else {
data.value.splice(index, 1);
}
};
const editGroup = (index: number) => {
for (const i in data.value) {
const d = data.value[i];
if (d.name == '') {
data.value.splice(Number(i), 1);
}
if (d.edit) {
d.edit = false;
}
}
data.value[index].edit = true;
};
defineExpose({ acceptParams });
</script>

View file

@ -42,6 +42,9 @@ router.beforeEach((to, from, next) => {
if (to.path === '/apps/all' && to.query.install != undefined) { if (to.path === '/apps/all' && to.query.install != undefined) {
return next(); return next();
} }
// if (to.query.uncached != undefined) {
// return next();
// }
const activeMenuKey = 'cachedRoute' + (to.meta.activeMenu || ''); const activeMenuKey = 'cachedRoute' + (to.meta.activeMenu || '');
const cachedRoute = localStorage.getItem(activeMenuKey); const cachedRoute = localStorage.getItem(activeMenuKey);

View file

@ -41,7 +41,7 @@ import { computed, onMounted, reactive, ref } from 'vue';
import { FormInstance } from 'element-plus'; import { FormInstance } from 'element-plus';
import i18n from '@/lang'; import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message'; import { MsgSuccess } from '@/utils/message';
import { getGroupList } from '@/api/modules/group'; import { getAgentGroupList } from '@/api/modules/group';
import { Group } from '@/api/interface/group'; import { Group } from '@/api/interface/group';
const websiteForm = ref<FormInstance>(); const websiteForm = ref<FormInstance>();
@ -87,7 +87,7 @@ const submit = async (formEl: FormInstance | undefined) => {
}); });
}; };
const search = async () => { const search = async () => {
const res = await getGroupList('website'); const res = await getAgentGroupList('website');
groups.value = res.data; groups.value = res.data;
getWebsite(websiteId.value).then((res) => { getWebsite(websiteId.value).then((res) => {

View file

@ -245,7 +245,7 @@ import DefaultHtml from '@/views/website/website/html/index.vue';
import CreateWebSite from '@/views/website/website/create/index.vue'; import CreateWebSite from '@/views/website/website/create/index.vue';
import DeleteWebsite from '@/views/website/website/delete/index.vue'; import DeleteWebsite from '@/views/website/website/delete/index.vue';
import NginxConfig from '@/views/website/website/nginx/index.vue'; import NginxConfig from '@/views/website/website/nginx/index.vue';
import GroupDialog from '@/components/group/index.vue'; import GroupDialog from '@/components/agent-group/index.vue';
import AppStatus from '@/components/app-status/index.vue'; import AppStatus from '@/components/app-status/index.vue';
import i18n from '@/lang'; import i18n from '@/lang';
import router from '@/routers'; import router from '@/routers';
@ -257,7 +257,7 @@ import { ElMessageBox } from 'element-plus';
import { dateFormatSimple } from '@/utils/util'; import { dateFormatSimple } from '@/utils/util';
import { MsgSuccess } from '@/utils/message'; import { MsgSuccess } from '@/utils/message';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { getGroupList } from '@/api/modules/group'; import { getAgentGroupList } from '@/api/modules/group';
import { Group } from '@/api/interface/group'; import { Group } from '@/api/interface/group';
import { GlobalStore } from '@/store'; import { GlobalStore } from '@/store';
const globalStore = GlobalStore(); const globalStore = GlobalStore();
@ -359,7 +359,7 @@ const search = async () => {
}; };
const listGroup = async () => { const listGroup = async () => {
const res = await getGroupList('website'); const res = await getAgentGroupList('website');
groups.value = res.data; groups.value = res.data;
}; };