mirror of https://github.com/1Panel-dev/1Panel
feat: 增加网站分组管理
parent
9621d6ea1f
commit
42134e315b
|
@ -5,10 +5,10 @@ import (
|
|||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (b *BaseApi) GetWebGroups(c *gin.Context) {
|
||||
|
||||
list, err := websiteGroupService.GetGroups()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
|
@ -18,16 +18,46 @@ func (b *BaseApi) GetWebGroups(c *gin.Context) {
|
|||
}
|
||||
|
||||
func (b *BaseApi) CreateWebGroup(c *gin.Context) {
|
||||
|
||||
var req dto.WebSiteGroupCreate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := websiteGroupService.CreateGroup(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
func (b *BaseApi) UpdateWebGroup(c *gin.Context) {
|
||||
var req dto.WebSiteGroupUpdate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := websiteGroupService.UpdateGroup(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
func (b *BaseApi) DeleteWebGroup(c *gin.Context) {
|
||||
|
||||
groupId := c.Param("groupId")
|
||||
if groupId == "" {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, nil)
|
||||
return
|
||||
}
|
||||
id, err := strconv.Atoi(groupId)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
if err := websiteGroupService.DeleteGroup(uint(id)); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ func (a *WebsiteGroupRouter) InitWebsiteGroupRouter(Router *gin.RouterGroup) {
|
|||
baseApi := v1.ApiGroupApp.BaseApi
|
||||
{
|
||||
groupRouter.GET("", baseApi.GetWebGroups)
|
||||
//groupRouter.GET("", baseApi.GetGroups)
|
||||
groupRouter.POST("", baseApi.CreateWebGroup)
|
||||
groupRouter.PUT("", baseApi.UpdateWebGroup)
|
||||
groupRouter.DELETE("/:groupId", baseApi.DeleteWebGroup)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,4 +46,9 @@ export namespace WebSite {
|
|||
name: string;
|
||||
default: boolean;
|
||||
}
|
||||
|
||||
export interface GroupOp {
|
||||
name: string;
|
||||
id?: number;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,6 @@ export const SearchWebSites = (req: WebSite.WebSiteSearch) => {
|
|||
return http.post<ResPage<WebSite.WebSite>>(`/websites/search`, req);
|
||||
};
|
||||
|
||||
export const ListGroups = () => {
|
||||
return http.get<WebSite.Group[]>(`/websites/groups`);
|
||||
};
|
||||
|
||||
export const CreateWebsite = (req: WebSite.WebSiteCreateReq) => {
|
||||
return http.post<any>(`/websites`, req);
|
||||
};
|
||||
|
@ -17,3 +13,19 @@ export const CreateWebsite = (req: WebSite.WebSiteCreateReq) => {
|
|||
export const DeleteWebsite = (req: WebSite.WebSiteDel) => {
|
||||
return http.post<any>(`/websites/del`, req);
|
||||
};
|
||||
|
||||
export const ListGroups = () => {
|
||||
return http.get<WebSite.Group[]>(`/websites/groups`);
|
||||
};
|
||||
|
||||
export const CreateGroup = (req: WebSite.GroupOp) => {
|
||||
return http.post<any>(`/websites/groups`, req);
|
||||
};
|
||||
|
||||
export const UpdateGroup = (req: WebSite.GroupOp) => {
|
||||
return http.put<any>(`/websites/groups`, req);
|
||||
};
|
||||
|
||||
export const DeleteGroup = (id: number) => {
|
||||
return http.delete<any>(`/websites/groups/${id}`);
|
||||
};
|
||||
|
|
|
@ -44,6 +44,7 @@ const checkName = (rule: any, value: any, callback: any) => {
|
|||
interface CommonRule {
|
||||
requiredInput: FormItemRule;
|
||||
requiredSelect: FormItemRule;
|
||||
requiredSelectBusiness: FormItemRule;
|
||||
name: FormItemRule;
|
||||
password: FormItemRule;
|
||||
email: FormItemRule;
|
||||
|
@ -63,6 +64,14 @@ export const Rules: CommonRule = {
|
|||
message: i18n.global.t('commons.rule.requiredSelect'),
|
||||
trigger: 'change',
|
||||
},
|
||||
requiredSelectBusiness: {
|
||||
required: true,
|
||||
min: 1,
|
||||
max: 65535,
|
||||
type: 'number',
|
||||
message: i18n.global.t('commons.rule.requiredSelect'),
|
||||
trigger: 'change',
|
||||
},
|
||||
name: {
|
||||
required: true,
|
||||
validator: checkName,
|
||||
|
|
|
@ -673,12 +673,14 @@ export default {
|
|||
alias: '代号',
|
||||
remark: '备注',
|
||||
group: '分组',
|
||||
groupSetting: '分组管理',
|
||||
app: '应用',
|
||||
app_new: '新装应用',
|
||||
app_installed: '已装应用',
|
||||
appNew: '新装应用',
|
||||
appInstalled: '已装应用',
|
||||
create: '创建网站',
|
||||
delete: '删除网站',
|
||||
deleteApp: '删除应用',
|
||||
deleteBackup: '删除备份',
|
||||
domain: '域名',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -21,16 +21,16 @@
|
|||
<el-form-item prop="appType">
|
||||
<el-radio-group v-model="website.appType" @change="changeAppType(website.appType)">
|
||||
<el-radio :label="'installed'" :value="'installed'">
|
||||
{{ $t('website.app_installed') }}
|
||||
{{ $t('website.appInstalled') }}
|
||||
</el-radio>
|
||||
<el-radio :label="'new'">
|
||||
{{ $t('website.app_new') }}
|
||||
{{ $t('website.appNew') }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="website.appType == 'installed'"
|
||||
:label="$t('website.app_installed')"
|
||||
:label="$t('website.appInstalled')"
|
||||
prop="appInstallID"
|
||||
>
|
||||
<el-select v-model="website.appInstallID">
|
||||
|
@ -125,13 +125,13 @@ const website = ref({
|
|||
remark: '',
|
||||
domains: [],
|
||||
appType: 'installed',
|
||||
appInstallID: null,
|
||||
appInstallID: 0,
|
||||
webSiteGroupID: 1,
|
||||
otherDomains: '',
|
||||
appinstall: {
|
||||
appID: null,
|
||||
appID: 0,
|
||||
name: '',
|
||||
appDetailID: null,
|
||||
appDetailID: 0,
|
||||
params: {},
|
||||
version: '',
|
||||
},
|
||||
|
@ -140,12 +140,12 @@ let rules = ref({
|
|||
primaryDomain: [Rules.requiredInput],
|
||||
alias: [Rules.requiredInput],
|
||||
type: [Rules.requiredInput],
|
||||
webSiteGroupID: [Rules.requiredInput],
|
||||
appInstallID: [Rules.requiredInput],
|
||||
webSiteGroupID: [Rules.requiredSelectBusiness],
|
||||
appInstallID: [Rules.requiredSelectBusiness],
|
||||
appType: [Rules.requiredInput],
|
||||
appinstall: {
|
||||
name: [Rules.requiredInput],
|
||||
appID: [Rules.requiredInput],
|
||||
appID: [Rules.requiredSelectBusiness],
|
||||
params: {},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
<template>
|
||||
<el-dialog v-model="open" :title="$t('website.groupSetting')" width="40%" :before-close="handleClose">
|
||||
<ComplexTable :data="data" @search="search()">
|
||||
<template #toolbar>
|
||||
<el-button type="primary" plain @click="openCreate">{{ $t('commons.button.create') }}</el-button>
|
||||
</template>
|
||||
<el-table-column :label="$t('commons.table.name')" prop="name">
|
||||
<template #default="{ row }">
|
||||
<span v-if="!row.edit" @click="row.edit = true">{{ row.name }}</span>
|
||||
<el-input v-if="row.edit" v-model="row.name" @blur="row.edit = false"></el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('commons.table.operate')">
|
||||
<template #default="{ row, $index }">
|
||||
<el-button link :disabled="row.default" type="primary" @click="saveGroup(row)">
|
||||
{{ $t('commons.button.save') }}
|
||||
</el-button>
|
||||
<el-button link :disabled="row.default" type="primary" @click="deleteGroup($index)">
|
||||
{{ $t('commons.button.delete') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ComplexTable>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import i18n from '@/lang';
|
||||
import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import { ListGroups, CreateGroup, DeleteGroup, UpdateGroup } from '@/api/modules/website';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
interface groupData {
|
||||
id: number;
|
||||
name: string;
|
||||
edit: boolean;
|
||||
default: boolean;
|
||||
}
|
||||
|
||||
let open = ref(false);
|
||||
let data = ref<groupData[]>([]);
|
||||
|
||||
const handleClose = () => {
|
||||
open.value = false;
|
||||
data.value = [];
|
||||
};
|
||||
|
||||
const search = () => {
|
||||
ListGroups().then((res) => {
|
||||
for (const d of res.data) {
|
||||
const g = {
|
||||
id: d.id,
|
||||
name: d.name,
|
||||
default: d.default,
|
||||
edit: false,
|
||||
};
|
||||
data.value.push(g);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const saveGroup = (create: groupData) => {
|
||||
const group = {
|
||||
name: create.name,
|
||||
id: create.id,
|
||||
};
|
||||
if (create.id == 0) {
|
||||
CreateGroup(group).then(() => {
|
||||
ElMessage.success(i18n.global.t('commons.msg.createSuccess'));
|
||||
});
|
||||
} else {
|
||||
UpdateGroup(group).then(() => {
|
||||
ElMessage.success(i18n.global.t('commons.msg.updateSuccess'));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const acceptParams = async () => {
|
||||
open.value = true;
|
||||
search();
|
||||
};
|
||||
|
||||
const openCreate = () => {
|
||||
const g = {
|
||||
id: 0,
|
||||
name: '',
|
||||
default: false,
|
||||
edit: true,
|
||||
};
|
||||
data.value.push(g);
|
||||
};
|
||||
|
||||
const deleteGroup = (index: number) => {
|
||||
const group = data.value[index];
|
||||
|
||||
if (group.id > 0) {
|
||||
DeleteGroup(group.id).then(() => {
|
||||
data.value.splice(index, 1);
|
||||
ElMessage.success(i18n.global.t('commons.msg.deleteSuccess'));
|
||||
});
|
||||
} else {
|
||||
data.value.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({ acceptParams });
|
||||
</script>
|
|
@ -2,7 +2,8 @@
|
|||
<LayoutContent :header="'网站'">
|
||||
<ComplexTable :data="data" @search="search()">
|
||||
<template #toolbar>
|
||||
<el-button type="primary" plain @click="openCreate">{{ '新建网站' }}</el-button>
|
||||
<el-button type="primary" plain @click="openCreate">{{ $t('commons.button.create') }}</el-button>
|
||||
<el-button type="primary" plain @click="openGroup">{{ $t('website.group') }}</el-button>
|
||||
<el-button type="primary" plain>{{ '修改默认页' }}</el-button>
|
||||
<el-button type="primary" plain>{{ '默认站点' }}</el-button>
|
||||
</template>
|
||||
|
@ -25,6 +26,7 @@
|
|||
</ComplexTable>
|
||||
<CreateWebSite ref="createRef" @close="search"></CreateWebSite>
|
||||
<DeleteWebsite ref="deleteRef" @close="search"></DeleteWebsite>
|
||||
<WebSiteGroup ref="groupRef"></WebSiteGroup>
|
||||
</LayoutContent>
|
||||
</template>
|
||||
|
||||
|
@ -32,15 +34,18 @@
|
|||
import LayoutContent from '@/layout/layout-content.vue';
|
||||
import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import { onMounted, reactive, ref } from '@vue/runtime-core';
|
||||
import router from '@/routers';
|
||||
import CreateWebSite from './create/index.vue';
|
||||
import DeleteWebsite from './delete/index.vue';
|
||||
import WebSiteGroup from './group/index.vue';
|
||||
import { SearchWebSites } from '@/api/modules/website';
|
||||
import i18n from '@/lang';
|
||||
import { WebSite } from '@/api/interface/website';
|
||||
|
||||
import i18n from '@/lang';
|
||||
import router from '@/routers';
|
||||
|
||||
const createRef = ref();
|
||||
const deleteRef = ref();
|
||||
const groupRef = ref();
|
||||
|
||||
const paginationConfig = reactive({
|
||||
currentPage: 1,
|
||||
|
@ -86,6 +91,10 @@ const openCreate = () => {
|
|||
createRef.value.acceptParams();
|
||||
};
|
||||
|
||||
const openGroup = () => {
|
||||
groupRef.value.acceptParams();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
search();
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue