<script lang="ts" setup>
|
import type { ScrollActionType } from '@jnpf/ui';
|
|
import { computed, nextTick, onMounted, reactive, ref, toRefs, unref, watch } from 'vue';
|
|
import { useMessage } from '@jnpf/hooks';
|
import { ScrollContainer } from '@jnpf/ui';
|
import { BasicForm, useForm } from '@jnpf/ui/form';
|
|
import { useUserStore } from '@vben/stores';
|
|
import { getAuthSystemList } from '#/api/system/system';
|
import { getFlowSelector, setCollectFlow } from '#/api/workFlow/template';
|
import { $t } from '#/locales';
|
import { useBaseStore } from '#/store';
|
import { getRealJnpfAppEnCode } from '#/utils/jnpf';
|
|
interface State {
|
[prop: string]: any;
|
}
|
const props = defineProps({
|
flowType: { type: Number, default: 0 },
|
});
|
const emit = defineEmits(['select']);
|
const userStore = useUserStore();
|
const getUserInfo: any = computed(() => userStore.getUserInfo || {});
|
const isWorkFlow = computed(() => getRealJnpfAppEnCode() === 'workFlow');
|
const state = reactive<State>({
|
category: '',
|
categoryList: [],
|
list: [],
|
listQuery: {
|
currentPage: 1,
|
pageSize: 50,
|
sort: 'desc',
|
sidx: '',
|
},
|
keyword: '',
|
loading: false,
|
finish: false,
|
total: 0,
|
flowList: [],
|
userList: [],
|
activeFlow: {},
|
});
|
const { category, categoryList, list, listQuery, loading } = toRefs(state);
|
const baseStore = useBaseStore();
|
const { createMessage } = useMessage();
|
|
const [registerForm, { resetFields }] = useForm({
|
baseColProps: { span: 6 },
|
showActionButtonGroup: true,
|
showAdvancedButton: true,
|
compact: true,
|
schemas: [
|
{
|
field: 'keyword',
|
label: $t('common.keyword'),
|
component: 'Input',
|
componentProps: {
|
placeholder: $t('common.enterKeyword'),
|
submitOnPressEnter: true,
|
},
|
},
|
],
|
});
|
const infiniteBody = ref<Nullable<ScrollActionType>>(null);
|
|
watch(
|
() => state.category,
|
() => {
|
resetFields();
|
},
|
);
|
|
function bindScroll() {
|
const bodyRef = infiniteBody.value;
|
const vBody = bodyRef?.getScrollWrap();
|
vBody?.addEventListener('scroll', () => {
|
if (vBody.scrollHeight - vBody.clientHeight - vBody.scrollTop <= 200 && !state.loading && !state.finish) {
|
state.listQuery.currentPage += 1;
|
initData();
|
}
|
});
|
}
|
function initData() {
|
state.loading = true;
|
const query = {
|
...state.listQuery,
|
keyword: state.keyword,
|
category: unref(isWorkFlow) ? '' : state.category,
|
flowType: props.flowType || 0,
|
systemId: unref(isWorkFlow) ? state.category : unref(getUserInfo)?.systemId,
|
isLaunch: 1,
|
};
|
getFlowSelector(query).then((res) => {
|
if (res.data.list.length < state.listQuery.pageSize) {
|
state.finish = true;
|
}
|
state.list = [...state.list, ...res.data.list];
|
state.total = res.data.pagination.total;
|
state.loading = false;
|
});
|
}
|
async function getCategoryData() {
|
if (unref(isWorkFlow)) {
|
state.loading = true;
|
getAuthSystemList()
|
.then((res) => {
|
state.categoryList = res.data || [];
|
state.loading = false;
|
})
|
.catch(() => {
|
state.loading = false;
|
});
|
} else {
|
state.categoryList = await baseStore.getDictionaryData('businessType');
|
}
|
initData();
|
nextTick(() => {
|
bindScroll();
|
});
|
}
|
function handleSubmit(values) {
|
if (state.loading) return;
|
state.keyword = values?.keyword || '';
|
search();
|
}
|
function handleReset() {
|
if (state.loading) return;
|
state.keyword = '';
|
search();
|
}
|
function search() {
|
state.list = [];
|
state.finish = false;
|
state.listQuery = {
|
currentPage: 1,
|
pageSize: 50,
|
sort: 'desc',
|
sidx: '',
|
};
|
initData();
|
}
|
function handleClick(item) {
|
if (!item.id) return createMessage.error('流程不存在');
|
selectFlow(item);
|
}
|
function selectFlow(item) {
|
emit('select', item);
|
}
|
function handleCommonFlow(item, i) {
|
setCollectFlow(item.id).then((res) => {
|
createMessage.success(res.msg);
|
item.isCommonFlow = !item.isCommonFlow;
|
if (state.category == 'commonFlow' && !item.isCommonFlow) state.list.splice(i, 1);
|
});
|
}
|
|
onMounted(() => {
|
getCategoryData();
|
});
|
</script>
|
|
<template>
|
<div class="flow-list-container">
|
<a-tabs v-model:active-key="category" tab-position="left" class="common-left-tabs flow-left-tabs">
|
<a-tab-pane key="" tab="全部流程" />
|
<a-tab-pane :key="item.id" :tab="item.fullName" v-for="item in categoryList" />
|
<a-tab-pane key="-1" tab="其他应用委托" v-if="isWorkFlow" />
|
</a-tabs>
|
<div class="flow-list">
|
<div class="jnpf-common-search-box">
|
<BasicForm class="search-form" @register="registerForm" @submit="handleSubmit" @reset="handleReset" />
|
</div>
|
<div class="list">
|
<ScrollContainer v-loading="loading && listQuery.currentPage === 1" ref="infiniteBody">
|
<div class="px-[10px] pt-[10px]" v-if="list.length">
|
<a-row :gutter="20">
|
<a-col :span="6" v-for="(item, i) in list" :key="i" class="item" @click="handleClick(item)">
|
<a-card hoverable>
|
<div class="item-icon" :style="{ backgroundColor: item.iconBackground || '#008cff' }">
|
<i :class="item.icon || 'icon-ym icon-ym-funcFlow'"></i>
|
</div>
|
<div class="item-title">
|
<p :title="item.fullName">{{ item.fullName }}</p>
|
<p class="item-desc" :title="item.systemName" v-if="isWorkFlow">{{ item.systemName }}</p>
|
</div>
|
<a-tooltip placement="bottom" :title="item.isCommonFlow ? '取消收藏' : '收藏流程'">
|
<div class="item-star" @click.stop="handleCommonFlow(item, i)">
|
<i class="icon-ym icon-ym-header-star-fill" :class="{ 'common-flow': item.isCommonFlow }"></i>
|
</div>
|
</a-tooltip>
|
</a-card>
|
</a-col>
|
</a-row>
|
</div>
|
<jnpf-empty v-if="!list.length" />
|
</ScrollContainer>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<style lang="scss" scoped>
|
.flow-list-container {
|
display: flex;
|
width: 100%;
|
height: 100%;
|
|
.flow-list {
|
display: flex;
|
flex: 1;
|
flex-direction: column;
|
height: 100%;
|
padding: 10px 0;
|
overflow: hidden;
|
|
.list {
|
flex: 1;
|
min-height: 0;
|
|
.item {
|
margin-bottom: 20px;
|
cursor: pointer;
|
|
&:nth-last-child(1),
|
&:nth-last-child(2),
|
&:nth-last-child(3),
|
&:nth-last-child(4) {
|
margin-bottom: 0;
|
}
|
|
:deep(.ant-card) {
|
border-radius: 8px;
|
|
.ant-card-body {
|
display: flex;
|
align-items: center;
|
padding: 20px 15px 20px 20px;
|
|
&:hover {
|
.item-star i {
|
display: block;
|
}
|
}
|
}
|
}
|
|
.item-icon {
|
display: inline-block;
|
width: 56px;
|
height: 56px;
|
margin-right: 20px;
|
text-align: center;
|
background-color: #ccc;
|
border-radius: 8px;
|
|
i {
|
font-size: 40px;
|
line-height: 56px;
|
color: #fff;
|
text-align: center;
|
}
|
}
|
|
.item-title {
|
flex: 1;
|
min-width: 0;
|
font-size: 16px;
|
|
p {
|
overflow: hidden;
|
text-overflow: ellipsis;
|
white-space: nowrap;
|
|
&.item-desc {
|
margin-top: 4px;
|
font-size: 12px;
|
line-height: 17px;
|
color: var(--text-color-label);
|
}
|
}
|
}
|
|
.item-star {
|
width: 32px;
|
padding: 6px;
|
margin-top: -36px;
|
text-align: right;
|
|
i {
|
display: none;
|
font-size: 14px;
|
color: #c0c4cc;
|
}
|
|
.common-flow {
|
display: block;
|
color: #efae32;
|
}
|
}
|
}
|
}
|
|
.ant-empty {
|
margin-top: 60px;
|
}
|
}
|
}
|
</style>
|