123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 |
- <template>
- <div class="list_group_container">
- <div v-if="!hideAddInput" class="group_list">
- <div class="group_header flex flex-pack-justify items-center">
- <div class="group_header_title">
- <span>
- <el-input v-model="listGroupName" v-autoFocus placeholder="请输入流程组名称" @blur="addFlowGroup" />
- </span>
- </div>
- </div>
- </div>
- <draggable
- v-bind="dragOptions"
- v-model="categoryList"
- handle=".group_header"
- item-key="categoryId"
- @update:model-value="update_item_categoryList"
- >
- <template #item="{ element: item, index }">
- <div class="group_list">
- <div class="group_header flex flex-pack-justify items-center px-4">
- <div class="group_header_title">
- <span>
- <template v-if="!item.editor">
- {{ item.categoryName }}
- </template>
- <template v-else>
- <el-input v-model="item.categoryName" v-autoFocus placeholder="请输入流程组名称" @blur="editFlowGroup('save', item, index)" />
- </template>
- </span>
- </div>
- <div class="group_header_nameOperate">
- <LeIcon
- class="text-lg text-icon-color cursor-pointer"
- icon-class="icon-processInfo-mage--edit"
- @click="editFlowGroup('edit', item, index)"
- />
- <el-tooltip effect="dark" content="删除" placement="top">
- <LeIcon
- class="text-lg ml-2 text-rose-700 cursor-pointer"
- icon-class="icon-processInfo-iconoir--trash"
- @click="deleteFlowGroup(item)"
- />
- </el-tooltip>
- </div>
- </div>
- <div class="group_body">
- <draggable
- v-model="item.processList"
- v-bind="dragOptions"
- group="categoryId"
- tag="ul"
- class="group_list_ul"
- :component-data="{
- type: 'transition-group',
- name: !drag ? 'flip-list' : null
- }"
- item-key="processId"
- @update:model-value="update_item_processList"
- @start="drag = true"
- @end="drag = false"
- >
- <template #item="{ element }">
- <li class="group_item">
- <el-row :gutter="5">
- <el-col :span="5" :xs="7">
- <div class="flex items-center h-[42px]">
- <LeIcon class="group_itemIcon text-[2rem]" :icon-class="`${flowIconPrefix}${element.processIcon}`" />
- <div class="truncate pr-2">
- <div class="group_itemNameWrapper flex items-center">
- <div class="group_itemName">
- <span :title="element.processName">{{ element.processName }}</span>
- </div>
- </div>
- <div class="group_itemIntro" :title="element.title">
- {{ element.title }}
- </div>
- </div>
- </div>
- </el-col>
- <el-col :span="15" :xs="9">
- <div class="flex items-center" style="height: 42px">
- <div class="flex-1">
- <el-tag size="small" round>V{{ element.processVersion }}</el-tag>
- <el-tag v-if="element.processType === 'child'" type="warning" round class="ml-1" size="small">子流程</el-tag>
- <el-tag v-if="element.processType === 'business'" type="success" round class="ml-1" size="small">业务流程</el-tag>
- <el-tag v-if="element.processState === 0" type="danger" round class="ml-1" size="small">已停用</el-tag>
- </div>
- <div class="flex-1 max-m:hidden">{{ element.processKey }}</div>
- </div>
- </el-col>
- <el-col :span="4" :xs="8">
- <div class="group_itemOperations flex flex-pack-end items-center pr-1" style="height: 42px">
- <el-tooltip effect="dark" content="版本控制" placement="top">
- <LeIcon
- v-if="element.processVersion > 1"
- class="text-lg ml-2 text-icon-color cursor-pointer"
- icon-class="icon-processInfo-hugeicons--git-merge"
- @click="historyEv(element)"
- />
- </el-tooltip>
- <el-tooltip effect="dark" content="编辑" placement="top">
- <LeIcon
- class="text-lg ml-2 text-icon-color cursor-pointer"
- icon-class="icon-processInfo-mage--edit"
- @click="updateEv(element)"
- />
- </el-tooltip>
- <el-tooltip content="复制" placement="top" effect="dark">
- <LeIcon
- class="text-lg ml-2 text-icon-color cursor-pointer"
- icon-class="icon-processInfo-lucide--copy"
- @click="copyEv(element)"
- />
- </el-tooltip>
- <el-tooltip v-if="element.processState === 1" effect="dark" content="禁用" placement="top">
- <LeIcon
- class="text-lg ml-2 text-icon-color cursor-pointer"
- icon-class="icon-processInfo-solar--forbidden-circle-broken"
- @click="enabledEv(element, 0)"
- />
- </el-tooltip>
- <el-tooltip v-if="element.processState === 0" effect="dark" content="启用" placement="top">
- <LeIcon
- class="text-lg ml-2 text-icon-color cursor-pointer"
- icon-class="icon-processInfo-heroicons--lock-open"
- @click="enabledEv(element, 1)"
- />
- </el-tooltip>
- <el-tooltip content="删除" placement="top" effect="dark">
- <LeIcon
- class="text-lg ml-2 text-rose-700 cursor-pointer"
- icon-class="icon-processInfo-iconoir--trash"
- @click="stopEv(element)"
- />
- </el-tooltip>
- </div>
- </el-col>
- </el-row>
- </li>
- </template>
- </draggable>
- </div>
- </div>
- </template>
- </draggable>
- <!-- 历史流程签出 -->
- <history-process-list
- v-if="visibleHistory"
- ref="historyDialog"
- v-model="visibleHistory"
- :item="currentProcess"
- @success-fn="flowGroupListAll"
- ></history-process-list>
- </div>
- </template>
- <script lang="tsx" setup>
- import Draggable from 'vuedraggable'
- // import { Delete, CircleClose, EditPen } from '@element-plus/icons-vue'
- import { ref, onActivated, nextTick, onMounted } from 'vue'
- import flowGroup from '@/api/flow/group'
- import flowDefinition from '@/api/flow/definition'
- import { ElMessage, ElMessageBox } from 'element-plus'
- import process from '@/api/flow/process'
- import router from '@/router'
- import { debounce, flowIconPrefix /*, getAssetsFile*/ } from '@/utils/index'
- import HistoryProcessList from './historyProcessList.vue'
- const categoryList = ref<any[]>([])
- const hideAddInput = ref(true)
- const visibleHistory = ref(false)
- const currentProcess = ref({})
- const listGroupName = ref('')
- const dragOptions = {
- animation: 200,
- group: 'processId',
- disabled: false,
- ghostClass: 'ghost'
- }
- const drag = ref(false)
- // 显示隐藏添加流程组元素
- const showAddInput = () => {
- hideAddInput.value = !hideAddInput.value
- }
- // 新增流程组
- const addFlowGroup = async () => {
- if (!listGroupName.value.trim()) {
- showAddInput()
- return false
- }
- try {
- const param = {
- name: listGroupName.value,
- sort: 0
- }
- await flowGroup.flowGroupAddOrEditSaveApi(param)
- showAddInput()
- flowGroupListAll()
- } catch (e) {
- console.log(e)
- }
- }
- const update_categoryListSort = debounce(() => {
- // console.error('刷新数据........', xxx)
- // {categoryId:string; processIds: string[]}[]
- flowDefinition.updateProcessSortApi(
- categoryList.value.map(v => ({
- categoryId: v.categoryId,
- processIds: v.processList && v.processList.length ? v.processList.map(_v => _v.processId) : undefined
- }))
- )
- /*.then(res => {
- console.warn(res, 'res......')
- })*/
- }, 50)
- const update_item_categoryList = (values: any[]) => {
- // console.warn(values, 'values update_item_categoryList', categoryList.value)
- update_categoryListSort()
- }
- const update_item_processList = (values: any[]) => {
- // console.warn(values, 'values update_item_processList', categoryList.value)
- update_categoryListSort()
- }
- // 流程组列表
- const flowGroupListAll = async (item = {}) => {
- try {
- const data: any = await flowDefinition.flowDefinitionListCategoryApi(item)
- categoryList.value = data || []
- console.log(data)
- } catch (e) {
- console.log(e)
- }
- }
- // 流程组删除
- const deleteFlowGroup = (item: any) => {
- try {
- // todo 这里需要判断当前的流程组下是否有实例,有不能删除,没有 直接调用删除接口
- ElMessageBox.confirm('是否删除该分组?', '提示', {
- confirmButtonText: '确认',
- cancelButtonText: '取消',
- type: 'error',
- buttonSize: 'default'
- })
- .then(async () => {
- await flowGroup.flowGroupDeleteApi([item.categoryId])
- flowGroupListAll()
- ElMessage({
- message: '删除成功!',
- type: 'success'
- })
- })
- .catch(() => {
- console.log('取消')
- })
- } catch (e) {
- console.log(e)
- }
- }
- /**
- * 编辑流程组函数
- *
- * @param type 操作类型,'edit'表示编辑,其他表示保存
- * @param item 当前项
- * @param idx 当前项的索引
- * @returns 如果type为'edit',则返回false;否则返回undefined
- */
- const editFlowGroup = async (type, item, idx) => {
- if (type === 'edit') {
- categoryList.value[idx].editor = true
- return false
- }
- try {
- categoryList.value[idx].editor = false
- const param = {
- id: categoryList.value[idx].categoryId,
- name: categoryList.value[idx].categoryName
- // sort: categoryList.value[idx].categorySort
- }
- await flowGroup.flowGroupAddOrEditSaveApi(param)
- flowGroupListAll()
- } catch (e) {
- console.log(e)
- }
- }
- // 删除
- const stopEv = (ele: any) => {
- ElMessageBox.confirm(`确认删除「${ele.processName}」流程?`, '提示', {
- confirmButtonText: '确认',
- cancelButtonText: '取消',
- type: 'error'
- }).then(async () => {
- await process.progressDeleteApi({ id: ele.processId })
- flowGroupListAll()
- })
- }
- /**
- * 启用/禁用事件处理函数
- *
- * @param id 要启用/禁用的元素的ID
- * @param state 启用/禁用的状态,1表示启用,0表示禁用
- * @returns 无返回值,执行异步操作
- */
- const enabledEv = async (ele: any, state: number) => {
- ElMessageBox.confirm(`您即将${state === 1 ? '启用' : '禁用'}「${ele.processName}」流程,是否确认?`, '提示', {
- confirmButtonText: '确认',
- cancelButtonText: '取消',
- type: 'warning'
- }).then(async () => {
- await process.processUpdateStateApi({ id: ele.processId, state: state })
- ElMessage.success('操作成功')
- flowGroupListAll()
- })
- }
- /**
- * 复制事件处理函数
- *
- * @returns 无返回值,执行异步操作
- */
- const copyEv = (ele: any) => {
- ElMessageBox.confirm(`您即将复制「${ele.processName}」流程,是否确认?`, '提示', {
- confirmButtonText: '确认',
- cancelButtonText: '取消',
- type: 'info'
- }).then(async () => {
- await process.progressCloneApi({ id: ele.processId })
- flowGroupListAll()
- })
- }
- // 修改
- const updateEv = async (element: any) => {
- const jumpRouterUrl = '/flow_create/' + (element.processType === 'main' ? 'index' : element.processType)
- router.push(`${jumpRouterUrl}?id=${element.processId}`)
- }
- // 打开当前流程的历史版本
- const historyEv = (element: any) => {
- currentProcess.value = element
- visibleHistory.value = !visibleHistory.value
- }
- // keep-alive缓存树,防止创建完流程过后,回到当前窗口未刷新
- onActivated(() => {
- flowGroupListAll()
- })
- /**
- * 当组件被挂载到 DOM 后,执行回调函数
- */
- onMounted(() => {
- nextTick(() => {
- flowGroupListAll()
- })
- })
- // 父组件使用的话需要导出
- defineExpose({
- showAddInput,
- searchProcessEv: flowGroupListAll
- })
- </script>
- <style scoped lang="scss">
- .list_group_container {
- // 同sortGroup一样的样式
- .group_list {
- border-radius: 4px;
- margin-bottom: 16px;
- box-shadow: var(--el-box-shadow-lighter);
- background-color: var(--el-bg-color);
- .group_header {
- height: 54px;
- //padding: 0px 16px 0px 12px;
- font-size: 16px;
- line-height: 24px;
- background-color: var(--el-fill-color-light);
- &_title {
- position: relative;
- font-family: PingFangSC-Medium;
- display: flex;
- align-items: center;
- &.disabled {
- color: var(--el-text-color-disabled);
- }
- .edit_line {
- display: inline-block;
- width: 200px;
- border: 1px solid var(--el-text-color-primary);
- visibility: hidden;
- height: 36px;
- position: absolute;
- left: -5px;
- }
- .edit_icon {
- right: -170px;
- visibility: hidden;
- }
- &:hover {
- .edit_line,
- .edit_icon {
- visibility: visible;
- }
- }
- }
- &_nameOperate {
- cursor: pointer;
- }
- }
- .group_body,
- .group_list_ul {
- box-sizing: border-box;
- padding: 0;
- //width: 1000px;
- }
- .group_item {
- padding: 8px 12px;
- &:not(.group_item-disabled):hover {
- background-color: var(--el-fill-color-lighter);
- }
- .group_itemIcon {
- flex-shrink: 0;
- margin-right: 8px;
- //height: 42px;
- //width: 42px;
- border-radius: 50%;
- overflow: hidden;
- //font-size: 42px;
- /*img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- }*/
- }
- .group_itemLeft {
- padding-right: 8px;
- }
- .group_itemOperations {
- cursor: pointer;
- .le-icon {
- flex-shrink: 0;
- }
- }
- .group_itemIntro {
- font-size: 14px;
- text-overflow: ellipsis;
- overflow: hidden;
- white-space: nowrap;
- line-height: 17px;
- font-family: PingFangSC-Regular;
- }
- .group_itemNameWrapper {
- justify-content: flex-start;
- }
- .group_itemName {
- max-width: 418px;
- font-size: 14px;
- text-overflow: ellipsis;
- overflow: hidden;
- white-space: nowrap;
- line-height: 16px;
- font-weight: 500;
- font-family: PingFangSC-Medium;
- }
- }
- }
- .ghost {
- opacity: 0.5;
- box-shadow: 1px 1px 5px 2px rgba(0, 0, 0, 0.15);
- }
- }
- </style>
|