mirror of
https://github.com/m-xlsea/ruoyi-plus-soybean.git
synced 2025-09-24 07:49:47 +08:00
feat: 增加流程作废功能并优化按钮组件
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, useAttrs } from 'vue';
|
import { type VNode, computed, useAttrs } from 'vue';
|
||||||
import type { ButtonProps, PopoverPlacement } from 'naive-ui';
|
import type { ButtonProps, PopoverPlacement } from 'naive-ui';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
@ -11,6 +11,8 @@ defineOptions({
|
|||||||
interface Props {
|
interface Props {
|
||||||
/** Button class */
|
/** Button class */
|
||||||
class?: string;
|
class?: string;
|
||||||
|
/** Show popconfirm icon */
|
||||||
|
showPopconfirmIcon?: boolean;
|
||||||
/** Iconify icon name */
|
/** Iconify icon name */
|
||||||
icon?: string;
|
icon?: string;
|
||||||
/** Local icon name */
|
/** Local icon name */
|
||||||
@ -19,8 +21,8 @@ interface Props {
|
|||||||
tooltipContent?: string;
|
tooltipContent?: string;
|
||||||
/** Tooltip placement */
|
/** Tooltip placement */
|
||||||
tooltipPlacement?: PopoverPlacement;
|
tooltipPlacement?: PopoverPlacement;
|
||||||
/** Popconfirm content */
|
/** Popconfirm content - can be string or VNode */
|
||||||
popconfirmContent?: string;
|
popconfirmContent?: string | VNode;
|
||||||
zIndex?: number;
|
zIndex?: number;
|
||||||
quaternary?: boolean;
|
quaternary?: boolean;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
@ -28,6 +30,7 @@ interface Props {
|
|||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
class: '',
|
class: '',
|
||||||
|
showPopconfirmIcon: true,
|
||||||
icon: '',
|
icon: '',
|
||||||
localIcon: '',
|
localIcon: '',
|
||||||
tooltipContent: '',
|
tooltipContent: '',
|
||||||
@ -59,8 +62,11 @@ const handlePositiveClick = () => {
|
|||||||
<template>
|
<template>
|
||||||
<NTooltip :placement="tooltipPlacement" :z-index="zIndex" :disabled="!tooltipContent">
|
<NTooltip :placement="tooltipPlacement" :z-index="zIndex" :disabled="!tooltipContent">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<NPopconfirm :disabled="!popconfirmContent" @positive-click="handlePositiveClick">
|
<NPopconfirm :show-icon="showPopconfirmIcon" :disabled="!popconfirmContent" @positive-click="handlePositiveClick">
|
||||||
{{ popconfirmContent }}
|
<template #default>
|
||||||
|
<component :is="popconfirmContent" v-if="typeof popconfirmContent !== 'string'" />
|
||||||
|
<template v-else>{{ popconfirmContent }}</template>
|
||||||
|
</template>
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<NButton
|
<NButton
|
||||||
:quaternary="quaternary"
|
:quaternary="quaternary"
|
||||||
|
@ -9,14 +9,6 @@ export function fetchGetRunningProcessInstanceList(params: Api.Workflow.ProcessI
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 查询正在运行的流程实例列表 */
|
|
||||||
export function fetchGetFinishProcessInstanceList(params: Api.Workflow.ProcessInstanceSearchParams) {
|
|
||||||
return request<Api.Workflow.ProcessInstanceList>({
|
|
||||||
url: '/workflow/instance/pageByFinish',
|
|
||||||
method: 'get',
|
|
||||||
params
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/** 查询已结束的流程实例列表 */
|
/** 查询已结束的流程实例列表 */
|
||||||
export function fetchGetFinishedProcessInstanceList(params: Api.Workflow.ProcessInstanceSearchParams) {
|
export function fetchGetFinishedProcessInstanceList(params: Api.Workflow.ProcessInstanceSearchParams) {
|
||||||
return request<Api.Workflow.ProcessInstanceList>({
|
return request<Api.Workflow.ProcessInstanceList>({
|
||||||
@ -29,7 +21,16 @@ export function fetchGetFinishedProcessInstanceList(params: Api.Workflow.Process
|
|||||||
/** 按照实例id删除流程实例 */
|
/** 按照实例id删除流程实例 */
|
||||||
export function fetchBatchDeleteProcessInstance(instanceIds: CommonType.IdType[]) {
|
export function fetchBatchDeleteProcessInstance(instanceIds: CommonType.IdType[]) {
|
||||||
return request<boolean>({
|
return request<boolean>({
|
||||||
url: `/workflow/deleteByInstanceIds/${instanceIds.join(',')}`,
|
url: `/workflow/instance/deleteByInstanceIds/${instanceIds.join(',')}`,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 流程作废操作 */
|
||||||
|
export function fetchFlowInvalidOperate(data: Api.Workflow.FlowInvalidOperateParams) {
|
||||||
|
return request<boolean>({
|
||||||
|
url: '/workflow/instance/invalid',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
8
src/typings/api/workflow.api.d.ts
vendored
8
src/typings/api/workflow.api.d.ts
vendored
@ -156,5 +156,13 @@ declare namespace Api {
|
|||||||
>;
|
>;
|
||||||
/** 流程实例列表 */
|
/** 流程实例列表 */
|
||||||
type ProcessInstanceList = Common.PaginatingQueryRecord<ProcessInstance>;
|
type ProcessInstanceList = Common.PaginatingQueryRecord<ProcessInstance>;
|
||||||
|
|
||||||
|
/** 流程作废操作参数 */
|
||||||
|
type FlowInvalidOperateParams = CommonType.RecordNullable<{
|
||||||
|
/** 主键 */
|
||||||
|
id: CommonType.IdType;
|
||||||
|
/** 作废原因 */
|
||||||
|
comment: string;
|
||||||
|
}>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, reactive, ref, watch } from 'vue';
|
||||||
import { NButton, NDivider, NEmpty, NInput, NRadioButton, NRadioGroup, NSpin, NTag } from 'naive-ui';
|
import { NButton, NDivider, NEmpty, NInput, NRadioButton, NRadioGroup, NSpin, NTag } from 'naive-ui';
|
||||||
import { workflowActivityStatusRecord } from '@/constants/workflow';
|
import { workflowActivityStatusRecord } from '@/constants/workflow';
|
||||||
import { fetchGetCategoryTree } from '@/service/api/workflow/category';
|
import { fetchGetCategoryTree } from '@/service/api/workflow/category';
|
||||||
import {
|
import {
|
||||||
fetchBatchDeleteProcessInstance,
|
fetchBatchDeleteProcessInstance,
|
||||||
fetchGetFinishProcessInstanceList,
|
fetchFlowInvalidOperate,
|
||||||
|
fetchGetFinishedProcessInstanceList,
|
||||||
fetchGetRunningProcessInstanceList
|
fetchGetRunningProcessInstanceList
|
||||||
} from '@/service/api/workflow/instance';
|
} from '@/service/api/workflow/instance';
|
||||||
import { useAppStore } from '@/store/modules/app';
|
import { useAppStore } from '@/store/modules/app';
|
||||||
@ -41,6 +42,17 @@ const runningStatusOptions = ref<RunningStatusOption[]>([
|
|||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
type CancelModel = Api.Workflow.FlowInvalidOperateParams;
|
||||||
|
|
||||||
|
const cancelModel: CancelModel = reactive(createDefaultModel());
|
||||||
|
|
||||||
|
function createDefaultModel(): CancelModel {
|
||||||
|
return {
|
||||||
|
id: null,
|
||||||
|
comment: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// 基础列
|
// 基础列
|
||||||
const baseColumns = ref<NaiveUI.TableColumn<Api.Workflow.ProcessInstance>[]>([
|
const baseColumns = ref<NaiveUI.TableColumn<Api.Workflow.ProcessInstance>[]>([
|
||||||
{
|
{
|
||||||
@ -50,7 +62,7 @@ const baseColumns = ref<NaiveUI.TableColumn<Api.Workflow.ProcessInstance>[]>([
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'flowName',
|
key: 'flowName',
|
||||||
title: '流程定义名称',
|
title: '流程名称',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 120
|
width: 120
|
||||||
},
|
},
|
||||||
@ -62,7 +74,7 @@ const baseColumns = ref<NaiveUI.TableColumn<Api.Workflow.ProcessInstance>[]>([
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'flowCode',
|
key: 'flowCode',
|
||||||
title: '流程定义编码',
|
title: '流程编码',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
minWidth: 120
|
minWidth: 120
|
||||||
},
|
},
|
||||||
@ -70,7 +82,10 @@ const baseColumns = ref<NaiveUI.TableColumn<Api.Workflow.ProcessInstance>[]>([
|
|||||||
key: 'categoryName',
|
key: 'categoryName',
|
||||||
title: '流程分类',
|
title: '流程分类',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
minWidth: 120
|
minWidth: 120,
|
||||||
|
render(row) {
|
||||||
|
return <NTag type="default">{row.categoryName}</NTag>;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'createByName',
|
key: 'createByName',
|
||||||
@ -134,30 +149,34 @@ const operateColumns = ref<NaiveUI.TableColumn<Api.Workflow.ProcessInstance>[]>(
|
|||||||
width: 150,
|
width: 150,
|
||||||
render: row => {
|
render: row => {
|
||||||
const showAll = runningStatus.value;
|
const showAll = runningStatus.value;
|
||||||
|
const id = row.id;
|
||||||
return (
|
return (
|
||||||
<div class="flex-center gap-1px">
|
<div class="flex-center gap-1px">
|
||||||
{showAll && (
|
{showAll && [
|
||||||
<>
|
<ButtonIcon
|
||||||
<ButtonIcon
|
key="cancel"
|
||||||
text
|
text
|
||||||
type="error"
|
type="error"
|
||||||
icon="material-symbols:cancel-outline-rounded"
|
showPopconfirmIcon={false}
|
||||||
tooltipContent="作废流程"
|
icon="material-symbols:cancel-outline-rounded"
|
||||||
onClick={() => edit(row.id!)}
|
tooltipContent="作废流程"
|
||||||
/>
|
popconfirmContent={
|
||||||
<NDivider vertical />
|
<NInput v-model:value={cancelModel.comment} size="large" type="textarea" placeholder="请输入作废原因" />
|
||||||
<ButtonIcon
|
}
|
||||||
text
|
onPositiveClick={() => handleCancel(id)}
|
||||||
type="error"
|
/>,
|
||||||
icon="material-symbols:delete-outline"
|
<NDivider key="div1" vertical />,
|
||||||
tooltipContent={$t('common.delete')}
|
<ButtonIcon
|
||||||
popconfirmContent={$t('common.confirmDelete')}
|
key="delete"
|
||||||
onPositiveClick={() => handleDelete(row.id!)}
|
text
|
||||||
/>
|
type="error"
|
||||||
<NDivider vertical />
|
icon="material-symbols:delete-outline"
|
||||||
</>
|
tooltipContent={$t('common.delete')}
|
||||||
)}
|
popconfirmContent={$t('common.confirmDelete')}
|
||||||
|
onPositiveClick={() => handleDelete(id)}
|
||||||
|
/>,
|
||||||
|
<NDivider key="div2" vertical />
|
||||||
|
]}
|
||||||
<ButtonIcon text type="info" icon="material-symbols:visibility-outline" tooltipContent="流程预览" />
|
<ButtonIcon text type="info" icon="material-symbols:visibility-outline" tooltipContent="流程预览" />
|
||||||
<NDivider vertical />
|
<NDivider vertical />
|
||||||
<ButtonIcon text type="info" icon="material-symbols:variable-insert" tooltipContent="流程变量" />
|
<ButtonIcon text type="info" icon="material-symbols:variable-insert" tooltipContent="流程变量" />
|
||||||
@ -196,10 +215,10 @@ const {
|
|||||||
: [...baseColumns.value, ...finishColumns.value, ...operateColumns.value]
|
: [...baseColumns.value, ...finishColumns.value, ...operateColumns.value]
|
||||||
});
|
});
|
||||||
|
|
||||||
const { handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } = useTableOperate(data, getData);
|
const { checkedRowKeys, onBatchDeleted, onDeleted } = useTableOperate(data, getData);
|
||||||
// 监听运行状态变化
|
// 监听运行状态变化
|
||||||
watch(runningStatus, async () => {
|
watch(runningStatus, async () => {
|
||||||
const newApiFn = runningStatus.value ? fetchGetRunningProcessInstanceList : fetchGetFinishProcessInstanceList;
|
const newApiFn = runningStatus.value ? fetchGetRunningProcessInstanceList : fetchGetFinishedProcessInstanceList;
|
||||||
updateApiFn(newApiFn);
|
updateApiFn(newApiFn);
|
||||||
reloadColumns();
|
reloadColumns();
|
||||||
await getDataByPage();
|
await getDataByPage();
|
||||||
@ -256,8 +275,12 @@ async function handleDelete(instanceId: CommonType.IdType) {
|
|||||||
onDeleted();
|
onDeleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function edit(instanceId: CommonType.IdType) {
|
async function handleCancel(instanceId: CommonType.IdType) {
|
||||||
handleEdit('id', instanceId);
|
cancelModel.id = instanceId;
|
||||||
|
// request
|
||||||
|
const { error } = await fetchFlowInvalidOperate(cancelModel);
|
||||||
|
if (error) return;
|
||||||
|
getDataByPage();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -329,7 +352,7 @@ async function edit(instanceId: CommonType.IdType) {
|
|||||||
:data="data"
|
:data="data"
|
||||||
size="small"
|
size="small"
|
||||||
:flex-height="!appStore.isMobile"
|
:flex-height="!appStore.isMobile"
|
||||||
:scroll-x="1078"
|
:scroll-x="1400"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
remote
|
remote
|
||||||
:row-key="row => row.id"
|
:row-key="row => row.id"
|
||||||
@ -340,68 +363,3 @@ async function edit(instanceId: CommonType.IdType) {
|
|||||||
</div>
|
</div>
|
||||||
</TableSiderLayout>
|
</TableSiderLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.category-tree {
|
|
||||||
.n-button {
|
|
||||||
--n-padding: 8px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.n-tree__empty) {
|
|
||||||
height: 100%;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.n-spin-content) {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.infinite-scroll) {
|
|
||||||
height: calc(100vh - 228px - var(--calc-footer-height, 0px)) !important;
|
|
||||||
max-height: calc(100vh - 228px - var(--calc-footer-height, 0px)) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 1024px) {
|
|
||||||
:deep(.infinite-scroll) {
|
|
||||||
height: calc(100vh - 227px - var(--calc-footer-height, 0px)) !important;
|
|
||||||
max-height: calc(100vh - 227px - var(--calc-footer-height, 0px)) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.n-tree-node) {
|
|
||||||
height: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.n-tree-node-switcher) {
|
|
||||||
height: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.n-tree-node-switcher__icon) {
|
|
||||||
font-size: 16px !important;
|
|
||||||
height: 16px !important;
|
|
||||||
width: 16px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.n-data-table-wrapper),
|
|
||||||
:deep(.n-data-table-base-table),
|
|
||||||
:deep(.n-data-table-base-table-body) {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 800px) {
|
|
||||||
:deep(.n-data-table-base-table-body) {
|
|
||||||
max-height: calc(100vh - 400px - var(--calc-footer-height, 0px));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 802px) {
|
|
||||||
:deep(.n-data-table-base-table-body) {
|
|
||||||
max-height: calc(100vh - 473px - var(--calc-footer-height, 0px));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.n-card-header__main) {
|
|
||||||
min-width: 69px !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
Reference in New Issue
Block a user