mirror of
https://github.com/certd/certd.git
synced 2026-04-24 12:27:25 +08:00
perf: 流水线支持批量修改分组,批量删除
This commit is contained in:
@@ -7,5 +7,9 @@
|
||||
.menu-item-title{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.fs-icon{
|
||||
font-size: 16px !important;
|
||||
min-width: 16px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ export default defineComponent({
|
||||
const title: any = () => {
|
||||
const icon = sub.icon || sub?.meta?.icon;
|
||||
if (icon) {
|
||||
// @ts-ignore
|
||||
// @ts-ignore , anticon必须要有,不然不能折叠
|
||||
return (
|
||||
<div class={"menu-item-title"}>
|
||||
<fsIcon class={"anticon"} icon={icon} />
|
||||
|
||||
@@ -10,13 +10,14 @@
|
||||
@tab-click="handleClick"
|
||||
@edit="handleTabEdit"
|
||||
>
|
||||
<a-tab-pane
|
||||
v-for="item in page.getOpened"
|
||||
:key="item.fullPath"
|
||||
:tab="item.meta?.title || '未命名'"
|
||||
:name="item.fullPath"
|
||||
:closable="isTabClosable(item)"
|
||||
/>
|
||||
<a-tab-pane v-for="item in page.getOpened" :key="item.fullPath" :name="item.fullPath" :closable="isTabClosable(item)">
|
||||
<template #tab>
|
||||
<span class="flex-o">
|
||||
<fs-icon :icon="item.meta.icon" class="mr-5"></fs-icon>
|
||||
{{ item.meta?.title || "未命名" }}
|
||||
</span>
|
||||
</template>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
<!-- <fs-contextmenu v-model:open="contextmenuFlag" :x="contentmenuX" :y="contentmenuY">-->
|
||||
<!-- <fs-contextmenu-list-->
|
||||
|
||||
@@ -70,6 +70,16 @@ export const certdResources = [
|
||||
auth: true
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "分组管理",
|
||||
name: "PipelineGroupManager",
|
||||
path: "/certd/pipeline/group",
|
||||
component: "/certd/pipeline/group/index.vue",
|
||||
meta: {
|
||||
icon: "mdi:format-list-group",
|
||||
auth: true
|
||||
}
|
||||
},
|
||||
// {
|
||||
// title: "邮箱设置",
|
||||
// name: "EmailSetting",
|
||||
|
||||
@@ -7,6 +7,7 @@ import { ref } from "vue";
|
||||
import { CrudOptions, useColumns, useFormWrapper } from "@fast-crud/fast-crud";
|
||||
import * as api from "/@/views/certd/mine/api";
|
||||
import { notification } from "ant-design-vue";
|
||||
import { useUserStore } from "/@/store/modules/user";
|
||||
|
||||
defineProps<{
|
||||
showButton: boolean;
|
||||
@@ -33,6 +34,7 @@ const validatePass2 = async (rule: any, value: any) => {
|
||||
throw new Error("两次输入密码不一致!");
|
||||
}
|
||||
};
|
||||
const userStore = useUserStore();
|
||||
const { openDialog } = useFormWrapper();
|
||||
const { buildFormOptions } = useColumns();
|
||||
const passwordFormOptions: CrudOptions = {
|
||||
@@ -46,6 +48,8 @@ const passwordFormOptions: CrudOptions = {
|
||||
},
|
||||
async doSubmit({ form }) {
|
||||
await api.changePassword(form);
|
||||
//重新加载用户信息
|
||||
await userStore.loadUserInfo();
|
||||
},
|
||||
async afterSubmit() {
|
||||
notification.success({ message: "修改成功" });
|
||||
|
||||
@@ -76,6 +76,22 @@ export async function Cancel(historyId: any) {
|
||||
});
|
||||
}
|
||||
|
||||
export async function BatchUpdateGroup(pipelineIds: number[], groupId: number): Promise<CertInfo> {
|
||||
return await request({
|
||||
url: apiPrefix + "/batchUpdateGroup",
|
||||
method: "post",
|
||||
data: { ids: pipelineIds, groupId }
|
||||
});
|
||||
}
|
||||
|
||||
export async function BatchDelete(pipelineIds: number[]): Promise<CertInfo> {
|
||||
return await request({
|
||||
url: apiPrefix + "/batchDelete",
|
||||
method: "post",
|
||||
data: { ids: pipelineIds }
|
||||
});
|
||||
}
|
||||
|
||||
export async function GetFiles(pipelineId: number) {
|
||||
return await request({
|
||||
url: historyApiPrefix + "/files",
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<fs-button icon="mdi:format-list-group" type="link" text="修改分组" @click="openGroupSelectDialog"></fs-button>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import * as api from "../api";
|
||||
import { notification } from "ant-design-vue";
|
||||
import { dict, useFormWrapper } from "@fast-crud/fast-crud";
|
||||
|
||||
const props = defineProps<{
|
||||
selectedRowKeys: any[];
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
change: any;
|
||||
}>();
|
||||
async function batchUpdateGroupRequest(groupId: number) {
|
||||
await api.BatchUpdateGroup(props.selectedRowKeys, groupId);
|
||||
emit("change");
|
||||
}
|
||||
|
||||
const pipelineGroupDictRef = dict({
|
||||
url: "/pi/pipeline/group/all",
|
||||
value: "id",
|
||||
label: "name"
|
||||
});
|
||||
const { openCrudFormDialog } = useFormWrapper();
|
||||
|
||||
async function openGroupSelectDialog() {
|
||||
const crudOptions: any = {
|
||||
columns: {
|
||||
groupId: {
|
||||
title: "分组",
|
||||
type: "dict-select",
|
||||
dict: pipelineGroupDictRef,
|
||||
form: {
|
||||
rules: [{ required: true, message: "请选择分组" }]
|
||||
}
|
||||
}
|
||||
},
|
||||
form: {
|
||||
mode: "edit",
|
||||
//@ts-ignore
|
||||
async doSubmit({ form }) {
|
||||
await batchUpdateGroupRequest(form.groupId);
|
||||
},
|
||||
col: {
|
||||
span: 22
|
||||
},
|
||||
labelCol: {
|
||||
style: {
|
||||
width: "100px"
|
||||
}
|
||||
},
|
||||
wrapper: {
|
||||
title: "批量修改分组",
|
||||
width: 600
|
||||
}
|
||||
}
|
||||
} as any;
|
||||
await openCrudFormDialog({ crudOptions });
|
||||
}
|
||||
</script>
|
||||
@@ -15,7 +15,7 @@ import { useModal } from "/@/use/use-modal";
|
||||
import CertView from "./cert-view.vue";
|
||||
import { eachStages } from "./utils";
|
||||
import { createApi as createNotificationApi } from "../notification/api";
|
||||
export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
export default function ({ crudExpose, context: { certdFormRef, groupDictRef, selectedRowKeys } }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
const lastResRef = ref();
|
||||
@@ -198,6 +198,7 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
||||
};
|
||||
const userStore = useUserStore();
|
||||
const settingStore = useSettingStore();
|
||||
|
||||
return {
|
||||
crudOptions: {
|
||||
request: {
|
||||
@@ -206,6 +207,26 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
||||
editRequest,
|
||||
delRequest
|
||||
},
|
||||
settings: {
|
||||
plugins: {
|
||||
//行选择插件,内置插件
|
||||
rowSelection: {
|
||||
//是否启用本插件
|
||||
enabled: true,
|
||||
order: -2,
|
||||
//合并在用户配置crudOptions之前还是之后
|
||||
before: true,
|
||||
props: {
|
||||
multiple: true,
|
||||
crossPage: false,
|
||||
selectedRowKeys,
|
||||
onSelectedChanged(selected) {
|
||||
console.log("已选择变化:", selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
actionbar: {
|
||||
buttons: {
|
||||
add: {
|
||||
@@ -232,9 +253,16 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
||||
table: {
|
||||
scroll: { x: 1500 }
|
||||
},
|
||||
tabs: {
|
||||
name: "groupId",
|
||||
show: true
|
||||
},
|
||||
rowHandle: {
|
||||
width: 300,
|
||||
width: 200,
|
||||
fixed: "right",
|
||||
dropdown: {
|
||||
show: true
|
||||
},
|
||||
buttons: {
|
||||
play: {
|
||||
order: -999,
|
||||
@@ -275,8 +303,9 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
||||
},
|
||||
config: {
|
||||
order: 1,
|
||||
title: "修改流水线内容",
|
||||
title: "编辑流水线",
|
||||
type: "link",
|
||||
dropdown: true,
|
||||
icon: "ant-design:edit-outlined",
|
||||
click({ row }) {
|
||||
router.push({ path: "/certd/pipeline/detail", query: { id: row.id, editMode: "true" } });
|
||||
@@ -284,8 +313,9 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
||||
},
|
||||
edit: {
|
||||
order: 2,
|
||||
title: "修改流水线运行配置",
|
||||
icon: "ant-design:setting-outlined"
|
||||
title: "修改配置/分组",
|
||||
icon: "ant-design:setting-outlined",
|
||||
dropdown: true
|
||||
},
|
||||
viewCert: {
|
||||
order: 3,
|
||||
@@ -293,7 +323,7 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
||||
type: "link",
|
||||
icon: "ph:certificate",
|
||||
async click({ row }) {
|
||||
viewCert(row);
|
||||
await viewCert(row);
|
||||
}
|
||||
},
|
||||
download: {
|
||||
@@ -302,11 +332,12 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
||||
title: "下载证书",
|
||||
icon: "ant-design:download-outlined",
|
||||
async click({ row }) {
|
||||
downloadCert(row);
|
||||
await downloadCert(row);
|
||||
}
|
||||
},
|
||||
remove: {
|
||||
order: 5
|
||||
order: 5,
|
||||
dropdown: true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -495,17 +526,19 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
keepHistoryCount: {
|
||||
title: "历史记录保持数",
|
||||
type: "number",
|
||||
form: {
|
||||
value: 20,
|
||||
helper: "历史记录保持条数,多余的会被删除"
|
||||
groupId: {
|
||||
title: "分组",
|
||||
type: "dict-select",
|
||||
search: {
|
||||
show: true
|
||||
},
|
||||
dict: groupDictRef,
|
||||
column: {
|
||||
width: 130,
|
||||
show: false
|
||||
align: "center",
|
||||
component: {
|
||||
color: "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
order: {
|
||||
@@ -520,6 +553,18 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
||||
value: 0
|
||||
}
|
||||
},
|
||||
keepHistoryCount: {
|
||||
title: "历史记录保持数",
|
||||
type: "number",
|
||||
form: {
|
||||
value: 20,
|
||||
helper: "历史记录保持条数,多余的会被删除"
|
||||
},
|
||||
column: {
|
||||
width: 130,
|
||||
show: false
|
||||
}
|
||||
},
|
||||
createTime: {
|
||||
title: "创建时间",
|
||||
type: "datetime",
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { request } from "/src/api/service";
|
||||
|
||||
export function createApi() {
|
||||
const apiPrefix = "/pi/pipeline/group";
|
||||
return {
|
||||
async GetList(query: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/page",
|
||||
method: "post",
|
||||
data: query
|
||||
});
|
||||
},
|
||||
|
||||
async AddObj(obj: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/add",
|
||||
method: "post",
|
||||
data: obj
|
||||
});
|
||||
},
|
||||
|
||||
async UpdateObj(obj: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/update",
|
||||
method: "post",
|
||||
data: obj
|
||||
});
|
||||
},
|
||||
|
||||
async DelObj(id: number) {
|
||||
return await request({
|
||||
url: apiPrefix + "/delete",
|
||||
method: "post",
|
||||
params: { id }
|
||||
});
|
||||
},
|
||||
|
||||
async GetObj(id: number) {
|
||||
return await request({
|
||||
url: apiPrefix + "/info",
|
||||
method: "post",
|
||||
params: { id }
|
||||
});
|
||||
},
|
||||
async ListAll() {
|
||||
return await request({
|
||||
url: apiPrefix + "/all",
|
||||
method: "post"
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const pipelineGroupApi = createApi();
|
||||
@@ -0,0 +1,124 @@
|
||||
// @ts-ignore
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { ref } from "vue";
|
||||
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
||||
import { pipelineGroupApi } from "./api";
|
||||
|
||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const { t } = useI18n();
|
||||
const api = pipelineGroupApi;
|
||||
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
||||
return await api.GetList(query);
|
||||
};
|
||||
const editRequest = async (req: EditReq) => {
|
||||
const { form, row } = req;
|
||||
form.id = row.id;
|
||||
const res = await api.UpdateObj(form);
|
||||
return res;
|
||||
};
|
||||
const delRequest = async (req: DelReq) => {
|
||||
const { row } = req;
|
||||
return await api.DelObj(row.id);
|
||||
};
|
||||
|
||||
const addRequest = async (req: AddReq) => {
|
||||
const { form } = req;
|
||||
const res = await api.AddObj(form);
|
||||
return res;
|
||||
};
|
||||
|
||||
return {
|
||||
crudOptions: {
|
||||
request: {
|
||||
pageRequest,
|
||||
addRequest,
|
||||
editRequest,
|
||||
delRequest
|
||||
},
|
||||
form: {
|
||||
labelCol: {
|
||||
//固定label宽度
|
||||
span: null,
|
||||
style: {
|
||||
width: "100px"
|
||||
}
|
||||
},
|
||||
col: {
|
||||
span: 22
|
||||
},
|
||||
wrapper: {
|
||||
width: 600
|
||||
}
|
||||
},
|
||||
rowHandle: {
|
||||
width: 200,
|
||||
group: {
|
||||
editable: {
|
||||
edit: {
|
||||
text: "编辑",
|
||||
order: -1,
|
||||
type: "primary",
|
||||
click({ row, index }) {
|
||||
crudExpose.openEdit({
|
||||
index,
|
||||
row
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
table: {
|
||||
editable: {
|
||||
enabled: true,
|
||||
mode: "cell",
|
||||
exclusive: true,
|
||||
//排他式激活效果,将其他行的编辑状态触发保存
|
||||
exclusiveEffect: "save", //自动保存其他行编辑状态,cancel = 自动关闭其他行编辑状态
|
||||
async updateCell(opts) {
|
||||
const { row, key, value } = opts;
|
||||
//如果是添加,需要返回{[rowKey]:xxx},比如:{id:2}
|
||||
return await api.UpdateObj({ id: row.id, [key]: value });
|
||||
}
|
||||
}
|
||||
},
|
||||
columns: {
|
||||
id: {
|
||||
title: "ID",
|
||||
key: "id",
|
||||
type: "number",
|
||||
search: {
|
||||
show: true
|
||||
},
|
||||
column: {
|
||||
width: 100,
|
||||
editable: {
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
form: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
name: {
|
||||
title: "分组名称",
|
||||
search: {
|
||||
show: true
|
||||
},
|
||||
type: "text",
|
||||
form: {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入分组名称"
|
||||
}
|
||||
]
|
||||
},
|
||||
column: {
|
||||
width: 400
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<fs-page>
|
||||
<template #header>
|
||||
<div class="title">
|
||||
分组管理
|
||||
<span class="sub">管理流水线分组</span>
|
||||
</div>
|
||||
</template>
|
||||
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
|
||||
</fs-page>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onActivated, onMounted } from "vue";
|
||||
import { useFs } from "@fast-crud/fast-crud";
|
||||
import createCrudOptions from "./crud";
|
||||
import { createApi } from "./api";
|
||||
|
||||
export default defineComponent({
|
||||
name: "PipelineGroupManager",
|
||||
setup() {
|
||||
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: {} });
|
||||
|
||||
// 页面打开后获取列表数据
|
||||
onMounted(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
onActivated(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
|
||||
return {
|
||||
crudBinding,
|
||||
crudRef
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -4,6 +4,13 @@
|
||||
<div class="title">我的流水线</div>
|
||||
</template>
|
||||
<fs-crud ref="crudRef" v-bind="crudBinding">
|
||||
<div v-if="selectedRowKeys.length > 0" class="batch-actions">
|
||||
<div class="batch-actions-inner">
|
||||
<span> 已选择 {{ selectedRowKeys.length }} 项 </span>
|
||||
<fs-button icon="ion:trash-outline" type="link" text="批量删除" @click="batchDelete"></fs-button>
|
||||
<change-group :selected-row-keys="selectedRowKeys" @change="groupChanged"></change-group>
|
||||
</div>
|
||||
</div>
|
||||
<template #actionbar-right> </template>
|
||||
<template #form-bottom>
|
||||
<div>申请证书</div>
|
||||
@@ -13,37 +20,80 @@
|
||||
</fs-page>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, onMounted, onActivated } from "vue";
|
||||
import { useCrud, useFs } from "@fast-crud/fast-crud";
|
||||
<script lang="ts" setup>
|
||||
import { onActivated, onMounted, ref } from "vue";
|
||||
import { dict, useFs } from "@fast-crud/fast-crud";
|
||||
import createCrudOptions from "./crud";
|
||||
import { useExpose } from "@fast-crud/fast-crud";
|
||||
import PiCertdForm from "./certd-form/index.vue";
|
||||
export default defineComponent({
|
||||
name: "PipelineManager",
|
||||
components: { PiCertdForm },
|
||||
setup() {
|
||||
const certdFormRef = ref();
|
||||
const context: any = {
|
||||
certdFormRef
|
||||
};
|
||||
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
|
||||
|
||||
// 页面打开后获取列表数据
|
||||
onMounted(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
|
||||
onActivated(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
|
||||
return {
|
||||
crudBinding,
|
||||
crudRef,
|
||||
certdFormRef
|
||||
};
|
||||
}
|
||||
import ChangeGroup from "./components/change-group.vue";
|
||||
import { Modal, notification } from "ant-design-vue";
|
||||
import * as api from "./api";
|
||||
defineOptions({
|
||||
name: "PipelineManager"
|
||||
});
|
||||
|
||||
const certdFormRef = ref();
|
||||
const groupDictRef = dict({
|
||||
url: "/pi/pipeline/group/all",
|
||||
value: "id",
|
||||
label: "name"
|
||||
});
|
||||
const selectedRowKeys = ref([]);
|
||||
const context: any = {
|
||||
certdFormRef,
|
||||
groupDictRef,
|
||||
selectedRowKeys
|
||||
};
|
||||
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
|
||||
|
||||
// 页面打开后获取列表数据
|
||||
onMounted(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
|
||||
onActivated(async () => {
|
||||
await groupDictRef.reloadDict();
|
||||
await crudExpose.doRefresh();
|
||||
});
|
||||
|
||||
function groupChanged() {
|
||||
crudExpose.doRefresh();
|
||||
}
|
||||
|
||||
function batchDelete() {
|
||||
Modal.confirm({
|
||||
title: "确认删除",
|
||||
content: "确定要删除选中的数据吗?",
|
||||
async onOk() {
|
||||
await api.BatchDelete(selectedRowKeys.value);
|
||||
notification.success({ message: "删除成功" });
|
||||
await crudExpose.doRefresh();
|
||||
selectedRowKeys.value = [];
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style lang="less"></style>
|
||||
<style lang="less">
|
||||
.batch-actions {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
line-height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 37.86px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
margin-top: 1px;
|
||||
padding-left: 48px;
|
||||
pointer-events: none;
|
||||
|
||||
.batch-actions-inner {
|
||||
pointer-events: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
background-color: #fafafa;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user