From 46b2ae1c889e181ebe186de3758fc09804696029 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 23 七月 2026 09:54:23 +0800
Subject: [PATCH] feat(workorder): 工单工序列表支持拖拽排序功能
---
src/views/mes/pro/workorder/modules/process-list.vue | 112 +++++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 90 insertions(+), 22 deletions(-)
diff --git a/src/views/mes/pro/workorder/modules/process-list.vue b/src/views/mes/pro/workorder/modules/process-list.vue
index 6559581..35ac698 100644
--- a/src/views/mes/pro/workorder/modules/process-list.vue
+++ b/src/views/mes/pro/workorder/modules/process-list.vue
@@ -5,11 +5,13 @@
import type { MesProWorkOrderApi } from '#/api/mes/pro/workorder';
import type { MesProWorkOrderProcessApi } from '#/api/mes/pro/workorder/process';
-import { computed, ref, watch } from 'vue';
+import { computed, nextTick, onUnmounted, ref, watch } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { MesProWorkOrderStatusEnum } from '@vben/constants';
+import { IconifyIcon } from '@vben/icons';
+import { useSortable } from '@vueuse/integrations/useSortable';
import { message, Tag } from 'ant-design-vue';
import { TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
@@ -45,6 +47,9 @@
const isCreateMode = computed(() => props.formType === 'create');
+// 鎷栨嫿鎺掑簭
+const sortableInstance = ref<any>(null);
+
const [ProcessFormModal, processFormModalApi] = useVbenModal({
connectedComponent: ProcessForm,
destroyOnClose: true,
@@ -54,7 +59,7 @@
gridOptions: {
autoResize: true,
border: true,
- columns: useProcessGridColumns(),
+ columns: useProcessGridColumns(isEditable.value),
data: [],
minHeight: 240,
pagerConfig: { enabled: false },
@@ -63,6 +68,50 @@
toolbarConfig: { enabled: false },
} as VxeTableGridOptions<MesProWorkOrderProcessApi.WorkOrderProcess>,
});
+
+/** 鍒濆鍖�/閿�姣佹嫋鎷芥帓搴� */
+async function initSortable() {
+ destroySortable();
+ if (!isEditable.value || list.value.length === 0) return;
+ await nextTick();
+ sortableInstance.value = useSortable(
+ '.workorder-process-list .vxe-table--body-wrapper:not(.fixed-right--wrapper) .vxe-table--body tbody',
+ list.value,
+ {
+ animation: 150,
+ draggable: '.vxe-body--row',
+ handle: '.drag-handle',
+ onEnd: ({ newDraggableIndex, oldDraggableIndex }) => {
+ if (
+ newDraggableIndex !== undefined &&
+ oldDraggableIndex !== undefined &&
+ oldDraggableIndex !== newDraggableIndex
+ ) {
+ // 閲嶆柊鎺掑簭鏁扮粍
+ list.value.splice(
+ newDraggableIndex,
+ 0,
+ list.value.splice(oldDraggableIndex, 1)[0]!,
+ );
+ // 鏇存柊 sort 瀛楁
+ list.value.forEach((item, index) => {
+ item.sort = index + 1;
+ });
+ gridApi.setGridOptions({ data: list.value });
+ emit('processListChange', list.value);
+ }
+ },
+ },
+ );
+}
+
+/** 閿�姣佹嫋鎷芥帓搴忓疄渚� */
+function destroySortable() {
+ if (sortableInstance.value) {
+ sortableInstance.value.stop?.();
+ sortableInstance.value = null;
+ }
+}
/** 鍔犺浇宸ュ簭鍒楄〃 */
async function getList() {
@@ -106,6 +155,8 @@
}
gridApi.setGridOptions({ data: list.value });
emit('processListChange', list.value);
+ // 鍒濆鍖栨嫋鎷芥帓搴�
+ initSortable();
} finally {
gridApi.setLoading(false);
}
@@ -135,25 +186,6 @@
.open();
}
-/** 鍒犻櫎宸ュ簭 */
-function handleDelete(row: MesProWorkOrderProcessApi.WorkOrderProcess) {
- if (isCreateMode.value) {
- // 鏂板妯″紡锛氫粠鍒楄〃鍒犻櫎
- const index = list.value.findIndex((item) => item.processId === row.processId);
- if (index > -1) {
- list.value.splice(index, 1);
- gridApi.setGridOptions({ data: list.value });
- emit('processListChange', list.value);
- }
- } else {
- // 缂栬緫妯″紡锛氳皟鐢ㄦ帴鍙e垹闄�
- deleteWorkOrderProcess(row.id!).then(() => {
- message.success($t('ui.actionMessage.deleteSuccess', [row.processName]));
- getList();
- });
- }
-}
-
/** 鏂板/缂栬緫鎴愬姛鍥炶皟 */
function handleFormSuccess(data: MesProWorkOrderProcessApi.WorkOrderProcess, isEdit: boolean) {
if (isCreateMode.value) {
@@ -167,10 +199,40 @@
}
gridApi.setGridOptions({ data: list.value });
emit('processListChange', list.value);
+ initSortable();
} else {
getList();
}
}
+
+/** 鍒犻櫎宸ュ簭 */
+function handleDelete(row: MesProWorkOrderProcessApi.WorkOrderProcess) {
+ if (isCreateMode.value) {
+ // 鏂板妯″紡锛氫粠鍒楄〃鍒犻櫎
+ const index = list.value.findIndex((item) => item.processId === row.processId);
+ if (index > -1) {
+ list.value.splice(index, 1);
+ // 鏇存柊 sort 瀛楁
+ list.value.forEach((item, idx) => {
+ item.sort = idx + 1;
+ });
+ gridApi.setGridOptions({ data: list.value });
+ emit('processListChange', list.value);
+ initSortable();
+ }
+ } else {
+ // 缂栬緫妯″紡锛氳皟鐢ㄦ帴鍙e垹闄�
+ deleteWorkOrderProcess(row.id!).then(() => {
+ message.success($t('ui.actionMessage.deleteSuccess', [row.processName]));
+ getList();
+ });
+ }
+}
+
+// 缁勪欢鍗歌浇鏃堕攢姣佹帓搴忓疄渚�
+onUnmounted(() => {
+ destroySortable();
+});
// 鐩戝惉浜у搧/宸ュ崟鍙樺寲
watch(
@@ -183,7 +245,7 @@
</script>
<template>
- <div>
+ <div class="workorder-process-list">
<ProcessFormModal @success="handleFormSuccess" />
<div v-if="isEditable" class="mb-3 flex items-center justify-start">
<TableAction
@@ -197,6 +259,12 @@
/>
</div>
<Grid class="w-full" table-title="宸ュ簭">
+ <template #dragHandle>
+ <IconifyIcon
+ icon="ic:round-drag-indicator"
+ class="drag-handle cursor-move text-xl text-gray-400"
+ />
+ </template>
<template #keyFlag="{ row }">
<Tag v-if="row.keyFlag" color="red">鍏抽敭</Tag>
<span v-else>-</span>
--
Gitblit v1.9.3