merge: t25 单据查询页面与只读详情
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
import request from '@/utils/request';
|
||||
import type { ApiResult } from '@/api';
|
||||
import type { ApprovalOrganization, ApprovalUser } from '../instance/model';
|
||||
import { THINK_API_URL } from '@/config/setting';
|
||||
|
||||
/**
|
||||
* 启用组织(审批管理下拉)
|
||||
*/
|
||||
export async function listApprovalOrganizations() {
|
||||
const res = await request.get<ApiResult<ApprovalOrganization[]>>(
|
||||
THINK_API_URL + '/approval/directory/organizations'
|
||||
);
|
||||
if (res.data.code === 0 && res.data.data) {
|
||||
return res.data.data;
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用用户远程搜索(审批管理下拉)
|
||||
*/
|
||||
export async function searchApprovalUsers(params?: {
|
||||
keywords?: string;
|
||||
organizationId?: number;
|
||||
}) {
|
||||
const res = await request.get<ApiResult<ApprovalUser[]>>(
|
||||
THINK_API_URL + '/approval/directory/users',
|
||||
{ params }
|
||||
);
|
||||
if (res.data.code === 0 && res.data.data) {
|
||||
return res.data.data;
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import request from '@/utils/request';
|
||||
import type { ApiResult, PageResult } from '@/api';
|
||||
import type {
|
||||
ApprovalInstance,
|
||||
ApprovalItem,
|
||||
ApprovalQueryParam
|
||||
} from './model';
|
||||
import { THINK_API_URL } from '@/config/setting';
|
||||
|
||||
/**
|
||||
* 单据查询分页
|
||||
*/
|
||||
export async function pageInstances(params: ApprovalQueryParam) {
|
||||
const res = await request.get<ApiResult<PageResult<ApprovalItem>>>(
|
||||
THINK_API_URL + '/approval/instance/page',
|
||||
{ params }
|
||||
);
|
||||
if (res.data.code === 0) {
|
||||
return res.data.data;
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
|
||||
/**
|
||||
* 单据详情(只读)
|
||||
*/
|
||||
export async function getInstance(id: number) {
|
||||
const res = await request.get<ApiResult<ApprovalInstance>>(
|
||||
THINK_API_URL + '/approval/instance/' + id
|
||||
);
|
||||
if (res.data.code === 0) {
|
||||
return res.data.data;
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
import type { PageParam } from '@/api';
|
||||
|
||||
/**
|
||||
* 单据查询条件
|
||||
*/
|
||||
export interface ApprovalQueryParam extends PageParam {
|
||||
// 单据类型 completion/coordination
|
||||
docType?: string;
|
||||
// 单号
|
||||
bizNo?: string;
|
||||
// 关键词:单号、名称或标题、实施单位
|
||||
keyword?: string;
|
||||
// 报送部门id
|
||||
reportOrgId?: number;
|
||||
// 受理部门id
|
||||
acceptOrgId?: number;
|
||||
// 发起人id
|
||||
reporterId?: number;
|
||||
// 单据状态
|
||||
status?: string;
|
||||
// 提交时间起
|
||||
submitTimeStart?: string;
|
||||
// 提交时间止
|
||||
submitTimeEnd?: string;
|
||||
// 归档时间起
|
||||
archiveTimeStart?: string;
|
||||
// 归档时间止
|
||||
archiveTimeEnd?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 单据列表行
|
||||
*/
|
||||
export interface ApprovalItem {
|
||||
id?: number;
|
||||
bizNo?: string;
|
||||
docType?: string;
|
||||
docTypeName?: string;
|
||||
status?: string;
|
||||
statusName?: string;
|
||||
// 名称或标题
|
||||
title?: string;
|
||||
submitTime?: string;
|
||||
currentNodeName?: string;
|
||||
reporterId?: number;
|
||||
reporterName?: string;
|
||||
reportOrgName?: string;
|
||||
acceptOrgName?: string;
|
||||
archiveTime?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 附件
|
||||
*/
|
||||
export interface ApprovalAttachment {
|
||||
id?: number;
|
||||
fileId?: number;
|
||||
name?: string;
|
||||
url?: string;
|
||||
length?: number;
|
||||
category?: string;
|
||||
categoryName?: string;
|
||||
uploaderId?: number;
|
||||
uploaderName?: string;
|
||||
createTime?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理记录
|
||||
*/
|
||||
export interface ApprovalRecord {
|
||||
id?: number;
|
||||
taskId?: number;
|
||||
nodeKey?: string;
|
||||
nodeName?: string;
|
||||
operatorId?: number;
|
||||
operatorName?: string;
|
||||
action?: string;
|
||||
actionName?: string;
|
||||
opinion?: string;
|
||||
round?: number;
|
||||
createTime?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前轮存档确认
|
||||
*/
|
||||
export interface ApprovalConfirm {
|
||||
userId?: number;
|
||||
userName?: string;
|
||||
status?: string;
|
||||
statusName?: string;
|
||||
handleTime?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 我的待处理任务
|
||||
*/
|
||||
export interface ApprovalMyTask {
|
||||
id?: number;
|
||||
nodeKey?: string;
|
||||
nodeType?: string;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 单据详情
|
||||
*/
|
||||
export interface ApprovalInstance {
|
||||
id?: number;
|
||||
bizNo?: string;
|
||||
docType?: string;
|
||||
docTypeName?: string;
|
||||
flowCode?: string;
|
||||
status?: string;
|
||||
statusName?: string;
|
||||
round?: number;
|
||||
reporterId?: number;
|
||||
reporterName?: string;
|
||||
reportOrgId?: number;
|
||||
reportOrgName?: string;
|
||||
acceptOrgId?: number;
|
||||
acceptOrgName?: string;
|
||||
currentNodeKey?: string;
|
||||
currentNodeType?: string;
|
||||
currentNodeName?: string;
|
||||
submitTime?: string;
|
||||
approveTime?: string;
|
||||
archiveTime?: string;
|
||||
archivistId?: number;
|
||||
archivistName?: string;
|
||||
// 业务完成确认单
|
||||
name?: string;
|
||||
implementOrg?: string;
|
||||
fee?: number;
|
||||
serviceContent?: string;
|
||||
// 内部协调单
|
||||
title?: string;
|
||||
content?: string;
|
||||
remark?: string;
|
||||
dispatchTargetId?: number;
|
||||
dispatchTargetName?: string;
|
||||
attachments?: ApprovalAttachment[];
|
||||
records?: ApprovalRecord[];
|
||||
confirms?: ApprovalConfirm[];
|
||||
myTask?: ApprovalMyTask | null;
|
||||
permissions?: Record<string, boolean>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批目录组织
|
||||
*/
|
||||
export interface ApprovalOrganization {
|
||||
organizationId?: number;
|
||||
parentId?: number;
|
||||
organizationName?: string;
|
||||
organizationFullName?: string;
|
||||
organizationCode?: string;
|
||||
leaderId?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批目录用户
|
||||
*/
|
||||
export interface ApprovalUser {
|
||||
userId?: number;
|
||||
username?: string;
|
||||
nickname?: string;
|
||||
realName?: string;
|
||||
organizationId?: number;
|
||||
organizationName?: string;
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
<!-- 单据详情抽屉(只读) -->
|
||||
<template>
|
||||
<ele-modal
|
||||
title="单据详情"
|
||||
:width="860"
|
||||
:footer="null"
|
||||
:visible="visible"
|
||||
@update:visible="updateVisible"
|
||||
>
|
||||
<a-spin :spinning="loading">
|
||||
<template v-if="data">
|
||||
<a-descriptions
|
||||
:column="2"
|
||||
size="small"
|
||||
bordered
|
||||
:label-style="{ width: '110px' }"
|
||||
>
|
||||
<a-descriptions-item label="单号">
|
||||
{{ data.bizNo || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="单据类型">
|
||||
{{ data.docTypeName || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="状态">
|
||||
<a-tag :color="statusColor(data.status)">
|
||||
{{ data.statusName || '-' }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="当前节点">
|
||||
{{ data.currentNodeName || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="发起人">
|
||||
{{ data.reporterName || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="报送部门">
|
||||
{{ data.reportOrgName || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="受理部门">
|
||||
{{ data.acceptOrgName || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="提交时间">
|
||||
{{ toDateString(data.submitTime) || '-' }}
|
||||
</a-descriptions-item>
|
||||
<template v-if="data.docType === 'completion'">
|
||||
<a-descriptions-item label="名称" :span="2">
|
||||
{{ data.name || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="实施单位">
|
||||
{{ data.implementOrg || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="费用(元)">
|
||||
{{ data.fee ?? '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="服务内容" :span="2">
|
||||
<div class="ele-text-break">{{ data.serviceContent || '-' }}</div>
|
||||
</a-descriptions-item>
|
||||
</template>
|
||||
<template v-else>
|
||||
<a-descriptions-item label="标题" :span="2">
|
||||
{{ data.title || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="协调内容" :span="2">
|
||||
<div class="ele-text-break">{{ data.content || '-' }}</div>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="备注" :span="2">
|
||||
<div class="ele-text-break">{{ data.remark || '-' }}</div>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="派单对象">
|
||||
{{ data.dispatchTargetName || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="审批完成时间">
|
||||
{{ toDateString(data.approveTime) || '-' }}
|
||||
</a-descriptions-item>
|
||||
</template>
|
||||
<a-descriptions-item label="归档时间">
|
||||
{{ toDateString(data.archiveTime) || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="归档人">
|
||||
{{ data.archivistName || '-' }}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
|
||||
<a-divider orientation="left">附件</a-divider>
|
||||
<div v-if="data.attachments && data.attachments.length">
|
||||
<div
|
||||
v-for="attachment in data.attachments"
|
||||
:key="attachment.id"
|
||||
class="attachment-item"
|
||||
>
|
||||
<a :href="attachment.url" target="_blank" rel="noopener noreferrer">
|
||||
{{ attachment.name || '附件' }}
|
||||
</a>
|
||||
<a-tag style="margin-left: 8px">
|
||||
{{ attachment.categoryName || '-' }}
|
||||
</a-tag>
|
||||
<span class="ele-text-secondary" style="margin-left: 8px">
|
||||
{{ sizeText(attachment.length) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="ele-text-secondary">暂无附件</div>
|
||||
|
||||
<a-divider orientation="left">存档确认</a-divider>
|
||||
<div v-if="data.confirms && data.confirms.length">
|
||||
<div
|
||||
v-for="confirm in data.confirms"
|
||||
:key="confirm.userId"
|
||||
class="confirm-item"
|
||||
>
|
||||
<span>{{ confirm.userName || '-' }}</span>
|
||||
<a-tag
|
||||
style="margin-left: 8px"
|
||||
:color="confirm.status === 'DONE' ? 'green' : 'default'"
|
||||
>
|
||||
{{ confirm.statusName || '-' }}
|
||||
</a-tag>
|
||||
<span class="ele-text-secondary" style="margin-left: 8px">
|
||||
{{ toDateString(confirm.handleTime) || '' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="ele-text-secondary">尚未进入存档环节</div>
|
||||
|
||||
<a-divider orientation="left">处理记录</a-divider>
|
||||
<a-timeline v-if="data.records && data.records.length">
|
||||
<a-timeline-item
|
||||
v-for="record in data.records"
|
||||
:key="record.id"
|
||||
:color="actionColor(record.action)"
|
||||
>
|
||||
<div>
|
||||
<span style="font-weight: 500">
|
||||
{{ record.operatorName || '-' }}
|
||||
</span>
|
||||
<span style="margin-left: 8px">
|
||||
{{ record.actionName || record.action }}
|
||||
</span>
|
||||
<span
|
||||
v-if="record.nodeName"
|
||||
class="ele-text-secondary"
|
||||
style="margin-left: 8px"
|
||||
>
|
||||
({{ record.nodeName }})
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="record.opinion" class="ele-text-secondary">
|
||||
意见:{{ record.opinion }}
|
||||
</div>
|
||||
<div class="ele-text-secondary">
|
||||
{{ toDateString(record.createTime) }}
|
||||
</div>
|
||||
</a-timeline-item>
|
||||
</a-timeline>
|
||||
<div v-else class="ele-text-secondary">暂无处理记录</div>
|
||||
</template>
|
||||
<a-empty v-else-if="!loading" description="暂无数据" />
|
||||
</a-spin>
|
||||
</ele-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import { message } from 'ant-design-vue/es';
|
||||
import { toDateString } from 'ele-admin-pro/es';
|
||||
import { getInstance } from '@/api/approval/instance';
|
||||
import type { ApprovalInstance } from '@/api/approval/instance/model';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:visible', visible: boolean): void;
|
||||
}>();
|
||||
|
||||
const props = defineProps<{
|
||||
// 抽屉是否打开
|
||||
visible: boolean;
|
||||
// 单据id
|
||||
instanceId?: number;
|
||||
}>();
|
||||
|
||||
// 详情数据
|
||||
const data = ref<ApprovalInstance | null>(null);
|
||||
// 加载状态
|
||||
const loading = ref(false);
|
||||
|
||||
// 状态颜色
|
||||
const statusColor = (status?: string) => {
|
||||
switch (status) {
|
||||
case 'PENDING':
|
||||
return 'processing';
|
||||
case 'REJECTED':
|
||||
return 'red';
|
||||
case 'WITHDRAWN':
|
||||
return 'orange';
|
||||
case 'APPROVED':
|
||||
return 'green';
|
||||
case 'ARCHIVED':
|
||||
return 'blue';
|
||||
default:
|
||||
return 'default';
|
||||
}
|
||||
};
|
||||
|
||||
// 处理记录颜色
|
||||
const actionColor = (action?: string) => {
|
||||
switch (action) {
|
||||
case 'APPROVE':
|
||||
case 'CONFIRM':
|
||||
case 'ARCHIVE':
|
||||
return 'green';
|
||||
case 'REJECT':
|
||||
return 'red';
|
||||
default:
|
||||
return 'blue';
|
||||
}
|
||||
};
|
||||
|
||||
// 附件大小
|
||||
const sizeText = (length?: number) => {
|
||||
if (!length && length !== 0) {
|
||||
return '';
|
||||
}
|
||||
if (length < 1024) {
|
||||
return length + ' B';
|
||||
}
|
||||
if (length < 1024 * 1024) {
|
||||
return (length / 1024).toFixed(1) + ' KB';
|
||||
}
|
||||
return (length / 1024 / 1024).toFixed(1) + ' MB';
|
||||
};
|
||||
|
||||
/* 更新visible */
|
||||
const updateVisible = (value: boolean) => {
|
||||
emit('update:visible', value);
|
||||
};
|
||||
|
||||
/* 加载详情 */
|
||||
const loadData = () => {
|
||||
if (!props.instanceId) {
|
||||
data.value = null;
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
data.value = null;
|
||||
getInstance(props.instanceId)
|
||||
.then((result) => {
|
||||
data.value = result;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((e) => {
|
||||
loading.value = false;
|
||||
message.error(e.message);
|
||||
});
|
||||
};
|
||||
|
||||
watch(
|
||||
() => [props.visible, props.instanceId],
|
||||
() => {
|
||||
if (props.visible) {
|
||||
loadData();
|
||||
} else {
|
||||
data.value = null;
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.attachment-item {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.confirm-item {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.ele-text-break {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,254 @@
|
||||
<!-- 单据查询搜索表单 -->
|
||||
<template>
|
||||
<a-form
|
||||
:label-col="
|
||||
styleResponsive ? { xl: 7, lg: 5, md: 7, sm: 4 } : { flex: '90px' }
|
||||
"
|
||||
:wrapper-col="
|
||||
styleResponsive ? { xl: 17, lg: 19, md: 17, sm: 20 } : { flex: '1' }
|
||||
"
|
||||
>
|
||||
<a-row :gutter="8">
|
||||
<a-col v-for="field in basicFields" :key="field.prop" v-bind="colSpan">
|
||||
<a-form-item :label="field.label">
|
||||
<a-select
|
||||
v-if="field.prop === 'docType'"
|
||||
v-model:value="form.docType"
|
||||
placeholder="全部"
|
||||
allow-clear
|
||||
:options="docTypeOptions"
|
||||
/>
|
||||
<a-select
|
||||
v-else-if="field.prop === 'status'"
|
||||
v-model:value="form.status"
|
||||
placeholder="全部"
|
||||
allow-clear
|
||||
:options="statusOptions"
|
||||
/>
|
||||
<a-select
|
||||
v-else-if="field.prop === 'reportOrgId'"
|
||||
v-model:value="form.reportOrgId"
|
||||
placeholder="全部"
|
||||
allow-clear
|
||||
show-search
|
||||
:filter-option="filterOrganization"
|
||||
:options="organizationOptions"
|
||||
/>
|
||||
<a-select
|
||||
v-else-if="field.prop === 'acceptOrgId'"
|
||||
v-model:value="form.acceptOrgId"
|
||||
placeholder="全部"
|
||||
allow-clear
|
||||
show-search
|
||||
:filter-option="filterOrganization"
|
||||
:options="organizationOptions"
|
||||
/>
|
||||
<a-select
|
||||
v-else-if="field.prop === 'reporterId'"
|
||||
v-model:value="form.reporterId"
|
||||
placeholder="输入姓名或账号搜索"
|
||||
allow-clear
|
||||
show-search
|
||||
:filter-option="false"
|
||||
:options="userOptions"
|
||||
:loading="userLoading"
|
||||
@search="searchUsers"
|
||||
/>
|
||||
<a-input
|
||||
v-else
|
||||
v-model:value.trim="form[field.prop]"
|
||||
placeholder="请输入"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col v-bind="colSpan">
|
||||
<a-form-item label="提交时间">
|
||||
<a-range-picker
|
||||
v-model:value="submitRange"
|
||||
:show-time="true"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
class="ele-fluid"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col v-bind="colSpan">
|
||||
<a-form-item label="归档时间">
|
||||
<a-range-picker
|
||||
v-model:value="archiveRange"
|
||||
:show-time="true"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
class="ele-fluid"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col v-bind="colSpan">
|
||||
<a-form-item class="ele-text-right" :wrapper-col="{ span: 24 }">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="search">查询</a-button>
|
||||
<a-button @click="reset">重置</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import useFormData from '@/utils/use-form-data';
|
||||
import {
|
||||
listApprovalOrganizations,
|
||||
searchApprovalUsers
|
||||
} from '@/api/approval/directory';
|
||||
import type {
|
||||
ApprovalOrganization,
|
||||
ApprovalQueryParam,
|
||||
ApprovalUser
|
||||
} from '@/api/approval/instance/model';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'search', where?: ApprovalQueryParam): void;
|
||||
}>();
|
||||
|
||||
// 是否开启响应式布局
|
||||
const themeStore = useThemeStore();
|
||||
const { styleResponsive } = storeToRefs(themeStore);
|
||||
|
||||
// 栅格宽度
|
||||
const colSpan = {
|
||||
xl: 6,
|
||||
lg: 12,
|
||||
md: 12,
|
||||
sm: 24,
|
||||
xs: 24
|
||||
};
|
||||
|
||||
// 基础字段
|
||||
const basicFields: {
|
||||
prop:
|
||||
| 'docType'
|
||||
| 'bizNo'
|
||||
| 'keyword'
|
||||
| 'reportOrgId'
|
||||
| 'acceptOrgId'
|
||||
| 'reporterId'
|
||||
| 'status';
|
||||
label: string;
|
||||
}[] = [
|
||||
{ prop: 'docType', label: '单据类型' },
|
||||
{ prop: 'bizNo', label: '单号' },
|
||||
{ prop: 'keyword', label: '标题或名称' },
|
||||
{ prop: 'reportOrgId', label: '报送部门' },
|
||||
{ prop: 'acceptOrgId', label: '受理部门' },
|
||||
{ prop: 'reporterId', label: '发起人' },
|
||||
{ prop: 'status', label: '状态' }
|
||||
];
|
||||
|
||||
// 单据类型选项
|
||||
const docTypeOptions = [
|
||||
{ label: '业务完成确认单', value: 'completion' },
|
||||
{ label: '内部协调单', value: 'coordination' }
|
||||
];
|
||||
|
||||
// 状态选项
|
||||
const statusOptions = [
|
||||
{ label: '未提交', value: 'DRAFT' },
|
||||
{ label: '审批中', value: 'PENDING' },
|
||||
{ label: '已驳回', value: 'REJECTED' },
|
||||
{ label: '已撤回', value: 'WITHDRAWN' },
|
||||
{ label: '审批完成', value: 'APPROVED' },
|
||||
{ label: '已归档', value: 'ARCHIVED' }
|
||||
];
|
||||
|
||||
// 表单数据
|
||||
const { form, resetFields } = useFormData<ApprovalQueryParam>({
|
||||
docType: undefined,
|
||||
bizNo: '',
|
||||
keyword: '',
|
||||
reportOrgId: undefined,
|
||||
acceptOrgId: undefined,
|
||||
reporterId: undefined,
|
||||
status: undefined
|
||||
});
|
||||
|
||||
// 提交时间范围
|
||||
const submitRange = ref<[string, string]>(['', '']);
|
||||
// 归档时间范围
|
||||
const archiveRange = ref<[string, string]>(['', '']);
|
||||
|
||||
// 组织下拉选项
|
||||
const organizationOptions = ref<{ label: string; value: number }[]>([]);
|
||||
|
||||
// 发起人下拉选项
|
||||
const userOptions = ref<{ label: string; value: number }[]>([]);
|
||||
// 发起人请求状态
|
||||
const userLoading = ref(false);
|
||||
|
||||
// 组织远程过滤
|
||||
const filterOrganization = (input: string, option: { label: string }) => {
|
||||
return (option?.label ?? '').toLowerCase().includes(input.toLowerCase());
|
||||
};
|
||||
|
||||
// 远程搜索发起人
|
||||
const searchUsers = (keywords?: string) => {
|
||||
userLoading.value = true;
|
||||
searchApprovalUsers({ keywords })
|
||||
.then((data) => {
|
||||
userOptions.value = data.map((user: ApprovalUser) => ({
|
||||
label:
|
||||
(user.realName || user.nickname || user.username || '') +
|
||||
(user.username ? '(' + user.username + ')' : ''),
|
||||
value: user.userId as number
|
||||
}));
|
||||
})
|
||||
.catch(() => {
|
||||
userOptions.value = [];
|
||||
})
|
||||
.finally(() => {
|
||||
userLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
/* 搜索 */
|
||||
const search = () => {
|
||||
const [submitTimeStart, submitTimeEnd] = submitRange.value ?? ['', ''];
|
||||
const [archiveTimeStart, archiveTimeEnd] = archiveRange.value ?? ['', ''];
|
||||
emit('search', {
|
||||
...form,
|
||||
submitTimeStart,
|
||||
submitTimeEnd,
|
||||
archiveTimeStart,
|
||||
archiveTimeEnd
|
||||
});
|
||||
};
|
||||
|
||||
/* 重置 */
|
||||
const reset = () => {
|
||||
resetFields();
|
||||
submitRange.value = ['', ''];
|
||||
archiveRange.value = ['', ''];
|
||||
userOptions.value = [];
|
||||
search();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
listApprovalOrganizations()
|
||||
.then((data) => {
|
||||
organizationOptions.value = data.map(
|
||||
(organization: ApprovalOrganization) => ({
|
||||
label:
|
||||
organization.organizationFullName ||
|
||||
organization.organizationName ||
|
||||
'',
|
||||
value: organization.organizationId as number
|
||||
})
|
||||
);
|
||||
})
|
||||
.catch(() => {
|
||||
organizationOptions.value = [];
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,188 @@
|
||||
<!-- 审批管理 - 单据查询 -->
|
||||
<template>
|
||||
<div class="ele-body">
|
||||
<a-card :bordered="false">
|
||||
<!-- 搜索表单 -->
|
||||
<search @search="reload" />
|
||||
<!-- 表格 -->
|
||||
<ele-pro-table
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:columns="columns"
|
||||
:datasource="datasource"
|
||||
:scroll="{ x: 1500 }"
|
||||
cache-key="proApprovalInstanceTable"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'docType'">
|
||||
<a-tag :color="record.docType === 'completion' ? 'blue' : 'purple'">
|
||||
{{ record.docTypeName }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'status'">
|
||||
<a-tag :color="statusColor(record.status)">
|
||||
{{ record.statusName }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'submitTime'">
|
||||
{{ toDateString(record.submitTime) || '-' }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'archiveTime'">
|
||||
{{ toDateString(record.archiveTime) || '-' }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'action'">
|
||||
<a @click="openDetail(record)">详情</a>
|
||||
</template>
|
||||
</template>
|
||||
</ele-pro-table>
|
||||
</a-card>
|
||||
<!-- 详情抽屉 -->
|
||||
<detail v-model:visible="showDetail" :instance-id="currentId" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import type { EleProTable } from 'ele-admin-pro/es';
|
||||
import { toDateString } from 'ele-admin-pro/es';
|
||||
import type {
|
||||
DatasourceFunction,
|
||||
ColumnItem
|
||||
} from 'ele-admin-pro/es/ele-pro-table/types';
|
||||
import Search from './components/search.vue';
|
||||
import Detail from './components/detail.vue';
|
||||
import { pageInstances } from '@/api/approval/instance';
|
||||
import type {
|
||||
ApprovalItem,
|
||||
ApprovalQueryParam
|
||||
} from '@/api/approval/instance/model';
|
||||
|
||||
// 表格实例
|
||||
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
|
||||
|
||||
// 详情抽屉是否显示
|
||||
const showDetail = ref(false);
|
||||
// 当前查看的单据id
|
||||
const currentId = ref<number | undefined>(undefined);
|
||||
|
||||
// 表格数据源
|
||||
const datasource: DatasourceFunction = ({ page, limit, where }) => {
|
||||
return pageInstances({
|
||||
...(where as ApprovalQueryParam),
|
||||
page,
|
||||
limit
|
||||
});
|
||||
};
|
||||
|
||||
// 表格列配置
|
||||
const columns = ref<ColumnItem[]>([
|
||||
{
|
||||
title: '单号',
|
||||
dataIndex: 'bizNo',
|
||||
width: 180,
|
||||
ellipsis: true,
|
||||
customRender: ({ text }) => text || '-'
|
||||
},
|
||||
{
|
||||
title: '单据类型',
|
||||
key: 'docType',
|
||||
dataIndex: 'docType',
|
||||
width: 140,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '标题或名称',
|
||||
dataIndex: 'title',
|
||||
minWidth: 220,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '报送部门',
|
||||
dataIndex: 'reportOrgName',
|
||||
width: 180,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '报送人',
|
||||
dataIndex: 'reporterName',
|
||||
width: 120,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '受理部门',
|
||||
dataIndex: 'acceptOrgName',
|
||||
width: 180,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
dataIndex: 'status',
|
||||
width: 110,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '当前节点',
|
||||
dataIndex: 'currentNodeName',
|
||||
width: 140,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '提交时间',
|
||||
key: 'submitTime',
|
||||
dataIndex: 'submitTime',
|
||||
width: 170,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '归档时间',
|
||||
key: 'archiveTime',
|
||||
dataIndex: 'archiveTime',
|
||||
width: 170,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 90,
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
hideInSetting: true
|
||||
}
|
||||
]);
|
||||
|
||||
// 状态颜色
|
||||
const statusColor = (status?: string) => {
|
||||
switch (status) {
|
||||
case 'PENDING':
|
||||
return 'processing';
|
||||
case 'REJECTED':
|
||||
return 'red';
|
||||
case 'WITHDRAWN':
|
||||
return 'orange';
|
||||
case 'APPROVED':
|
||||
return 'green';
|
||||
case 'ARCHIVED':
|
||||
return 'blue';
|
||||
default:
|
||||
return 'default';
|
||||
}
|
||||
};
|
||||
|
||||
/* 刷新表格 */
|
||||
const reload = (where?: ApprovalQueryParam) => {
|
||||
tableRef?.value?.reload({ page: 1, where: where ?? {} });
|
||||
};
|
||||
|
||||
/* 打开详情 */
|
||||
const openDetail = (row: ApprovalItem) => {
|
||||
currentId.value = row.id;
|
||||
showDetail.value = true;
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'ApprovalInstance'
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user