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