mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-22 16:00:51 +00:00
feat: support bach set website group (#10754)
This commit is contained in:
@@ -1162,6 +1162,26 @@ func (b *BaseApi) BatchOpWebsites(c *gin.Context) {
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Batch set website group
|
||||
// @Accept json
|
||||
// @Param request body request.BatchSetGroupReq true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /websites/batch/group [post]
|
||||
func (b *BaseApi) BatchSetWebsiteGroup(c *gin.Context) {
|
||||
var req request.BatchWebsiteGroup
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := websiteService.BatchSetGroup(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags Website
|
||||
// @Summary Get CORS Config
|
||||
// @Accept json
|
||||
|
||||
@@ -109,6 +109,11 @@ type BatchWebsiteOp struct {
|
||||
TaskID string `json:"taskID" validate:"required"`
|
||||
}
|
||||
|
||||
type BatchWebsiteGroup struct {
|
||||
IDs []uint `json:"ids" validate:"required"`
|
||||
GroupID uint `json:"groupID" validate:"required"`
|
||||
}
|
||||
|
||||
type WebsiteRedirectUpdate struct {
|
||||
WebsiteID uint `json:"websiteId" validate:"required"`
|
||||
Key string `json:"key" validate:"required"`
|
||||
|
||||
@@ -61,6 +61,7 @@ type IWebsiteService interface {
|
||||
DeleteWebsite(req request.WebsiteDelete) error
|
||||
GetWebsite(id uint) (response.WebsiteDTO, error)
|
||||
BatchOpWebsite(req request.BatchWebsiteOp) error
|
||||
BatchSetGroup(req request.BatchWebsiteGroup) error
|
||||
|
||||
CreateWebsiteDomain(create request.WebsiteDomainCreate) ([]model.WebsiteDomain, error)
|
||||
GetWebsiteDomain(websiteId uint) ([]model.WebsiteDomain, error)
|
||||
@@ -521,6 +522,17 @@ func (w WebsiteService) OpWebsite(req request.WebsiteOp) error {
|
||||
return websiteRepo.Save(context.Background(), &website)
|
||||
}
|
||||
|
||||
func (w WebsiteService) BatchSetGroup(req request.BatchWebsiteGroup) error {
|
||||
websites, _ := websiteRepo.List(repo.WithByIDs(req.IDs))
|
||||
for _, web := range websites {
|
||||
web.WebsiteGroupID = req.GroupID
|
||||
if err := websiteRepo.Save(context.Background(), &web); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w WebsiteService) BatchOpWebsite(req request.BatchWebsiteOp) error {
|
||||
websites, _ := websiteRepo.List(repo.WithByIDs(req.IDs))
|
||||
opTask, err := task.NewTaskWithOps(i18n.GetMsgByKey("Status"), task.TaskBatch, task.TaskScopeWebsite, req.TaskID, 0)
|
||||
|
||||
@@ -26,6 +26,7 @@ func (a *WebsiteRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
websiteRouter.POST("/default/server", baseApi.ChangeDefaultServer)
|
||||
websiteRouter.POST("/group/change", baseApi.ChangeWebsiteGroup)
|
||||
websiteRouter.POST("/batch/operate", baseApi.BatchOpWebsites)
|
||||
websiteRouter.POST("/batch/group", baseApi.BatchSetWebsiteGroup)
|
||||
|
||||
websiteRouter.GET("/domains/:websiteId", baseApi.GetWebDomains)
|
||||
websiteRouter.POST("/domains/del", baseApi.DeleteWebDomain)
|
||||
|
||||
@@ -694,4 +694,9 @@ export namespace Website {
|
||||
export interface CorsConfigReq extends CorsConfig {
|
||||
websiteID: number;
|
||||
}
|
||||
|
||||
export interface BatchSetGroup {
|
||||
ids: number[];
|
||||
groupID: number;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,3 +367,7 @@ export const getCorsConfig = (id: number) => {
|
||||
export const updateCorsConfig = (req: Website.CorsConfigReq) => {
|
||||
return http.post(`/websites/cors/update`, req);
|
||||
};
|
||||
|
||||
export const batchSetGroup = (req: Website.BatchSetGroup) => {
|
||||
return http.post(`/websites/batch/group`, req);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<DrawerPro v-model="open" :header="$t('commons.table.group')" size="30%" @close="handleClose">
|
||||
<el-form ref="websiteForm" label-position="top" :model="form" :rules="rules" v-loading="loading">
|
||||
<GroupSelect v-model="form.groupID" :prop="'groupID'" :groupType="'website'"></GroupSelect>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submit()" :disabled="loading">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</DrawerPro>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import GroupSelect from '@/views/website/website/components/group/index.vue';
|
||||
|
||||
import { batchSetGroup } from '@/api/modules/website';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { FormInstance } from 'element-plus';
|
||||
|
||||
const open = ref(false);
|
||||
const loading = ref(false);
|
||||
const websiteForm = ref<FormInstance>();
|
||||
const form = reactive({
|
||||
ids: [] as number[],
|
||||
groupID: 0,
|
||||
});
|
||||
const rules = ref({
|
||||
groupID: [Rules.requiredSelect],
|
||||
});
|
||||
|
||||
const handleClose = () => {
|
||||
open.value = false;
|
||||
};
|
||||
|
||||
const acceptParams = async (ids: []) => {
|
||||
form.ids = ids;
|
||||
form.groupID = 0;
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const submit = async () => {
|
||||
loading.value = true;
|
||||
const valid = await websiteForm.value.validate();
|
||||
if (!valid) {
|
||||
loading.value = false;
|
||||
return;
|
||||
}
|
||||
batchSetGroup(form)
|
||||
.then(() => {
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
open.value = false;
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<el-form-item :label="$t('commons.table.group')" :prop="prop">
|
||||
<el-select v-model="selectedValue">
|
||||
<el-option
|
||||
v-for="(group, index) in groups"
|
||||
:key="index"
|
||||
:label="group.name === 'Default' ? $t('commons.table.default') : group.name"
|
||||
:value="group.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { Group } from '@/api/interface/group';
|
||||
import { getAgentGroupList } from '@/api/modules/group';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
groupType: {
|
||||
type: String,
|
||||
default: 'website',
|
||||
},
|
||||
prop: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
||||
const groups = ref<Group.GroupInfo[]>([]);
|
||||
|
||||
const selectedValue = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value) => emit('update:modelValue', value),
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
const res = await getAgentGroupList(props.groupType);
|
||||
groups.value = res.data;
|
||||
if (groups.value.length > 0 && !props.modelValue && props.modelValue == 0) {
|
||||
selectedValue.value = groups.value[0].id;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -8,16 +8,11 @@
|
||||
<el-form-item :label="$t('website.alias')" prop="primaryDomain">
|
||||
<el-input v-model="form.alias" disabled></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.table.group')" prop="webSiteGroupID">
|
||||
<el-select v-model="form.webSiteGroupId">
|
||||
<el-option
|
||||
v-for="(group, index) in groups"
|
||||
:key="index"
|
||||
:label="group.name == 'Default' ? $t('commons.table.default') : group.name"
|
||||
:value="group.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<GroupSelect
|
||||
v-model="form.webSiteGroupId"
|
||||
:prop="'webSiteGroupId'"
|
||||
:groupType="'website'"
|
||||
></GroupSelect>
|
||||
<el-form-item :label="$t('website.remark')" prop="remark">
|
||||
<el-input v-model="form.remark"></el-input>
|
||||
</el-form-item>
|
||||
@@ -35,14 +30,14 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import GroupSelect from '@/views/website/website/components/group/index.vue';
|
||||
|
||||
import { getWebsite, updateWebsite } from '@/api/modules/website';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import i18n from '@/lang';
|
||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||
import { getAgentGroupList } from '@/api/modules/group';
|
||||
import { Group } from '@/api/interface/group';
|
||||
|
||||
const websiteForm = ref<FormInstance>();
|
||||
const props = defineProps({
|
||||
@@ -68,7 +63,6 @@ const rules = ref({
|
||||
primaryDomain: [Rules.requiredInput],
|
||||
webSiteGroupId: [Rules.requiredSelect],
|
||||
});
|
||||
const groups = ref<Group.GroupInfo[]>([]);
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
@@ -92,9 +86,6 @@ const submit = async (formEl: FormInstance | undefined) => {
|
||||
});
|
||||
};
|
||||
const search = async () => {
|
||||
const res = await getAgentGroupList('website');
|
||||
groups.value = res.data;
|
||||
|
||||
getWebsite(websiteId.value).then((res) => {
|
||||
form.primaryDomain = res.data.primaryDomain;
|
||||
form.remark = res.data.remark;
|
||||
|
||||
@@ -28,16 +28,11 @@
|
||||
:validate-on-rule-change="false"
|
||||
v-loading="loading"
|
||||
>
|
||||
<el-form-item :label="$t('commons.table.group')" prop="webSiteGroupId">
|
||||
<el-select v-model="website.webSiteGroupId">
|
||||
<el-option
|
||||
v-for="(group, index) in groups"
|
||||
:key="index"
|
||||
:label="group.name == 'Default' ? $t('commons.table.default') : group.name"
|
||||
:value="group.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<GroupSelect
|
||||
v-model="website.webSiteGroupId"
|
||||
:prop="'webSiteGroupId'"
|
||||
:groupType="'website'"
|
||||
></GroupSelect>
|
||||
<div v-if="website.type === 'deployment'">
|
||||
<el-form-item prop="appType">
|
||||
<el-radio-group v-model="website.appType" @change="changeAppType(website.appType)">
|
||||
@@ -421,6 +416,13 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="CreateWebSite">
|
||||
import AppInstallForm from '@/views/app-store/detail/form/index.vue';
|
||||
import SSLAlert from '@/views/website/website/create/site-alert/index.vue';
|
||||
import DomainCreate from '@/views/website/website/domain-create/index.vue';
|
||||
import TaskLog from '@/components/log/task/index.vue';
|
||||
import Check from '../check/index.vue';
|
||||
import GroupSelect from '@/views/website/website/components/group/index.vue';
|
||||
|
||||
import { App } from '@/api/interface/app';
|
||||
import { searchApp, getAppInstalled } from '@/api/modules/app';
|
||||
import {
|
||||
@@ -435,23 +437,16 @@ import { Rules, checkNumberRange } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { ElForm, FormInstance } from 'element-plus';
|
||||
import { reactive, ref } from 'vue';
|
||||
import Check from '../check/index.vue';
|
||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||
import { getAgentGroupList } from '@/api/modules/group';
|
||||
import { Group } from '@/api/interface/group';
|
||||
import { SearchRuntimes } from '@/api/modules/runtime';
|
||||
import { Runtime } from '@/api/interface/runtime';
|
||||
import { getRandomStr, getRuntimeLabel } from '@/utils/util';
|
||||
import TaskLog from '@/components/log/task/index.vue';
|
||||
import { getAppService } from '@/api/modules/app';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { dateFormatSimple, getProvider, getAccountName } from '@/utils/util';
|
||||
import { Website } from '@/api/interface/website';
|
||||
import DomainCreate from '@/views/website/website/domain-create/index.vue';
|
||||
import { getPathByType } from '@/api/modules/files';
|
||||
import { getWebsiteTypes } from '@/global/mimetype';
|
||||
import AppInstallForm from '@/views/app-store/detail/form/index.vue';
|
||||
import SSLAlert from '@/views/website/website/create/site-alert/index.vue';
|
||||
|
||||
const websiteForm = ref<FormInstance>();
|
||||
|
||||
@@ -462,7 +457,7 @@ const initData = () => ({
|
||||
remark: '',
|
||||
appType: 'installed',
|
||||
appInstallId: undefined,
|
||||
webSiteGroupId: 1,
|
||||
webSiteGroupId: 0,
|
||||
otherDomains: '',
|
||||
proxy: '',
|
||||
runtimeID: undefined,
|
||||
@@ -539,7 +534,6 @@ const rules = ref<any>({
|
||||
|
||||
const open = ref(false);
|
||||
const loading = ref(false);
|
||||
const groups = ref<Group.GroupInfo[]>([]);
|
||||
const acmeAccounts = ref();
|
||||
const appInstalls = ref<App.AppInstalled[]>([]);
|
||||
const appReq = reactive({
|
||||
@@ -714,9 +708,6 @@ const acceptParams = async () => {
|
||||
const dirRes = await getPathByType('websiteDir');
|
||||
staticPath.value = dirRes.data + '/sites/';
|
||||
|
||||
const res = await getAgentGroupList('website');
|
||||
groups.value = res.data;
|
||||
website.value.webSiteGroupId = res.data[0].id;
|
||||
runtimeResource.value = 'appstore';
|
||||
runtimeReq.value = initRuntimeReq();
|
||||
changeType(websiteType);
|
||||
|
||||
@@ -222,6 +222,10 @@
|
||||
:label="$t('commons.button.delete') + $t('menu.website')"
|
||||
value="delete"
|
||||
></el-option>
|
||||
<el-option
|
||||
:label="$t('commons.button.set') + $t('commons.table.group')"
|
||||
value="group"
|
||||
></el-option>
|
||||
</el-select>
|
||||
<el-button
|
||||
class="ml-2"
|
||||
@@ -261,6 +265,7 @@
|
||||
<DefaultHtml ref="defaultHtmlRef" />
|
||||
<TaskLog ref="taskLogRef" @close="search" />
|
||||
<OpDialog ref="opRef" @search="openTaskLog" />
|
||||
<BatchSetGroup ref="batchSetGroupRef" @close="search" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -276,6 +281,8 @@ import GroupDialog from '@/components/agent-group/index.vue';
|
||||
import AppStatus from '@/components/app-status/index.vue';
|
||||
import TaskLog from '@/components/log/task/index.vue';
|
||||
import Domain from '@/views/website/website/domain/index.vue';
|
||||
import BatchSetGroup from '@/views/website/website/batch-op/group.vue';
|
||||
|
||||
import i18n from '@/lang';
|
||||
import { onMounted, reactive, ref, computed } from 'vue';
|
||||
import { batchOpreate, opWebsite, searchWebsites, updateWebsite } from '@/api/modules/website';
|
||||
@@ -336,6 +343,7 @@ const batchReq = reactive({
|
||||
});
|
||||
const taskLogRef = ref();
|
||||
const opRef = ref();
|
||||
const batchSetGroupRef = ref();
|
||||
|
||||
const paginationConfig = reactive({
|
||||
cacheSizeKey: 'website-page-size',
|
||||
@@ -609,18 +617,22 @@ const openTaskLog = () => {
|
||||
};
|
||||
|
||||
const batchOp = () => {
|
||||
const names = selects.value.map((item) => item.primaryDomain);
|
||||
batchReq.ids = selects.value.map((item) => item.id);
|
||||
const taskID = newUUID();
|
||||
batchReq.taskID = taskID;
|
||||
opRef.value.acceptParams({
|
||||
names: names,
|
||||
title: i18n.global.t('website.batchOpreate'),
|
||||
api: batchOpreate,
|
||||
msg: i18n.global.t('website.batchOpreateHelper', [i18n.global.t('commons.button.' + batchReq.operate)]),
|
||||
params: batchReq,
|
||||
noMsg: true,
|
||||
});
|
||||
if (batchReq.operate == 'group') {
|
||||
batchSetGroupRef.value.acceptParams(selects.value.map((item) => item.id));
|
||||
} else {
|
||||
const names = selects.value.map((item) => item.primaryDomain);
|
||||
batchReq.ids = selects.value.map((item) => item.id);
|
||||
const taskID = newUUID();
|
||||
batchReq.taskID = taskID;
|
||||
opRef.value.acceptParams({
|
||||
names: names,
|
||||
title: i18n.global.t('website.batchOpreate'),
|
||||
api: batchOpreate,
|
||||
msg: i18n.global.t('website.batchOpreateHelper', [i18n.global.t('commons.button.' + batchReq.operate)]),
|
||||
params: batchReq,
|
||||
noMsg: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
Reference in New Issue
Block a user