Commit b056db55 by GoldenZqqqq

feat: 分类表格拖拽排序功能实现

parent 9dc268ef
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
"pinia-plugin-persistedstate": "^3.2.1", "pinia-plugin-persistedstate": "^3.2.1",
"qrcode": "^1.5.3", "qrcode": "^1.5.3",
"qs": "^6.12.0", "qs": "^6.12.0",
"sortablejs": "^1.15.3",
"steady-xml": "^0.1.0", "steady-xml": "^0.1.0",
"url": "^0.11.3", "url": "^0.11.3",
"video.js": "^7.21.5", "video.js": "^7.21.5",
......
<template> <template>
<ContentWrap>
<div class="flex justify-between pl-20px items-center">
<h3 class="font-extrabold">表单管理</h3>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px flex"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item align="right" prop="key" class="ml-auto">
<el-input
v-model="queryParams.key"
placeholder="搜索流程"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
>
<template #prefix>
<Icon icon="ep:search" class="mx-10px" />
</template>
</el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="openForm('create')" v-hasPermi="['bpm:model:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新建流程
</el-button>
</el-form-item>
<el-form-item>
<el-dropdown placement="bottom-end">
<el-button class="w-30px" plain>
<Icon icon="ep:setting" />
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<Icon icon="ep:circle-plus" size="13" class="mr-5px" />
新建分组
</el-dropdown-item>
<el-dropdown-item>
<Icon icon="fa:sort-amount-desc" size="13" class="mr-5px" />
分组排序
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-form-item>
</el-form>
</div>
<el-divider />
<!-- 分类卡片组 -->
<div class="px-15px">
<ContentWrap :body-style="{ padding: 0 }" v-for="(list, title) in categoryGroup" :key="title">
<!-- 默认使其全部展开 --> <!-- 默认使其全部展开 -->
<el-collapse :modelValue="title"> <el-collapse :modelValue="title">
<el-collapse-item :name="title"> <el-collapse-item :name="title">
...@@ -67,6 +10,7 @@ ...@@ -67,6 +10,7 @@
<Icon icon="ep:arrow-down-bold" color="#999" /> <Icon icon="ep:arrow-down-bold" color="#999" />
</div> </div>
<div class="ml-auto mr-30px"> <div class="ml-auto mr-30px">
<template v-if="!isSorting">
<el-button link type="info" class="mr-10px" @click.stop="handleSort"> <el-button link type="info" class="mr-10px" @click.stop="handleSort">
<Icon icon="fa:sort-amount-desc" class="mr-5px" /> <Icon icon="fa:sort-amount-desc" class="mr-5px" />
排序 排序
...@@ -75,23 +19,35 @@ ...@@ -75,23 +19,35 @@
<Icon icon="ep:setting" class="mr-5px" /> <Icon icon="ep:setting" class="mr-5px" />
分组 分组
</el-button> </el-button>
</template>
<template v-else>
<el-button @click.stop="cancelSort"> 取 消 </el-button>
<el-button type="primary" @click.stop="saveSort"> 保存排序 </el-button>
</template>
</div> </div>
</template> </template>
<template #title> <template #title>
<div class="flex items-center"> <div class="flex items-center">
<h3 class="ml-20px mr-8px text-18px">{{ title }}</h3> <h3 class="ml-20px mr-8px text-18px">{{ title }}</h3>
<div class="color-gray-600 text-16px"> ({{ list?.length || 0 }}) </div> <div class="color-gray-600 text-16px"> ({{ dataList?.length || 0 }}) </div>
</div> </div>
</template> </template>
<el-table <el-table
:class="title"
ref="tableRef"
:header-cell-style="{ backgroundColor: isDark ? '' : '#edeff0' }" :header-cell-style="{ backgroundColor: isDark ? '' : '#edeff0' }"
v-loading="loading" :data="dataList"
:data="list"
> >
<el-table-column label="流程名" prop="name" min-width="150"> <el-table-column label="流程名" prop="name" min-width="150">
<template #default="scope"> <template #default="scope">
<div class="flex items-center"> <div class="flex items-center">
<el-tooltip content="拖动排序" v-if="isSorting">
<Icon
icon="ic:round-drag-indicator"
class="drag-icon cursor-move text-#8a909c mr-10px"
/>
</el-tooltip>
<el-image :src="scope.row.icon" class="h-32px w-32px mr-10px rounded" /> <el-image :src="scope.row.icon" class="h-32px w-32px mr-10px rounded" />
{{ scope.row.name }} {{ scope.row.name }}
</div> </div>
...@@ -112,8 +68,7 @@ ...@@ -112,8 +68,7 @@
placement="top" placement="top"
:content="scope.row.startUsers.map((user: any) => user.nickname).join('、')" :content="scope.row.startUsers.map((user: any) => user.nickname).join('、')"
> >
{{ scope.row.startUsers[0].nickname }} {{ scope.row.startUsers[0].nickname }}{{ scope.row.startUsers.length }} 人可见
{{ scope.row.startUsers.length }} 人可见
</el-tooltip> </el-tooltip>
</el-text> </el-text>
</template> </template>
...@@ -191,11 +146,7 @@ ...@@ -191,11 +146,7 @@
<el-dropdown <el-dropdown
class="!align-middle ml-5px" class="!align-middle ml-5px"
@command="(command) => handleCommand(command, scope.row)" @command="(command) => handleCommand(command, scope.row)"
v-hasPermi="[ v-hasPermi="['bpm:process-definition:query', 'bpm:model:update', 'bpm:model:delete']"
'bpm:process-definition:query',
'bpm:model:update',
'bpm:model:delete'
]"
> >
<el-button type="primary" link>更多</el-button> <el-button type="primary" link>更多</el-button>
<template #dropdown> <template #dropdown>
...@@ -229,69 +180,37 @@ ...@@ -229,69 +180,37 @@
</el-table> </el-table>
</el-collapse-item> </el-collapse-item>
</el-collapse> </el-collapse>
</ContentWrap>
</div>
</ContentWrap>
<!-- 表单弹窗:添加/修改流程 -->
<ModelForm ref="formRef" @success="getList" />
<!-- 弹窗:表单详情 -->
<Dialog title="表单详情" v-model="formDetailVisible" width="800">
<form-create :rule="formDetailPreview.rule" :option="formDetailPreview.option" />
</Dialog>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
// 拖拽组件
import Sortable from 'sortablejs'
import { propTypes } from '@/utils/propTypes'
import { formatDate } from '@/utils/formatTime' import { formatDate } from '@/utils/formatTime'
import * as ModelApi from '@/api/bpm/model' import * as ModelApi from '@/api/bpm/model'
import * as FormApi from '@/api/bpm/form' import * as FormApi from '@/api/bpm/form'
import ModelForm from './ModelForm.vue'
import { setConfAndFields2 } from '@/utils/formCreate' import { setConfAndFields2 } from '@/utils/formCreate'
import { CategoryApi } from '@/api/bpm/category'
import { BpmModelType } from '@/utils/constants' import { BpmModelType } from '@/utils/constants'
import { checkPermi } from '@/utils/permission' import { checkPermi } from '@/utils/permission'
import { useUserStoreWithOut } from '@/store/modules/user' import { useUserStoreWithOut } from '@/store/modules/user'
import { useAppStore } from '@/store/modules/app' import { useAppStore } from '@/store/modules/app'
import { groupBy } from 'lodash-es' import { cloneDeep } from 'lodash-es'
defineOptions({ name: 'BpmModel' }) defineOptions({ name: 'BpmModel' })
const props = defineProps({
// 分类后的数据
dataList: propTypes.object.def([]),
title: propTypes.string.def('')
})
const emit = defineEmits(['success'])
const appStore = useAppStore() const appStore = useAppStore()
const message = useMessage() // 消息弹窗 const message = useMessage() // 消息弹窗
const isDark = computed(() => appStore.getIsDark) const isDark = computed(() => appStore.getIsDark)
const { t } = useI18n() // 国际化 const { t } = useI18n() // 国际化
const { push } = useRouter() // 路由 const { push } = useRouter() // 路由
const userStore = useUserStoreWithOut() // 用户信息缓存 const userStore = useUserStoreWithOut() // 用户信息缓存
const loading = ref(true) // 列表的加载中 const isSorting = ref(false) // 是否正处于排序状态
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
key: undefined,
name: undefined,
category: undefined
})
const queryFormRef = ref() // 搜索的表单
const categoryList = ref([]) // 流程分类列表
const categoryGroup = ref<any>({}) // 按照category分组的数据
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
// TODO 芋艿:这里需要一个不分页查全部的流程模型接口
const data = await ModelApi.getModelPage(queryParams)
categoryGroup.value = groupBy(data.list, 'categoryName')
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** '更多'操作按钮 */ /** '更多'操作按钮 */
const handleCommand = (command: string, row: any) => { const handleCommand = (command: string, row: any) => {
...@@ -325,7 +244,7 @@ const handleDelete = async (row: any) => { ...@@ -325,7 +244,7 @@ const handleDelete = async (row: any) => {
await ModelApi.deleteModel(row.id) await ModelApi.deleteModel(row.id)
message.success(t('common.delSuccess')) message.success(t('common.delSuccess'))
// 刷新列表 // 刷新列表
await getList() emit('success')
} catch {} } catch {}
} }
...@@ -344,7 +263,7 @@ const handleChangeState = async (row: any) => { ...@@ -344,7 +263,7 @@ const handleChangeState = async (row: any) => {
await ModelApi.updateModelState(id, newState) await ModelApi.updateModelState(id, newState)
message.success(statusState + '成功') message.success(statusState + '成功')
// 刷新列表 // 刷新列表
await getList() emit('success')
} catch {} } catch {}
} }
...@@ -376,7 +295,7 @@ const handleDeploy = async (row: any) => { ...@@ -376,7 +295,7 @@ const handleDeploy = async (row: any) => {
await ModelApi.deployModel(row.id) await ModelApi.deployModel(row.id)
message.success(t('部署成功')) message.success(t('部署成功'))
// 刷新列表 // 刷新列表
await getList() emit('success')
} catch {} } catch {}
} }
...@@ -418,19 +337,48 @@ const isManagerUser = (row: any) => { ...@@ -418,19 +337,48 @@ const isManagerUser = (row: any) => {
/* 排序 */ /* 排序 */
const handleSort = () => { const handleSort = () => {
console.log('排序') isSorting.value = true
initSort()
}
const saveSort = () => {
// 接口调用
console.log(tableData.value)
cancelSort()
}
const cancelSort = () => {
isSorting.value = false
} }
/* 分组 */ /* 分组 */
const handleGroup = () => { const handleGroup = () => {
console.log('分组') console.log('分组')
} }
const tableRef = ref()
/** 初始化 **/ // 创建拖拽实例
onMounted(async () => { const initSort = () => {
await getList() const table = document.querySelector(`.${props.title} .el-table__body-wrapper tbody`)
// 查询流程分类列表 Sortable.create(table, {
categoryList.value = await CategoryApi.getCategorySimpleList() group: 'shared',
animation: 150,
draggable: '.el-table__row',
handle: '.drag-icon',
// 结束拖动事件
onEnd: ({ newDraggableIndex, oldDraggableIndex }) => {
if (oldDraggableIndex !== newDraggableIndex) {
tableData.value.splice(
newDraggableIndex,
0,
tableData.value.splice(oldDraggableIndex, 1)[0]
)
}
}
})
}
const tableData: any = ref([])
onMounted(() => {
tableData.value = cloneDeep(props.dataList)
}) })
</script> </script>
......
export const mockData = [
{
key: 'out_apply',
name: '外出申请',
description: null,
category: '1',
categoryName: '测试1',
formType: 20,
formId: null,
formCustomCreatePath: '/OA/goingOut/create',
formCustomViewPath: '/OA/goingOut/detail',
id: 'ff8f8bab-4d4e-11ef-8201-0242ac130002',
formName: null,
createTime: 1722218716216,
processDefinition: {
id: 'out_apply:4:7f56d464-4eec-11ef-8c3a-0242ac130002',
version: 4,
deploymentTime: 1722396312641,
suspensionState: 1
}
},
{
key: 'contract_change_history',
name: '合同变更申请',
description: null,
category: '2',
categoryName: '测试2',
formType: 20,
formId: null,
formCustomCreatePath: '/project/changeRecord/detail',
formCustomViewPath: '/project/changeRecord/detail',
id: '0c689067-3a92-11ef-b7f0-0242ac130002',
formName: null,
createTime: 1720158441959,
processDefinition: {
id: 'contract_change_history:1:f69fff4f-3a9a-11ef-b7f0-0242ac130002',
version: 1,
deploymentTime: 1720162270788,
suspensionState: 1
}
},
{
key: 'expenses_claim',
name: '费用报销申请',
description: null,
category: '1',
categoryName: '测试1',
formType: 20,
formId: null,
formCustomCreatePath: '/finance/reimbursement/detail',
formCustomViewPath: '/finance/reimbursement/detail',
id: '0310ad0c-351e-11ef-a653-0242ac130002',
formName: null,
createTime: 1719558848849,
processDefinition: {
id: 'expenses_claim:5:a043a1d8-4eec-11ef-8c3a-0242ac130002',
version: 5,
deploymentTime: 1722396367911,
suspensionState: 1
}
},
{
key: 'out_business_apply',
name: '申请单',
description: null,
category: '2',
categoryName: '测试2',
formType: 20,
formId: null,
formCustomCreatePath: '/finance/businessTripApply/detail',
formCustomViewPath: '/finance/businessTripApply/detail',
id: '279e27a4-3393-11ef-8401-0242ac130002',
formName: null,
createTime: 1719389258966,
processDefinition: {
id: 'out_business_apply:9:a7b2d4e2-430f-11ef-876f-0242ac130002',
version: 9,
deploymentTime: 1721091998780,
suspensionState: 1
}
},
{
key: 'pms_project_delay_application',
name: '项目延时申请',
description: null,
category: '2',
categoryName: '测试2',
formType: 20,
formId: null,
formCustomCreatePath: '/project/workHourDelay/create',
formCustomViewPath: '/project/workHourDelay/detail',
id: '46d87275-27c7-11ef-b258-0242ac130002',
formName: null,
createTime: 1718092231234,
processDefinition: {
id: 'b7ed308a-430f-11ef-876f-0242ac130002',
version: 5,
deploymentTime: 1721092026059,
suspensionState: 1
}
},
{
key: 'pms_project_result_approval',
name: '项目成果审核',
description: null,
category: '2',
categoryName: '测试2',
formType: 20,
formId: null,
formCustomCreatePath: '/project/projectTaskResult/detail',
formCustomViewPath: '/project/projectTaskResult/detail',
id: '4a15d4f8-23cc-11ef-8dd0-0242ac130002',
formName: null,
createTime: 1717654579502,
processDefinition: {
id: 'dd3cc360-4eec-11ef-8c3a-0242ac130002',
version: 6,
deploymentTime: 1722396470232,
suspensionState: 1
}
},
{
key: 'pms_contract',
name: '合同管理',
description: null,
category: '2',
categoryName: '测试2',
formType: 20,
formId: null,
formCustomCreatePath: '/sales/contract/create',
formCustomViewPath: '/sales/contract/detail',
id: '8317cb71-0d1a-11ef-8445-70b5e844a623',
formName: null,
createTime: 1715159299146,
processDefinition: {
id: 'pms_contract:5:c7d6012a-29f2-11ef-a08d-0242ac130002',
version: 5,
deploymentTime: 1718330818270,
suspensionState: 1
}
},
{
key: 'pms_consult_task_act',
name: '咨询任务书',
description: null,
category: '1',
categoryName: '测试1',
formType: 20,
formId: null,
formCustomCreatePath: '/consultTask/create',
formCustomViewPath: '/consultTask/detail',
id: '47fad8e4-0b91-11ef-b841-70b5e844a623',
formName: null,
createTime: 1714990407756,
processDefinition: {
id: 'pms_consult_task_act:1:67c2ae59-0b91-11ef-b841-70b5e844a623',
version: 1,
deploymentTime: 1714990460960,
suspensionState: 1
}
},
{
key: 'pms_project',
name: '立项管理',
description: null,
category: '1',
categoryName: '测试1',
formType: 20,
formId: null,
formCustomCreatePath: '/project/applyProject/create',
formCustomViewPath: '/project/applyProject/detail',
id: 'f0ba6bde-0b90-11ef-b841-70b5e844a623',
formName: null,
createTime: 1714990261372,
processDefinition: {
id: 'pms_project:6:b9e4e33b-2c6c-11ef-8386-0242ac130002',
version: 6,
deploymentTime: 1718603095738,
suspensionState: 1
}
},
{
key: 'invoice_apply_manage',
name: '开票申请',
description: 'asdas',
category: '1',
categoryName: '测试1',
formType: 20,
formId: null,
formCustomCreatePath: '/sales/invoice/create',
formCustomViewPath: '/sales/invoice/detail',
id: '7ec07575-0605-11ef-ab76-cc96e508c010',
formName: null,
createTime: 1714380614292,
processDefinition: {
id: 'invoice_apply_manage:8:665a8c40-44c9-11ef-9813-0242ac130002',
version: 8,
deploymentTime: 1721281726671,
suspensionState: 1
}
}
]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment