| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422 |
- <template>
- <el-row class="process-list" :gutter="20">
- <el-col :span="6" :xs="24">
- <div class="header" v-if="show">
- <el-row>
- <el-col :span="22">
- <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
- <el-tab-pane name="1">
- <template #label>
- <span class="custom-tabs-label">
- 待审<el-badge :value="count.todoCount" class="item" />
- </span>
- </template>
- </el-tab-pane>
- <el-tab-pane label="已审" name="2" />
- <el-tab-pane label="已发起" name="3">
- <template #label>
- <span class="custom-tabs-label">
- 已发起<el-badge :value="count.myCreateCount" class="item" />
- </span>
- </template>
- </el-tab-pane>
- <el-tab-pane label="抄送我的" name="4">
- <template #label>
- <span class="custom-tabs-label">
- 抄送我的<el-badge :value="count.copyCount" class="item" />
- </span>
- </template>
- </el-tab-pane>
- </el-tabs>
- </el-col>
- <el-col :span="2">
- <Icon icon="ep:search" :size="20" @click="show=false"/>
- </el-col>
- </el-row>
- </div>
- <el-form v-else :inline="true" :model="queryParams" ref="queryFormRef" class="searchContent">
- <el-row>
- <el-col :span="20">
- <el-input placeholder="请输入审批内容" v-model="queryParams.templateContent" @change="handleQuery"/>
- </el-col>
- <el-col :span="4">
- <el-button class="mt2" @click="show=true" link type="primary">取消</el-button>
- </el-col>
- </el-row>
- </el-form>
- <div
- v-if="selectableTaskIds.length"
- class="batch-select-bar"
- @click.stop
- >
- <el-checkbox
- :model-value="isAllSelectableSelected"
- :indeterminate="isPartialSelectableSelected"
- @change="onSelectAllChange"
- >
- 全选当前列表({{ selectedSelectableCount }}/{{ selectableTaskIds.length }})
- </el-checkbox>
- </div>
- <div v-infinite-scroll="load" class="infinite-list scrollLeft" v-loading="loading" v-if="list.length">
- <el-checkbox-group v-model="processInstanceIds">
- <el-card shadow="never" v-for="(item, index) in list" :key="index" :class="['card-item', {'selected': currItem.processInstanceId == item.processInstanceId}]" @click="handleClickCard(item)">
- <el-badge v-show="item.readStatus == 0 && currItem.processInstanceId != item.processInstanceId" is-dot class="badge" />
- <div class="title mb5 mt2">
- <span class="lh16 mr-1">{{ item.templateContent }}</span>
- <dict-tag :type="DICT_TYPE.BPM_TASK_STATUS" :value="item.status"/>
- <span class="ml2">
- <el-checkbox :value="item.id" v-if="item.status == 1"/>
- </span>
- </div>
- <div class="mb4 c6 lh14">申请类型:<span class="c3">{{ item.applicationType }}</span></div>
- <div class="mb4 c6 lh14">申请编号:<span class="c3">{{ item.processInstanceId }}</span></div>
- <div class="mb2 c6 lh14">所属组织:<span class="c3">{{ item.tenantName }}</span></div>
- </el-card>
- </el-checkbox-group>
- </div>
- <div class="no-content" v-else>
- <span>暂无数据</span>
- </div>
- </el-col>
- <el-col :span="18" :xs="24">
- <el-button @click="handlePass" type="primary" :loading="batchLoading">批量通过</el-button>
- <div class="content">
- <ProcessDetail v-if="obj.processInstanceId" :id="obj.processInstanceId" :taskName="obj.templateContent" ref="processDetailRef" @success="getList(false, true)"/>
- <div v-else class="tc">
- <div></div>
- </div>
- </div>
- </el-col>
- </el-row>
- </template>
- <script lang="ts" setup>
- import * as ProcessInstanceApi from '@/api/bpm/processInstance'
- import { DICT_TYPE } from '@/utils/dict'
- import { config } from '@/config/axios/config'
- import ProcessDetail from './detail.vue'
- import axios from '@/config/axios'
- import { message } from 'ant-design-vue'
- defineOptions({ name: 'BpmProcessList' })
- const { base_url } = config
- const activeName = ref('1')
- const processInstanceIds = ref<any[]>([])
- const route = useRoute()
- const loading = ref(false)
- const list = ref<any>([])
- const total = ref(0)
- const queryParams = reactive({
- pageNo: 1,
- pageSize: 10,
- queryType: '1',
- templateContent: ''
- })
- const queryFormRef = ref()
- const show = ref(true)
- const batchLoading = ref(false) // 批量审批按钮
- // 点击tab页签
- const handleClick = (tab) => {
- activeName.value = tab.paneName
- queryParams.queryType = tab.paneName
- list.value = []
- processInstanceIds.value = []
- queryParams.pageNo = 1
- getList()
- // 清空路由
- route.query.activeName = ''
- route.query.processId = ''
- route.query.status = ''
- }
- const currItem: any = ref({})
- const getList = async (flag: boolean = false, refresh=false) => { // flag 存在数据, refresh 是否重载页面数据
- try {
- loading.value = true
- const res = await ProcessInstanceApi.getMyPage(queryParams)
- if(refresh){
- list.value = res.list
- }else{
- list.value = list.value.concat(res.list)
- }
- total.value = res.total
- if(flag && res.list[0]){
- handleClickCard(res.list[0])
- currItem.value = res.list[0]
- }
- } finally {
- loading.value = false
- }
- }
- const load = () => {
- if(queryParams.pageNo * queryParams.pageSize < total.value){
- queryParams.pageNo += 1
- getList()
- }
- }
- const statusType = ref('')
- const businessKey = ref('')
- const obj: any = ref({})
- const handleClickCard = (item: any) => {
- obj.value = item
- currItem.value = item
- updateRead(item)
- }
- /** 搜索按钮操作 */
- const handleQuery = () => {
- queryParams.pageNo = 1
- processInstanceIds.value = []
- getList()
- }
- // 获取未读数量
- const count = ref({ copyCount: 0, todoCount: 0, myCreateCount: 0 })
- const getCount = async () => {
- const res = await ProcessInstanceApi.getProcessInstanceBpmnCount()
- count.value = res
- }
- // 标记已读
- const updateRead = async (item) => {
- if((queryParams.queryType != '3' && queryParams.queryType != '1') && item.messageId){
- await ProcessInstanceApi.updateReadById(item.messageId)
- item.readStatus = 1
- }else if(item.processInstanceId){
- await ProcessInstanceApi.updateMyCreateReadById(item.processInstanceId)
- item.readStatus = 1
- }
- }
- const processDetailRef = ref()
- /** 左侧列表中可进行批量审批的项(status == 1)对应的任务 id */
- const selectableTaskIds = computed(() =>
- list.value.filter((item) => item.status == 1).map((item) => item.id)
- )
- const selectedSelectableCount = computed(() =>
- selectableTaskIds.value.filter((id) => processInstanceIds.value.includes(id)).length
- )
- const isAllSelectableSelected = computed(
- () =>
- selectableTaskIds.value.length > 0 &&
- selectedSelectableCount.value === selectableTaskIds.value.length
- )
- const isPartialSelectableSelected = computed(
- () =>
- selectedSelectableCount.value > 0 &&
- selectedSelectableCount.value < selectableTaskIds.value.length
- )
- const onSelectAllChange = (checked: boolean) => {
- if (checked) {
- processInstanceIds.value = [...new Set([...processInstanceIds.value, ...selectableTaskIds.value])]
- } else {
- const drop = new Set(selectableTaskIds.value)
- processInstanceIds.value = processInstanceIds.value.filter((id) => !drop.has(id))
- }
- }
- // 批量通过
- const handlePass = () => {
- batchLoading.value = true
- let queue = processInstanceIds.value.map(item => {
- return new Promise((resolve, reject) => {
- axios.put({url: base_url + `/bpm/task/approve`, data: {
- id: item,
- reason: '批量通过',
- variables: {} // 审批通过, 把修改的字段值赋于流程实例变量
- }}).then((res) => {
- console.log(`获取的code为: ${res}`);
- resolve(res)
- }).catch((err) => {
- reject(err)
- batchLoading.value = true
- })
- })
- })
- Promise.all(queue).then(async result => {
- batchLoading.value = false
- // 判断所有值为0的时候审批成功
- const allApproved = result.every(item => item === true);
- if (allApproved) {
- message.success('所有审批通过成功')
- // 这里可以执行审批成功后的逻辑
- } else {
- console.log("存在未通过的审批!");
- // 这里可以执行审批失败后的逻辑
- message.error('审批不成功')
- }
- // 清空值
- processInstanceIds.value = []
- await getList(false, true)
- // 找到对应的id
- processDetailRef.value.refresh()
- getCount()
- })
- }
- watch(
- () => route.query.activeName,
- () => {
- if (route.query.activeName) {
- activeName.value = route.query.activeName as string
- businessKey.value = route.query.processId as string
- statusType.value = route.query.status as string
- }
- },
- { immediate: true }
- )
- onMounted(async () => {
- getCount()
- await getList(true)
- })
- </script>
- <style lang="scss" scoped>
- .process-list{
- font-size: 16px;
- .title{
- font-weight: bold;
- }
- .card-item{
- position: relative;
- margin-bottom: 5px;
- border-radius: 8px;
- border: 2px solid #e5e5e5;
- &:hover{
- background-color: #f3f4f6;
- }
- &.selected{
- border: 2px solid var(--el-color-primary);
- background-color: color-mix(in srgb, var(--el-color-primary) 10%, white);
- }
- .c6{
- color: #666;
- font-size: 14px;
- }
- .c3{
- color: #333;
- font-size: 14px;
- }
- .status-label{
- position: absolute;
- right: -15px;
- top: -6px;
- width: 40px;
- height: 24px;
- background: var(--el-color-primary);
- text-align: center;
- transform: rotate(45deg);
- .check{
- color: #fff;
- font-size: 12px !important;
- margin-top: 11px;
- transform: rotate(-45deg);
- }
- }
- .badge{
- position: absolute;
- top: 10px;
- right: 10px;
- }
- }
- .content{
- background-color: #fff;
- border-radius: 4px;
- }
- }
- </style>
- <style lang="scss">
- .process-list{
- position: relative;
- .searchContent{
- padding: 10px;
- border-radius: 4px;
- background-color: #fff;
- }
- .header{
- // display: flex;
- // align-items: flex-start;
- border-radius: 4px;
- background-color: #fff;
- .demo-tabs{
- .el-tabs__header{
- margin: 0;
- padding-bottom: 10px;
- }
- }
- .el-icon{
- padding-top: 20px;
- padding-left: 10px;
- cursor: pointer;
- }
- }
- .no-content{
- background-color: #fff;
- height: 77vh;
- margin-top: 10px;
- font-size: 20px;
- color: #ccc;
- display: flex;
- justify-content: center;
- align-items: center;
- border-radius: 8px;
- }
- .el-card{
- .el-card__body{
- padding: 10px 20px !important;
- }
- }
- .el-tabs__item{
- padding: 0 10px !important;
- }
- .el-scrollbar{
- height: auto;
- }
- .tc{
- display: flex;
- justify-content: center;
- align-items: center;
- height: 100%;
- font-size: 26px;
- color: #ccc;
- }
- .batch-select-bar{
- padding: 8px 12px;
- margin-top: 8px;
- background-color: #fff;
- border-radius: 8px;
- font-size: 14px;
- }
- .scrollLeft{
- padding: 10px 0;
- height: 78vh;
- overflow-y: auto;
- }
- ::-webkit-scrollbar {
- width: 0px; //滚动条宽度
- }
- ::-webkit-scrollbar-thumb {
- //上层
- border-radius: 10px; //滚动条圆弧半径
- //-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); //滚动条阴影
- background: var(--el-border-color-dark); //背景颜色
- }
- .lh14{
- line-height: 14px;
- }
- .lh16{
- line-height: 16px;
- }
- }
- </style>
|