pull/94/MERGE
xingyu4j 2025-05-07 18:22:31 +08:00
commit ff79b79456
6 changed files with 206 additions and 29 deletions

View File

@ -1,7 +1,5 @@
import type { PageParam, PageResult } from '@vben/request';
import type { BpmModelApi } from '#/api/bpm/model';
import { requestClient } from '#/api/request';
export namespace BpmCategoryApi {
@ -11,16 +9,9 @@ export namespace BpmCategoryApi {
name: string;
code: string;
status: number;
description?: string;
sort: number; // 分类排序
}
/** 模型分类信息 */
// TODO @jason这个应该非 api 的,可以考虑抽到页面里哈。
export interface ModelCategoryInfo {
id: number;
name: string;
modelList: BpmModelApi.ModelVO[];
}
}
/** 查询流程分类分页 */

View File

@ -40,13 +40,13 @@ export namespace BpmModelApi {
bpmnXml: string;
startUsers?: UserInfo[];
}
}
/** 模型分类信息 */
export interface ModelCategoryInfo {
id: number;
name: string;
modelList: ModelVO[];
}
/** 模型分类信息 */
export interface ModelCategoryInfo {
id: number;
name: string;
modelList: BpmModelApi.ModelVO[];
}
/** 获取流程模型列表 */

View File

@ -64,6 +64,7 @@ export function useFormSchema(): VbenFormSchema[] {
min: 0,
controlsPosition: 'right',
placeholder: '请输入分类排序',
class: 'w-full',
},
},
];

View File

@ -0,0 +1,102 @@
<script lang="ts" setup>
import type { BpmCategoryApi } from '#/api/bpm/category';
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { getCategory, updateCategory } from '#/api/bpm/category';
import { $t } from '#/locales';
const emit = defineEmits(['success']);
const formData = ref<BpmCategoryApi.CategoryVO>();
//
const formSchema = [
{
fieldName: 'name',
label: '分类名',
component: 'Input',
componentProps: {
placeholder: '请输入分类名',
},
rules: 'required',
},
];
//
const [Form, formApi] = useVbenForm({
layout: 'horizontal',
schema: formSchema,
showDefaultActions: false,
});
//
const [Modal, modalApi] = useVbenModal({
//
async onConfirm() {
const { valid } = await formApi.validate();
if (!valid) {
return;
}
modalApi.lock();
//
const formValues = await formApi.getValues();
const data = {
id: formData.value?.id,
name: formValues.name, //
code: formData.value?.code,
status: formData.value?.status,
description: formData.value?.description,
sort: formData.value?.sort,
} as BpmCategoryApi.CategoryVO;
try {
await updateCategory(data);
//
await modalApi.close();
emit('success');
message.success($t('ui.actionMessage.operationSuccess'));
} finally {
modalApi.unlock();
}
},
// /
async onOpenChange(isOpen: boolean) {
if (!isOpen) {
formData.value = undefined;
return;
}
//
const data = modalApi.getData<BpmCategoryApi.CategoryVO>();
if (!data || !data.id) {
return;
}
modalApi.lock();
try {
//
formData.value = await getCategory(data.id as number);
// name
await formApi.setValues({
name: formData.value.name,
});
} finally {
modalApi.unlock();
}
},
});
</script>
<template>
<Modal title="重命名流程分类">
<Form class="mx-4" />
</Modal>
</template>

View File

@ -1,9 +1,9 @@
<script lang="ts" setup>
import type { BpmModelApi } from '#/api/bpm/model';
import type { ModelCategoryInfo } from '#/api/bpm/model';
import { onActivated, reactive, ref, useTemplateRef, watch } from 'vue';
import { Page } from '@vben/common-ui';
import { Page, useVbenModal } from '@vben/common-ui';
import { Plus, Search, Settings } from '@vben/icons';
import { cloneDeep } from '@vben/utils';
@ -26,15 +26,24 @@ import {
} from '#/api/bpm/category';
import { getModelList } from '#/api/bpm/model';
//
import CategoryForm from '../category/modules/form.vue';
import CategoryDraggableModel from './modules/category-draggable-model.vue';
//
const [CategoryFormModal, categoryFormModalApi] = useVbenModal({
connectedComponent: CategoryForm,
destroyOnClose: true,
});
//
const modelListSpinning = refAutoReset(false, 3000);
//
const saveSortLoading = ref(false);
// category
const categoryGroup = ref<BpmModelApi.ModelCategoryInfo[]>([]);
const categoryGroup = ref<ModelCategoryInfo[]>([]);
//
const originalData = ref<BpmModelApi.ModelCategoryInfo[]>([]);
const originalData = ref<ModelCategoryInfo[]>([]);
//
const sortable = useTemplateRef<HTMLElement>('categoryGroupRef');
// 便
@ -100,7 +109,8 @@ const createModel = () => {
/** 处理下拉菜单命令 */
const handleCommand = (command: string) => {
if (command === 'handleCategoryAdd') {
// TODO
//
categoryFormModalApi.open();
} else if (command === 'handleCategorySort') {
originalData.value = cloneDeep(categoryGroup.value);
isCategorySorting.value = true;
@ -152,7 +162,7 @@ const handleCategorySortSubmit = async () => {
<Page auto-content-height>
<Card
:body-style="{ padding: '10px' }"
class="mb-4 h-[89vh]"
class="mb-4"
v-spinning="modelListSpinning"
>
<div class="flex h-full items-center justify-between pl-5">
@ -184,7 +194,7 @@ const handleCategorySortSubmit = async () => {
</Button>
</Form.Item>
<Form.Item>
<Dropdown placement="bottomRight">
<Dropdown placement="bottomRight" arrow>
<Button>
<template #icon>
<Settings class="size-4" />
@ -239,4 +249,7 @@ const handleCategorySortSubmit = async () => {
</div>
</Card>
</Page>
<!-- 流程分类表单弹窗 -->
<CategoryFormModal @success="getList" />
</template>

View File

@ -1,9 +1,9 @@
<script lang="ts" setup>
import type { BpmCategoryApi } from '#/api/bpm/category';
import type { BpmModelApi } from '#/api/bpm/model';
import type { BpmModelApi, ModelCategoryInfo } from '#/api/bpm/model';
import { computed, ref, watchEffect } from 'vue';
import { confirm, useVbenModal } from '@vben/common-ui';
import { cloneDeep, formatDateTime, isEqual } from '@vben/utils';
import { useDebounceFn } from '@vueuse/core';
@ -12,18 +12,25 @@ import {
Button,
Card,
Collapse,
Dropdown,
Menu,
message,
Table,
Tag,
Tooltip,
} from 'ant-design-vue';
import { deleteCategory } from '#/api/bpm/category';
import { updateModelSortBatch } from '#/api/bpm/model';
import { DictTag } from '#/components/dict-tag';
import { $t } from '#/locales';
import { DICT_TYPE } from '#/utils';
//
import CategoryRenameForm from '../../category/modules/rename-form.vue';
const props = defineProps<{
categoryInfo: BpmCategoryApi.ModelCategoryInfo;
categoryInfo: ModelCategoryInfo;
isCategorySorting: boolean;
}>();
@ -131,6 +138,36 @@ const handleModelSortCancel = () => {
}
};
/** 处理下拉菜单命令 */
const handleCommand = (command: string) => {
if (command === 'renameCategory') {
//
categoryRenameModalApi.setData(props.categoryInfo).open();
} else if (command === 'deleteCategory') {
handleDeleteCategory();
}
};
/** 删除流程分类 */
const handleDeleteCategory = async () => {
if (props.categoryInfo.modelList.length > 0) {
message.warning('该分类下仍有流程定义,不允许删除');
return;
}
confirm({
content: `确定要删除[${props.categoryInfo.name}]吗?`,
}).then(async () => {
//
await deleteCategory(props.categoryInfo.id);
message.success(
$t('ui.actionMessage.deleteSuccess', [props.categoryInfo.name]),
);
//
emit('success');
});
};
/** 处理表单详情点击 */
const handleFormDetail = (row: any) => {
// TODO
@ -169,6 +206,17 @@ const customRow = (_record: any) => {
class: isModelSorting.value ? 'cursor-move' : '',
};
};
//
const [CategoryRenameModal, categoryRenameModalApi] = useVbenModal({
connectedComponent: CategoryRenameForm,
destroyOnClose: true,
});
//
const handleRenameSuccess = () => {
emit('success');
};
</script>
<template>
@ -205,20 +253,39 @@ const customRow = (_record: any) => {
<div
class="ml-auto flex items-center"
:class="isModelSorting ? 'mr-4' : 'mr-12'"
:class="isModelSorting ? 'mr-4' : 'mr-8'"
>
<template v-if="!isModelSorting">
<Button
v-if="categoryInfo.modelList.length > 0"
type="link"
class="mr-5 flex items-center text-[14px]"
size="small"
class="flex items-center text-[14px]"
@click.stop="handleModelSort"
>
<template #icon>
<span class="icon-[fa--sort-amount-desc] mr-1"></span>
<span class="icon-[fa--sort-amount-desc]"></span>
</template>
排序
</Button>
<Dropdown placement="bottom" arrow>
<Button
type="link"
size="small"
class="flex items-center text-[14px]"
>
<template #icon>
<span class="icon-[ant-design--setting-outlined]"></span>
</template>
分类
</Button>
<template #overlay>
<Menu @click="(e) => handleCommand(e.key as string)">
<Menu.Item key="renameCategory"> 重命名 </Menu.Item>
<Menu.Item key="deleteCategory"> 删除分类 </Menu.Item>
</Menu>
</template>
</Dropdown>
</template>
<template v-else>
@ -370,6 +437,9 @@ const customRow = (_record: any) => {
</Collapse.Panel>
</Collapse>
</Card>
<!-- 重命名分类弹窗 -->
<CategoryRenameModal @success="handleRenameSuccess" />
</template>
<style lang="scss" scoped>