feat: 增加网站分组管理

pull/35/head
zhengkunwang223 2022-11-02 18:18:20 +08:00 committed by zhengkunwang223
parent 9621d6ea1f
commit 42134e315b
9 changed files with 198 additions and 22 deletions

View File

@ -5,10 +5,10 @@ import (
"github.com/1Panel-dev/1Panel/backend/app/dto" "github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/constant" "github.com/1Panel-dev/1Panel/backend/constant"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"strconv"
) )
func (b *BaseApi) GetWebGroups(c *gin.Context) { func (b *BaseApi) GetWebGroups(c *gin.Context) {
list, err := websiteGroupService.GetGroups() list, err := websiteGroupService.GetGroups()
if err != nil { if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) 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) { func (b *BaseApi) CreateWebGroup(c *gin.Context) {
var req dto.WebSiteGroupCreate var req dto.WebSiteGroupCreate
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return return
} }
if err := websiteGroupService.CreateGroup(req); err != nil { if err := websiteGroupService.CreateGroup(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return return
} }
helper.SuccessWithData(c, nil) 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)
}

View File

@ -16,6 +16,8 @@ func (a *WebsiteGroupRouter) InitWebsiteGroupRouter(Router *gin.RouterGroup) {
baseApi := v1.ApiGroupApp.BaseApi baseApi := v1.ApiGroupApp.BaseApi
{ {
groupRouter.GET("", baseApi.GetWebGroups) groupRouter.GET("", baseApi.GetWebGroups)
//groupRouter.GET("", baseApi.GetGroups) groupRouter.POST("", baseApi.CreateWebGroup)
groupRouter.PUT("", baseApi.UpdateWebGroup)
groupRouter.DELETE("/:groupId", baseApi.DeleteWebGroup)
} }
} }

View File

@ -46,4 +46,9 @@ export namespace WebSite {
name: string; name: string;
default: boolean; default: boolean;
} }
export interface GroupOp {
name: string;
id?: number;
}
} }

View File

@ -6,10 +6,6 @@ export const SearchWebSites = (req: WebSite.WebSiteSearch) => {
return http.post<ResPage<WebSite.WebSite>>(`/websites/search`, req); 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) => { export const CreateWebsite = (req: WebSite.WebSiteCreateReq) => {
return http.post<any>(`/websites`, req); return http.post<any>(`/websites`, req);
}; };
@ -17,3 +13,19 @@ export const CreateWebsite = (req: WebSite.WebSiteCreateReq) => {
export const DeleteWebsite = (req: WebSite.WebSiteDel) => { export const DeleteWebsite = (req: WebSite.WebSiteDel) => {
return http.post<any>(`/websites/del`, req); 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}`);
};

View File

@ -44,6 +44,7 @@ const checkName = (rule: any, value: any, callback: any) => {
interface CommonRule { interface CommonRule {
requiredInput: FormItemRule; requiredInput: FormItemRule;
requiredSelect: FormItemRule; requiredSelect: FormItemRule;
requiredSelectBusiness: FormItemRule;
name: FormItemRule; name: FormItemRule;
password: FormItemRule; password: FormItemRule;
email: FormItemRule; email: FormItemRule;
@ -63,6 +64,14 @@ export const Rules: CommonRule = {
message: i18n.global.t('commons.rule.requiredSelect'), message: i18n.global.t('commons.rule.requiredSelect'),
trigger: 'change', trigger: 'change',
}, },
requiredSelectBusiness: {
required: true,
min: 1,
max: 65535,
type: 'number',
message: i18n.global.t('commons.rule.requiredSelect'),
trigger: 'change',
},
name: { name: {
required: true, required: true,
validator: checkName, validator: checkName,

View File

@ -673,12 +673,14 @@ export default {
alias: '', alias: '',
remark: '', remark: '',
group: '', group: '',
groupSetting: '',
app: '', app: '',
app_new: '', appNew: '',
app_installed: '', appInstalled: '',
create: '', create: '',
delete: '', delete: '',
deleteApp: '', deleteApp: '',
deleteBackup: '', deleteBackup: '',
domain: '',
}, },
}; };

View File

@ -21,16 +21,16 @@
<el-form-item prop="appType"> <el-form-item prop="appType">
<el-radio-group v-model="website.appType" @change="changeAppType(website.appType)"> <el-radio-group v-model="website.appType" @change="changeAppType(website.appType)">
<el-radio :label="'installed'" :value="'installed'"> <el-radio :label="'installed'" :value="'installed'">
{{ $t('website.app_installed') }} {{ $t('website.appInstalled') }}
</el-radio> </el-radio>
<el-radio :label="'new'"> <el-radio :label="'new'">
{{ $t('website.app_new') }} {{ $t('website.appNew') }}
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
v-if="website.appType == 'installed'" v-if="website.appType == 'installed'"
:label="$t('website.app_installed')" :label="$t('website.appInstalled')"
prop="appInstallID" prop="appInstallID"
> >
<el-select v-model="website.appInstallID"> <el-select v-model="website.appInstallID">
@ -125,13 +125,13 @@ const website = ref({
remark: '', remark: '',
domains: [], domains: [],
appType: 'installed', appType: 'installed',
appInstallID: null, appInstallID: 0,
webSiteGroupID: 1, webSiteGroupID: 1,
otherDomains: '', otherDomains: '',
appinstall: { appinstall: {
appID: null, appID: 0,
name: '', name: '',
appDetailID: null, appDetailID: 0,
params: {}, params: {},
version: '', version: '',
}, },
@ -140,12 +140,12 @@ let rules = ref({
primaryDomain: [Rules.requiredInput], primaryDomain: [Rules.requiredInput],
alias: [Rules.requiredInput], alias: [Rules.requiredInput],
type: [Rules.requiredInput], type: [Rules.requiredInput],
webSiteGroupID: [Rules.requiredInput], webSiteGroupID: [Rules.requiredSelectBusiness],
appInstallID: [Rules.requiredInput], appInstallID: [Rules.requiredSelectBusiness],
appType: [Rules.requiredInput], appType: [Rules.requiredInput],
appinstall: { appinstall: {
name: [Rules.requiredInput], name: [Rules.requiredInput],
appID: [Rules.requiredInput], appID: [Rules.requiredSelectBusiness],
params: {}, params: {},
}, },
}); });

View File

@ -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>

View File

@ -2,7 +2,8 @@
<LayoutContent :header="'网站'"> <LayoutContent :header="'网站'">
<ComplexTable :data="data" @search="search()"> <ComplexTable :data="data" @search="search()">
<template #toolbar> <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>
<el-button type="primary" plain>{{ '默认站点' }}</el-button> <el-button type="primary" plain>{{ '默认站点' }}</el-button>
</template> </template>
@ -25,6 +26,7 @@
</ComplexTable> </ComplexTable>
<CreateWebSite ref="createRef" @close="search"></CreateWebSite> <CreateWebSite ref="createRef" @close="search"></CreateWebSite>
<DeleteWebsite ref="deleteRef" @close="search"></DeleteWebsite> <DeleteWebsite ref="deleteRef" @close="search"></DeleteWebsite>
<WebSiteGroup ref="groupRef"></WebSiteGroup>
</LayoutContent> </LayoutContent>
</template> </template>
@ -32,15 +34,18 @@
import LayoutContent from '@/layout/layout-content.vue'; import LayoutContent from '@/layout/layout-content.vue';
import ComplexTable from '@/components/complex-table/index.vue'; import ComplexTable from '@/components/complex-table/index.vue';
import { onMounted, reactive, ref } from '@vue/runtime-core'; import { onMounted, reactive, ref } from '@vue/runtime-core';
import router from '@/routers';
import CreateWebSite from './create/index.vue'; import CreateWebSite from './create/index.vue';
import DeleteWebsite from './delete/index.vue'; import DeleteWebsite from './delete/index.vue';
import WebSiteGroup from './group/index.vue';
import { SearchWebSites } from '@/api/modules/website'; import { SearchWebSites } from '@/api/modules/website';
import i18n from '@/lang';
import { WebSite } from '@/api/interface/website'; import { WebSite } from '@/api/interface/website';
import i18n from '@/lang';
import router from '@/routers';
const createRef = ref(); const createRef = ref();
const deleteRef = ref(); const deleteRef = ref();
const groupRef = ref();
const paginationConfig = reactive({ const paginationConfig = reactive({
currentPage: 1, currentPage: 1,
@ -86,6 +91,10 @@ const openCreate = () => {
createRef.value.acceptParams(); createRef.value.acceptParams();
}; };
const openGroup = () => {
groupRef.value.acceptParams();
};
onMounted(() => { onMounted(() => {
search(); search();
}); });