feat(oa/erp): 完成临时任务模块重构与功能升级

1.  新增临时任务流程编码枚举OATT
2.  重构临时任务API与类型定义,合并原变更记录模块功能
3.  新增协作人管理、工时维护、评分关闭等完整业务功能
4.  优化列表页搜索条件与表格列展示,新增归集部门筛选
5.  新增任务统计报表页面,支持按人员/项目/部门多维度分析
6.  删除废弃的临时任务变更记录相关文件
dev
zch 2 weeks ago
parent 2b9953a0e7
commit ce2f895c12

@ -1,76 +0,0 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { ErpTempTaskChangeForm, ErpTempTaskChangeQuery, ErpTempTaskChangeVO } from '@/api/oa/erp/erpTempTaskChange/types';
/**
*
* @param query
* @returns {*}
*/
export const listErpTempTaskChange = (query?: ErpTempTaskChangeQuery): AxiosPromise<ErpTempTaskChangeVO[]> => {
return request({
url: '/oa/erp/erpTempTaskChange/list',
method: 'get',
params: query
});
};
/**
*
* @param changeId
*/
export const getErpTempTaskChange = (changeId: string | number): AxiosPromise<ErpTempTaskChangeVO> => {
return request({
url: '/oa/erp/erpTempTaskChange/' + changeId,
method: 'get'
});
};
/**
*
* @param data
*/
export const addErpTempTaskChange = (data: ErpTempTaskChangeForm) => {
return request({
url: '/oa/erp/erpTempTaskChange',
method: 'post',
data: data
});
};
/**
*
* @param data
*/
export const updateErpTempTaskChange = (data: ErpTempTaskChangeForm) => {
return request({
url: '/oa/erp/erpTempTaskChange',
method: 'put',
data: data
});
};
/**
*
* @param changeId
*/
export const delErpTempTaskChange = (changeId: string | number | Array<string | number>) => {
return request({
url: '/oa/erp/erpTempTaskChange/' + changeId,
method: 'delete'
});
};
/**
*
* @param query
* @returns {*}
*/
export function getErpTempTaskChangeList(query) {
return request({
url: '/oa/erp/erpTempTaskChange/getErpTempTaskChangeList',
method: 'get',
params: query
});
}

@ -1,281 +0,0 @@
export interface ErpTempTaskChangeVO {
/**
* ID
*/
changeId: string | number;
/**
* ID
*/
tempTaskId: string | number;
/**
*
*/
tempTaskCode: string;
/**
* 1 2 3 4/ 5 6 7/
*/
changeType: string;
/**
*
*/
changeReason: string;
/**
*
*/
beforeContent: string;
/**
*
*/
afterContent: string;
/**
* /
*/
workloadEffect: string;
/**
* /
*/
timeEffect: string;
/**
* //
*/
scopeEffect: string;
/**
* ID//
*/
changeUserId: string | number;
/**
*
*/
changeUserName: string;
/**
* 1 2 3退 4/
*/
approveResult: string;
/**
* ID
*/
approverId: string | number;
/**
*
*/
approverName: string;
/**
*
*/
approveComment: string;
/**
*
*/
approveTime: string;
/**
*
*/
flowStatus: string;
}
export interface ErpTempTaskChangeForm extends BaseEntity {
/**
* ID
*/
changeId?: string | number;
/**
* ID
*/
tempTaskId?: string | number;
/**
*
*/
tempTaskCode?: string;
/**
* 1 2 3 4/ 5 6 7/
*/
changeType?: string;
/**
*
*/
changeReason?: string;
/**
*
*/
beforeContent?: string;
/**
*
*/
afterContent?: string;
/**
* /
*/
workloadEffect?: string;
/**
* /
*/
timeEffect?: string;
/**
* //
*/
scopeEffect?: string;
/**
* ID//
*/
changeUserId?: string | number;
/**
*
*/
changeUserName?: string;
/**
* 1 2 3退 4/
*/
approveResult?: string;
/**
* ID
*/
approverId?: string | number;
/**
*
*/
approverName?: string;
/**
*
*/
approveComment?: string;
/**
*
*/
approveTime?: string;
/**
*
*/
flowStatus?: string;
}
export interface ErpTempTaskChangeQuery extends PageQuery {
/**
* ID
*/
tempTaskId?: string | number;
/**
*
*/
tempTaskCode?: string;
/**
* 1 2 3 4/ 5 6 7/
*/
changeType?: string;
/**
*
*/
changeReason?: string;
/**
*
*/
beforeContent?: string;
/**
*
*/
afterContent?: string;
/**
* /
*/
workloadEffect?: string;
/**
* /
*/
timeEffect?: string;
/**
* //
*/
scopeEffect?: string;
/**
* ID//
*/
changeUserId?: string | number;
/**
*
*/
changeUserName?: string;
/**
* 1 2 3退 4/
*/
approveResult?: string;
/**
* ID
*/
approverId?: string | number;
/**
*
*/
approverName?: string;
/**
*
*/
approveComment?: string;
/**
*
*/
approveTime?: string;
/**
*
*/
flowStatus?: string;
/**
*
*/
params?: any;
}

@ -1,7 +1,23 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { TempTaskChangeForm, TempTaskChangeVO, TempTaskForm, TempTaskQuery, TempTaskVO } from '@/api/oa/erp/tempTask/types';
import {
TempTaskForm,
TempTaskQuery,
TempTaskVO,
TempTaskMemberVO,
TempTaskMemberForm,
TempTaskWorklogVO,
TempTaskWorklogForm,
TempTaskFinishSubmitForm,
TempTaskScoreVO,
TempTaskScoreSubmitForm
} from '@/api/oa/erp/tempTask/types';
/**
*
* /
* @param query
*/
export const listTempTask = (query?: TempTaskQuery): AxiosPromise<TempTaskVO[]> => {
return request({
url: '/oa/erp/tempTask/list',
@ -10,6 +26,11 @@ export const listTempTask = (query?: TempTaskQuery): AxiosPromise<TempTaskVO[]>
});
};
/**
*
*
* @param tempTaskId ID
*/
export const getTempTask = (tempTaskId: string | number): AxiosPromise<TempTaskVO> => {
return request({
url: `/oa/erp/tempTask/${tempTaskId}`,
@ -17,6 +38,11 @@ export const getTempTask = (tempTaskId: string | number): AxiosPromise<TempTaskV
});
};
/**
* 稿
* `taskStatus = '1'` `flowStatus = 'draft'`
* LSRW+yyyyMMdd+4
*/
export const addTempTask = (data: TempTaskForm) => {
return request({
url: '/oa/erp/tempTask',
@ -25,6 +51,10 @@ export const addTempTask = (data: TempTaskForm) => {
});
};
/**
*
* 稿退`canEdit = true`
*/
export const updateTempTask = (data: TempTaskForm) => {
return request({
url: '/oa/erp/tempTask',
@ -33,6 +63,10 @@ export const updateTempTask = (data: TempTaskForm) => {
});
};
/**
*
* 稿/退/
*/
export const delTempTask = (tempTaskId: string | number | Array<string | number>) => {
return request({
url: `/oa/erp/tempTask/${tempTaskId}`,
@ -40,6 +74,10 @@ export const delTempTask = (tempTaskId: string | number | Array<string | number>
});
};
/**
*
*
*/
export const getTempTaskList = (query?: TempTaskQuery): AxiosPromise<TempTaskVO[]> => {
return request({
url: '/oa/erp/tempTask/getErpTempTaskList',
@ -48,6 +86,11 @@ export const getTempTaskList = (query?: TempTaskQuery): AxiosPromise<TempTaskVO[
});
};
/**
* Warm-Flow
* (`taskStatus = '2'`) / `flowStatus = 'waiting'`
* variables(ignore=true, has_assignee) bizExt
*/
export const tempTaskSubmitAndFlowStart = (data: TempTaskForm): AxiosPromise<TempTaskVO> => {
return request({
url: '/oa/erp/tempTask/submit',
@ -56,33 +99,131 @@ export const tempTaskSubmitAndFlowStart = (data: TempTaskForm): AxiosPromise<Tem
});
};
export const closeTempTask = (data: TempTaskForm) => {
/**
* V3AD-12
* /// submitVerifycompleteTask
*/
export const assigneeReviewTempTask = (data: TempTaskForm) => {
return request({
url: '/oa/erp/tempTask/close',
url: '/oa/erp/tempTask/assigneeReview',
method: 'post',
data
});
};
export const listTempTaskChange = (tempTaskId: string | number): AxiosPromise<TempTaskChangeVO[]> => {
/**
* reassigned AD-12
*/
export const leaderReviewTempTaskVariables = (data: TempTaskForm): AxiosPromise<Record<string, unknown>> => {
return request({
url: `/oa/erp/tempTask/${tempTaskId}/changes`,
url: '/oa/erp/tempTask/leaderReviewVariables',
method: 'post',
data
});
};
/**
* Warm-Flow
*/
export const leaderReviewAndCompleteTempTask = (data: TempTaskForm) => {
return request({
url: '/oa/erp/tempTask/leaderReviewComplete',
method: 'post',
data
});
};
/**
* +AD-13
*/
export const listTempTaskMember = (tempTaskId: string | number): AxiosPromise<TempTaskMemberVO[]> => {
return request({
url: `/oa/erp/tempTask/${tempTaskId}/members`,
method: 'get'
});
};
export const addTempTaskChange = (data: TempTaskChangeForm) => {
/**
* AD-13
*/
export const addTempTaskMember = (data: TempTaskMemberForm) => {
return request({
url: '/oa/erp/tempTask/change',
url: '/oa/erp/tempTask/member',
method: 'post',
data
});
};
export const approveTempTaskChange = (data: TempTaskChangeForm) => {
/**
*
*/
export const delTempTaskMember = (memberId: string | number) => {
return request({
url: '/oa/erp/tempTask/change/approve',
url: `/oa/erp/tempTask/member/${memberId}`,
method: 'delete'
});
};
/**
* AD-07~AD-09
*/
export const listTempTaskWorklog = (tempTaskId: string | number): AxiosPromise<TempTaskWorklogVO[]> => {
return request({
url: `/oa/erp/tempTask/${tempTaskId}/worklogs`,
method: 'get'
});
};
/**
* /
* workDate ///
*/
export const saveTempTaskWorklog = (data: TempTaskWorklogForm) => {
return request({
url: '/oa/erp/tempTask/worklog',
method: 'post',
data
});
};
/**
*
*/
export const delTempTaskWorklog = (worklogId: string | number) => {
return request({
url: `/oa/erp/tempTask/worklog/${worklogId}`,
method: 'delete'
});
};
/**
* AD-14/AD-15
*/
export const submitFinishTempTask = (data: TempTaskFinishSubmitForm) => {
return request({
url: '/oa/erp/tempTask/submitFinish',
method: 'post',
data
});
};
/**
* AD-05/AD-16
*/
export const scoreAndCloseTempTask = (data: TempTaskScoreSubmitForm) => {
return request({
url: '/oa/erp/tempTask/scoreAndClose',
method: 'post',
data
});
};
/**
* AD-16
*/
export const listTempTaskScore = (tempTaskId: string | number): AxiosPromise<TempTaskScoreVO[]> => {
return request({
url: `/oa/erp/tempTask/${tempTaskId}/scores`,
method: 'get'
});
};

@ -1,164 +1,254 @@
/**
* VO ( ErpTempTaskVo )
*/
export interface TempTaskVO {
/** 临时任务唯一主键ID */
tempTaskId: string | number;
/** 临时任务唯一全局编号 */
tempTaskCode: string;
/** 临时任务标题 */
taskTitle?: string;
/** 临时任务描述 */
taskDesc: string;
priority?: string;
urgentReason?: string;
requireTime: string;
confirmFinishTime?: string;
/** 任务类型1部门 2市场 3项目 */
taskType?: string;
/** 计划开始时间 */
planStartTime?: string;
/** 计划完成时间 */
planEndTime?: string;
/** 实际开始时间 */
actualStartTime?: string;
/** 实际结束/关闭时间 */
actualFinishTime?: string;
/** 主报工项目ID */
projectId?: string | number;
/** 项目编号快照 */
projectCode?: string;
/** 项目名称快照 */
projectName?: string;
pmId?: string | number;
pmName?: string;
contractId?: string | number;
contractCode?: string;
/** 归集部门ID */
deptId?: string | number;
/** 归集部门名称快照 */
deptName?: string;
/** 发起人用户ID */
requesterId?: string | number;
/** 发起人姓名快照 */
requesterName?: string;
requestDeptId?: string | number;
requestDeptName?: string;
dispatcherId?: string | number;
dispatcherName?: string;
/** 实际需求人ID */
realRequesterId?: string | number;
/** 实际需求人姓名快照 */
realRequesterName?: string;
/** 实际需求部门ID */
realRequestDeptId?: string | number;
/** 实际需求部门名称快照 */
realRequestDeptName?: string;
/** 软件部领导用户ID */
softwareLeaderId?: string | number;
/** 软件部领导姓名快照 */
softwareLeaderName?: string;
/** 主执行人用户ID */
assigneeId?: string | number;
/** 主执行人姓名快照 */
assigneeName?: string;
/** 预计工时 */
estimateWorkload?: number;
actualWorkload?: number;
finishResult?: string;
terminateReason?: string;
finishRemark?: string;
relatedTaskId?: string | number;
relatedTaskCode?: string;
relateReason?: string;
relateRemark?: string;
/** 累计总工时 */
totalHours?: number;
/** 业务状态1暂存 2审批中 3执行中 4待领导审核 5已关闭 6作废 */
taskStatus?: string;
/** 工作流状态 */
flowStatus?: string;
/** 抄送人员用户ID */
ccUserIds?: string;
ossId?: string;
/** 备注 */
remark?: string;
changeCount?: number;
pendingChangeCount?: number;
/** 参与人列表 */
members?: TempTaskMemberVO[];
/** 工时明细列表 */
worklogs?: TempTaskWorklogVO[];
/** 可见评分列表 */
scores?: TempTaskScoreVO[];
/** 创建时间 */
createTime?: string;
}
/**
*
*/
export interface TempTaskForm extends BaseEntity {
tempTaskId?: string | number;
taskId?: string | number;
tempTaskCode?: string;
taskTitle?: string;
taskDesc?: string;
priority?: string;
urgentReason?: string;
requireTime?: string;
confirmFinishTime?: string;
taskType?: string;
planStartTime?: string;
planEndTime?: string;
actualStartTime?: string;
actualFinishTime?: string;
projectId?: string | number;
projectCode?: string;
projectName?: string;
pmId?: string | number;
pmName?: string;
contractId?: string | number;
contractCode?: string;
deptId?: string | number;
deptName?: string;
requesterId?: string | number;
requesterName?: string;
requestDeptId?: string | number;
requestDeptName?: string;
dispatcherId?: string | number;
dispatcherName?: string;
realRequesterId?: string | number;
realRequesterName?: string;
realRequestDeptId?: string | number;
realRequestDeptName?: string;
softwareLeaderId?: string | number;
softwareLeaderName?: string;
assigneeId?: string | number;
assigneeName?: string;
assigneeOpinion?: string;
leaderOpinion?: string;
leaderFinalOpinion?: string;
estimateWorkload?: number;
actualWorkload?: number;
finishResult?: string;
terminateReason?: string;
finishRemark?: string;
relatedTaskId?: string | number;
relatedTaskCode?: string;
relateReason?: string;
relateRemark?: string;
totalHours?: number;
taskStatus?: string;
flowStatus?: string;
ccUserIds?: string;
ossId?: string;
remark?: string;
changeCount?: number;
pendingChangeCount?: number;
/** 流程定义编码,固定传入 OATT */
flowCode?: string;
/** 工作流办理过程中传递的变量Map */
variables?: Record<string, unknown>;
/** 流程实例业务扩展载荷 */
bizExt?: Record<string, unknown>;
}
/**
*
*/
export interface TempTaskQuery extends PageQuery {
tempTaskCode?: string;
taskTitle?: string;
taskDesc?: string;
priority?: string;
taskType?: string;
projectId?: string | number;
projectCode?: string;
projectName?: string;
deptId?: string | number;
deptName?: string;
realRequesterId?: string | number;
realRequesterName?: string;
realRequestDeptId?: string | number;
realRequestDeptName?: string;
requesterId?: string | number;
requesterName?: string;
requestDeptId?: string | number;
requestDeptName?: string;
dispatcherId?: string | number;
dispatcherName?: string;
assigneeId?: string | number;
assigneeName?: string;
finishResult?: string;
terminateReason?: string;
relatedTaskId?: string | number;
relatedTaskCode?: string;
relateReason?: string;
softwareLeaderId?: string | number;
taskStatus?: string;
flowStatus?: string;
/** 额外扩展查询 Map 载荷,如 beginActualFinishTime/endActualFinishTime */
params?: Record<string, unknown>;
}
export interface TempTaskChangeVO {
changeId: string | number;
/**
* VO
*/
export interface TempTaskMemberVO {
memberId: string | number;
tempTaskId: string | number;
tempTaskCode?: string;
changeType: string;
changeReason: string;
beforeContent?: string;
afterContent?: string;
workloadEffect?: string;
timeEffect?: string;
scopeEffect?: string;
changeUserId?: string | number;
changeUserName?: string;
approveResult?: string;
approverId?: string | number;
approverName?: string;
approveComment?: string;
approveTime?: string;
flowStatus?: string;
createTime?: string;
/** 参与类型1主执行人 2协作人 */
memberType: string;
userId: string | number;
userName?: string;
memberDeptId?: string | number;
joinRemark?: string;
}
export interface TempTaskChangeForm extends BaseEntity {
changeId?: string | number;
/**
*
*/
export interface TempTaskMemberForm {
memberId?: string | number;
tempTaskId?: string | number;
tempTaskCode?: string;
changeType?: string;
changeReason?: string;
beforeContent?: string;
afterContent?: string;
workloadEffect?: string;
timeEffect?: string;
scopeEffect?: string;
changeUserId?: string | number;
changeUserName?: string;
approveResult?: string;
approverId?: string | number;
approverName?: string;
approveComment?: string;
approveTime?: string;
flowStatus?: string;
memberType?: string;
userId?: string | number;
userName?: string;
memberDeptId?: string | number;
joinRemark?: string;
}
/**
* VO
*/
export interface TempTaskWorklogVO {
worklogId: string | number;
tempTaskId: string | number;
memberId: string | number;
userId: string | number;
userName?: string;
/** 自然周周一 */
weekStart: string;
/** 自然周周日 */
weekEnd: string;
/** 工作日期 */
workDate: string;
/** 本条工时最小0.5 */
hours: number;
workContent: string;
ossId?: string;
/** 锁定标志0可编辑 1已锁定 */
lockFlag: string;
}
/**
*
*/
export interface TempTaskWorklogForm {
worklogId?: string | number;
tempTaskId?: string | number;
workDate?: string;
hours?: number;
workContent?: string;
ossId?: string;
}
/**
*
*/
export interface TempTaskFinishSubmitForm {
tempTaskId: string | number;
taskId: string | number;
finishOpinion?: string;
}
/**
* VO
*/
export interface TempTaskScoreVO {
scoreId: string | number;
tempTaskId: string | number;
memberId: string | number;
userId: string | number;
userName?: string;
/** 评分等级A++ A+ A B C */
scoreGrade: string;
scoreRemark?: string;
scorerId?: string | number;
scoreTime?: string;
}
/**
*
*/
export interface TempTaskScoreForm {
memberId?: string | number;
userId: string | number;
scoreGrade: string;
scoreRemark?: string;
}
/**
*
*/
export interface TempTaskScoreSubmitForm {
tempTaskId: string | number;
taskId: string | number;
leaderFinalOpinion?: string;
scoreList: TempTaskScoreForm[];
}

@ -90,6 +90,10 @@ export enum ProjectCategoryEnum {
*
*/
export enum FlowCodeEnum {
/**
* KEY
*/
TEMP_TASK_CODE = 'OATT',
/**
* KEY
*/

@ -1 +1,12 @@
export type { TempTaskChangeForm, TempTaskChangeVO, TempTaskForm, TempTaskQuery, TempTaskVO } from '@/api/oa/erp/tempTask/types';
export type {
TempTaskForm,
TempTaskQuery,
TempTaskVO,
TempTaskMemberVO,
TempTaskMemberForm,
TempTaskWorklogVO,
TempTaskWorklogForm,
TempTaskScoreVO,
TempTaskScoreForm,
TempTaskScoreSubmitForm
} from '@/api/oa/erp/tempTask/types';

@ -1,408 +0,0 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="100px">
<el-form-item label="临时任务ID" prop="tempTaskId">
<el-input v-model="queryParams.tempTaskId" placeholder="请输入临时任务ID" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="任务编号快照" prop="tempTaskCode">
<el-input v-model="queryParams.tempTaskCode" placeholder="请输入任务编号快照" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="变更原因" prop="changeReason">
<el-input v-model="queryParams.changeReason" placeholder="请输入变更原因" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="工时影响" prop="workloadEffect">
<el-input v-model="queryParams.workloadEffect" placeholder="请输入工时影响" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="时间影响" prop="timeEffect">
<el-input v-model="queryParams.timeEffect" placeholder="请输入时间影响" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="执行影响说明" prop="scopeEffect">
<el-input v-model="queryParams.scopeEffect" placeholder="请输入执行影响说明" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="变更发起人ID" prop="changeUserId">
<el-input v-model="queryParams.changeUserId" placeholder="请输入变更发起人ID" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="变更发起人姓名快照" prop="changeUserName">
<el-input v-model="queryParams.changeUserName" placeholder="请输入变更发起人姓名快照" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="审批结论1通过 2不通过 3退回补充 4终止/不执行" prop="approveResult">
<el-input
v-model="queryParams.approveResult"
placeholder="请输入审批结论1通过 2不通过 3退回补充 4终止/不执行"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="审批人ID" prop="approverId">
<el-input v-model="queryParams.approverId" placeholder="请输入审批人ID" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="审批人姓名快照" prop="approverName">
<el-input v-model="queryParams.approverName" placeholder="请输入审批人姓名快照" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="审批意见" prop="approveComment">
<el-input v-model="queryParams.approveComment" placeholder="请输入审批意见" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="审批时间" prop="approveTime">
<el-date-picker clearable v-model="queryParams.approveTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择审批时间" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery"></el-button>
<el-button icon="Refresh" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['oa:erp:erpTempTaskChange:add']"></el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['oa:erp:erpTempTaskChange:edit']"
>修改</el-button
>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['oa:erp:erpTempTaskChange:remove']"
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['oa:erp:erpTempTaskChange:export']"></el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" :columns="columns" :search="true" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" border :data="erpTempTaskChangeList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="变更记录ID" align="center" prop="changeId" v-if="columns[0].visible" />
<el-table-column label="临时任务ID" align="center" prop="tempTaskId" v-if="columns[2].visible" />
<el-table-column label="任务编号快照" align="center" prop="tempTaskCode" v-if="columns[3].visible" />
<el-table-column
label="变更项类型1任务描述 2工时 3需求时间 4指派人/执行人 5可报工项目 6执行范围 7终止/不执行"
align="center"
prop="changeType"
v-if="columns[4].visible"
/>
<el-table-column label="变更原因" align="center" prop="changeReason" v-if="columns[5].visible" />
<el-table-column label="变更前内容" align="center" prop="beforeContent" v-if="columns[6].visible" />
<el-table-column label="变更后内容" align="center" prop="afterContent" v-if="columns[7].visible" />
<el-table-column label="工时影响" align="center" prop="workloadEffect" v-if="columns[8].visible" />
<el-table-column label="时间影响" align="center" prop="timeEffect" v-if="columns[9].visible" />
<el-table-column label="执行影响说明" align="center" prop="scopeEffect" v-if="columns[10].visible" />
<el-table-column label="变更发起人ID" align="center" prop="changeUserId" v-if="columns[11].visible" />
<el-table-column label="变更发起人姓名快照" align="center" prop="changeUserName" v-if="columns[12].visible" />
<el-table-column label="审批结论1通过 2不通过 3退回补充 4终止/不执行" align="center" prop="approveResult" v-if="columns[13].visible" />
<el-table-column label="审批人ID" align="center" prop="approverId" v-if="columns[14].visible" />
<el-table-column label="审批人姓名快照" align="center" prop="approverName" v-if="columns[15].visible" />
<el-table-column label="审批意见" align="center" prop="approveComment" v-if="columns[16].visible" />
<el-table-column label="审批时间" align="center" prop="approveTime" width="180" v-if="columns[17].visible">
<template #default="scope">
<span>{{ parseTime(scope.row.approveTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="变更审批流程状态" align="center" prop="flowStatus" v-if="columns[18].visible" />
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['oa:erp:erpTempTaskChange:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button
link
type="primary"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['oa:erp:erpTempTaskChange:remove']"
></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改临时任务变更记录对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="erpTempTaskChangeFormRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="临时任务ID" prop="tempTaskId">
<el-input v-model="form.tempTaskId" placeholder="请输入临时任务ID" />
</el-form-item>
<el-form-item label="任务编号快照" prop="tempTaskCode">
<el-input v-model="form.tempTaskCode" placeholder="请输入任务编号快照" />
</el-form-item>
<el-form-item label="变更原因" prop="changeReason">
<el-input v-model="form.changeReason" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="变更前内容">
<editor v-model="form.beforeContent" :min-height="192" />
</el-form-item>
<el-form-item label="变更后内容">
<editor v-model="form.afterContent" :min-height="192" />
</el-form-item>
<el-form-item label="工时影响" prop="workloadEffect">
<el-input v-model="form.workloadEffect" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="时间影响" prop="timeEffect">
<el-input v-model="form.timeEffect" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="执行影响说明" prop="scopeEffect">
<el-input v-model="form.scopeEffect" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="变更发起人ID" prop="changeUserId">
<el-input v-model="form.changeUserId" placeholder="请输入变更发起人ID" />
</el-form-item>
<el-form-item label="变更发起人姓名快照" prop="changeUserName">
<el-input v-model="form.changeUserName" placeholder="请输入变更发起人姓名快照" />
</el-form-item>
<el-form-item label="审批结论1通过 2不通过 3退回补充 4终止/不执行" prop="approveResult">
<el-input v-model="form.approveResult" placeholder="请输入审批结论1通过 2不通过 3退回补充 4终止/不执行" />
</el-form-item>
<el-form-item label="审批人ID" prop="approverId">
<el-input v-model="form.approverId" placeholder="请输入审批人ID" />
</el-form-item>
<el-form-item label="审批人姓名快照" prop="approverName">
<el-input v-model="form.approverName" placeholder="请输入审批人姓名快照" />
</el-form-item>
<el-form-item label="审批意见" prop="approveComment">
<el-input v-model="form.approveComment" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="审批时间" prop="approveTime">
<el-date-picker clearable v-model="form.approveTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择审批时间">
</el-date-picker>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="ErpTempTaskChange" lang="ts">
import {
addErpTempTaskChange,
delErpTempTaskChange,
getErpTempTaskChange,
listErpTempTaskChange,
updateErpTempTaskChange
} from '@/api/oa/erp/erpTempTaskChange';
import { ErpTempTaskChangeForm, ErpTempTaskChangeQuery, ErpTempTaskChangeVO } from '@/api/oa/erp/erpTempTaskChange/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const erpTempTaskChangeList = ref<ErpTempTaskChangeVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const erpTempTaskChangeFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
//
const columns = ref<FieldOption[]>([
{ key: 0, label: `变更记录ID`, visible: true },
{ key: 1, label: `租户编号`, visible: true },
{ key: 2, label: `临时任务ID`, visible: true },
{ key: 3, label: `任务编号快照`, visible: true },
{ key: 4, label: `变更项类型1任务描述 2工时 3需求时间 4指派人/执行人 5可报工项目 6执行范围 7终止/不执行`, visible: true },
{ key: 5, label: `变更原因`, visible: true },
{ key: 6, label: `变更前内容`, visible: true },
{ key: 7, label: `变更后内容`, visible: true },
{ key: 8, label: `工时影响`, visible: true },
{ key: 9, label: `时间影响`, visible: true },
{ key: 10, label: `执行影响说明`, visible: true },
{ key: 11, label: `变更发起人ID`, visible: true },
{ key: 12, label: `变更发起人姓名快照`, visible: true },
{ key: 13, label: `审批结论1通过 2不通过 3退回补充 4终止/不执行`, visible: true },
{ key: 14, label: `审批人ID`, visible: true },
{ key: 15, label: `审批人姓名快照`, visible: true },
{ key: 16, label: `审批意见`, visible: true },
{ key: 17, label: `审批时间`, visible: true },
{ key: 18, label: `变更审批流程状态`, visible: true },
{ key: 19, label: `删除标志`, visible: true },
{ key: 20, label: `创建部门`, visible: true },
{ key: 21, label: `创建者`, visible: true },
{ key: 22, label: `创建时间`, visible: true },
{ key: 23, label: `更新者`, visible: true },
{ key: 24, label: `更新时间`, visible: true }
]);
const initFormData: ErpTempTaskChangeForm = {
changeId: undefined,
tempTaskId: undefined,
tempTaskCode: undefined,
changeType: undefined,
changeReason: undefined,
beforeContent: undefined,
afterContent: undefined,
workloadEffect: undefined,
timeEffect: undefined,
scopeEffect: undefined,
changeUserId: undefined,
changeUserName: undefined,
approveResult: undefined,
approverId: undefined,
approverName: undefined,
approveComment: undefined,
approveTime: undefined,
flowStatus: undefined
};
const data = reactive<PageData<ErpTempTaskChangeForm, ErpTempTaskChangeQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
tempTaskId: undefined,
tempTaskCode: undefined,
changeType: undefined,
changeReason: undefined,
beforeContent: undefined,
afterContent: undefined,
workloadEffect: undefined,
timeEffect: undefined,
scopeEffect: undefined,
changeUserId: undefined,
changeUserName: undefined,
approveResult: undefined,
approverId: undefined,
approverName: undefined,
approveComment: undefined,
approveTime: undefined,
flowStatus: undefined,
params: {}
},
rules: {
changeId: [{ required: true, message: '变更记录ID不能为空', trigger: 'blur' }],
tempTaskId: [{ required: true, message: '临时任务ID不能为空', trigger: 'blur' }],
changeType: [
{
required: true,
message: '变更项类型1任务描述 2工时 3需求时间 4指派人/执行人 5可报工项目 6执行范围 7终止/不执行不能为空',
trigger: 'change'
}
],
changeReason: [{ required: true, message: '变更原因不能为空', trigger: 'blur' }],
changeUserId: [{ required: true, message: '变更发起人ID不能为空', trigger: 'blur' }]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询临时任务变更记录列表 */
const getList = async () => {
loading.value = true;
const res = await listErpTempTaskChange(queryParams.value);
erpTempTaskChangeList.value = res.rows;
total.value = res.total;
loading.value = false;
};
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
};
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
erpTempTaskChangeFormRef.value?.resetFields();
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: ErpTempTaskChangeVO[]) => {
ids.value = selection.map((item) => item.changeId);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
/** 新增按钮操作 */
const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = '添加临时任务变更记录';
};
/** 修改按钮操作 */
const handleUpdate = async (row?: ErpTempTaskChangeVO) => {
reset();
const _changeId = row?.changeId || ids.value[0];
const res = await getErpTempTaskChange(_changeId);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = '修改临时任务变更记录';
};
/** 提交按钮 */
const submitForm = () => {
erpTempTaskChangeFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.changeId) {
await updateErpTempTaskChange(form.value).finally(() => (buttonLoading.value = false));
} else {
await addErpTempTaskChange(form.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
};
/** 删除按钮操作 */
const handleDelete = async (row?: ErpTempTaskChangeVO) => {
const _changeIds = row?.changeId || ids.value;
await proxy?.$modal.confirm('是否确认删除临时任务变更记录编号为"' + _changeIds + '"的数据项?').finally(() => (loading.value = false));
await delErpTempTaskChange(_changeIds);
proxy?.$modal.msgSuccess('删除成功');
await getList();
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download(
'oa/erp/erpTempTaskChange/export',
{
...queryParams.value
},
`erpTempTaskChange_${new Date().getTime()}.xlsx`
);
};
onMounted(() => {
getList();
});
</script>

File diff suppressed because it is too large Load Diff

@ -10,9 +10,9 @@
<el-form-item label="任务描述" prop="taskDesc">
<el-input v-model="queryParams.taskDesc" placeholder="请输入任务描述" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="优先级" prop="priority">
<el-select v-model="queryParams.priority" placeholder="请选择优先级" clearable>
<el-option v-for="dict in temp_task_priority" :key="dict.value" :label="dict.label" :value="dict.value" />
<el-form-item label="任务类型" prop="taskType">
<el-select v-model="queryParams.taskType" placeholder="请选择任务类型" clearable>
<el-option v-for="dict in temp_task_type" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="项目" prop="projectName">
@ -22,25 +22,25 @@
</template>
</el-input>
</el-form-item>
<el-form-item label="归集部门" prop="deptId">
<el-select v-model="queryParams.deptId" placeholder="请选择部门" clearable filterable @change="handleDeptChange">
<el-option v-for="dept in deptList" :key="dept.deptId" :label="dept.deptName" :value="dept.deptId" />
</el-select>
</el-form-item>
<el-form-item label="发起人" prop="requesterName">
<el-input v-model="queryParams.requesterName" placeholder="请输入发起人" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="指派人" prop="dispatcherName">
<el-input v-model="queryParams.dispatcherName" placeholder="请输入指派人" clearable @keyup.enter="handleQuery" />
<el-form-item label="实际需求人" prop="realRequesterName">
<el-input v-model="queryParams.realRequesterName" placeholder="请输入实际需求人" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="执行人" prop="assigneeName">
<el-input v-model="queryParams.assigneeName" placeholder="请输入执行人" clearable @keyup.enter="handleQuery" />
<el-form-item label="执行人" prop="assigneeName">
<el-input v-model="queryParams.assigneeName" placeholder="请输入执行人" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="业务状态" prop="taskStatus">
<el-select v-model="queryParams.taskStatus" placeholder="请选择业务状态" clearable>
<el-option v-for="dict in temp_task_status" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="完成结果" prop="finishResult">
<el-select v-model="queryParams.finishResult" placeholder="请选择完成结果" clearable>
<el-option v-for="dict in temp_task_finish_result" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery"></el-button>
<el-button icon="Refresh" @click="resetQuery"></el-button>
@ -75,58 +75,62 @@
<el-tabs v-model="activeTab" class="mb-2" @tab-change="handleTabChange">
<el-tab-pane label="全部" name="all" />
<el-tab-pane label="草稿" name="draft" />
<el-tab-pane label="在办/未关闭" name="running" />
<el-tab-pane label="已结束" name="finished" />
<el-tab-pane label="暂存" name="draft" />
<el-tab-pane label="审批中" name="approving" />
<el-tab-pane label="执行中" name="running" />
<el-tab-pane label="待领导审核" name="pendingFinal" />
<el-tab-pane label="已关闭" name="closed" />
<el-tab-pane label="作废" name="invalid" />
</el-tabs>
<el-table v-loading="loading" border :data="tempTaskList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column type="index" label="序号" width="70" align="center" v-if="columns[0].visible" />
<el-table-column label="任务编号" prop="tempTaskCode" min-width="150" align="center" v-if="columns[1].visible" />
<el-table-column label="任务标题" prop="taskTitle" min-width="160" show-overflow-tooltip align="center" v-if="columns[2].visible" />
<el-table-column label="任务描述" prop="taskDesc" min-width="220" show-overflow-tooltip align="center" v-if="columns[3].visible" />
<el-table-column label="优先级" prop="priority" width="90" align="center" v-if="columns[4].visible">
<el-table-column label="任务类型" prop="taskType" width="100" align="center" v-if="columns[2].visible">
<template #default="scope">
<dict-tag :options="temp_task_priority" :value="scope.row.priority" />
<dict-tag :options="temp_task_type" :value="scope.row.taskType" />
</template>
</el-table-column>
<el-table-column label="需求时间" prop="requireTime" width="150" align="center" v-if="columns[5].visible">
<el-table-column label="任务标题" prop="taskTitle" min-width="160" show-overflow-tooltip align="center" v-if="columns[3].visible" />
<el-table-column label="任务描述" prop="taskDesc" min-width="220" show-overflow-tooltip align="center" v-if="columns[4].visible" />
<el-table-column label="计划开始" prop="planStartTime" width="150" align="center" v-if="columns[5].visible">
<template #default="scope">
<span>{{ parseTime(scope.row.requireTime, '{y}-{m}-{d}') }}</span>
<span>{{ parseTime(scope.row.planStartTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="确认完成时间" prop="confirmFinishTime" width="150" align="center" v-if="columns[6].visible">
<el-table-column label="计划完成" prop="planEndTime" width="150" align="center" v-if="columns[6].visible">
<template #default="scope">
<span>{{ parseTime(scope.row.confirmFinishTime, '{y}-{m}-{d}') }}</span>
<span>{{ parseTime(scope.row.planEndTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="项目编号" prop="projectCode" width="140" align="center" v-if="columns[7].visible" />
<el-table-column label="项目名称" prop="projectName" min-width="170" show-overflow-tooltip align="center" v-if="columns[8].visible" />
<el-table-column label="项目名称" prop="projectName" min-width="170" show-overflow-tooltip align="center" v-if="columns[7].visible" />
<el-table-column label="归集部门" prop="deptName" width="130" show-overflow-tooltip align="center" v-if="columns[8].visible" />
<el-table-column label="发起人" prop="requesterName" width="100" align="center" v-if="columns[9].visible" />
<el-table-column label="发起部门" prop="requestDeptName" width="130" align="center" v-if="columns[10].visible" />
<el-table-column label="指派人" prop="dispatcherName" width="100" align="center" v-if="columns[11].visible" />
<el-table-column label="实际需求人" prop="realRequesterName" width="110" align="center" v-if="columns[10].visible" />
<el-table-column
label="实际需求部门"
prop="realRequestDeptName"
width="130"
show-overflow-tooltip
align="center"
v-if="columns[11].visible"
/>
<el-table-column label="软件部领导" prop="softwareLeaderName" width="120" align="center" v-if="columns[12].visible" />
<el-table-column label="主执行人" prop="assigneeName" width="110" align="center" v-if="columns[13].visible" />
<el-table-column label="预计工时" prop="estimateWorkload" width="100" align="center" v-if="columns[14].visible" />
<el-table-column label="实际工时" prop="actualWorkload" width="100" align="center" v-if="columns[15].visible" />
<el-table-column label="业务状态" prop="taskStatus" width="100" align="center" v-if="columns[16].visible">
<el-table-column label="累计工时" prop="totalHours" width="100" align="center" v-if="columns[15].visible" />
<el-table-column label="业务状态" prop="taskStatus" width="110" align="center" v-if="columns[16].visible">
<template #default="scope">
<dict-tag :options="temp_task_status" :value="scope.row.taskStatus" />
</template>
</el-table-column>
<el-table-column label="流程状态" prop="flowStatus" width="100" align="center" v-if="columns[17].visible">
<el-table-column label="流程状态" prop="flowStatus" width="110" align="center" v-if="columns[17].visible">
<template #default="scope">
<dict-tag :options="wf_business_status" :value="scope.row.flowStatus" />
</template>
</el-table-column>
<el-table-column label="完成结果" prop="finishResult" width="130" align="center" v-if="columns[18].visible">
<template #default="scope">
<dict-tag :options="temp_task_finish_result" :value="scope.row.finishResult" />
</template>
</el-table-column>
<el-table-column label="待审批变更" prop="pendingChangeCount" width="110" align="center" v-if="columns[19].visible" />
<el-table-column label="创建时间" prop="createTime" width="160" align="center" v-if="columns[20].visible">
<el-table-column label="创建时间" prop="createTime" width="160" align="center" v-if="columns[18].visible">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</template>
@ -148,7 +152,7 @@
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button
v-if="canEdit(scope.row)"
v-if="canDelete(scope.row)"
link
type="primary"
icon="Delete"
@ -170,6 +174,8 @@
<script setup name="TempTask" lang="ts">
import { delTempTask, listTempTask } from '@/api/oa/erp/tempTask';
import type { TempTaskQuery, TempTaskVO } from '@/api/oa/erp/tempTask/types';
import type { DeptVO } from '@/api/system/dept/types';
import { allListDept } from '@/api/system/dept';
import ProjectSelect from '@/components/ProjectSelect/index.vue';
import type { ProjectInfoVO } from '@/api/oa/erp/projectInfo/types';
@ -186,11 +192,12 @@ const parseTime = (time?: string, pattern?: string) => {
return String(time).replace('T', ' ').slice(0, 16);
};
const { temp_task_priority, temp_task_status, temp_task_finish_result, wf_business_status } = toRefs<any>(
proxy?.useDict('temp_task_priority', 'temp_task_status', 'temp_task_finish_result', 'wf_business_status')
const { temp_task_type, temp_task_status, wf_business_status } = toRefs<any>(
proxy?.useDict('temp_task_type', 'temp_task_status', 'wf_business_status')
);
const tempTaskList = ref<TempTaskVO[]>([]);
const deptList = ref<DeptVO[]>([]);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
@ -205,25 +212,23 @@ const projectSelectRef = ref<InstanceType<typeof ProjectSelect>>();
const columns = ref<FieldOption[]>([
{ key: 0, label: '序号', visible: true },
{ key: 1, label: '任务编号', visible: true },
{ key: 2, label: '任务标题', visible: true },
{ key: 3, label: '任务描述', visible: true },
{ key: 4, label: '优先级', visible: true },
{ key: 5, label: '需求时间', visible: true },
{ key: 6, label: '确认完成时间', visible: true },
{ key: 7, label: '项目编号', visible: true },
{ key: 8, label: '项目名称', visible: true },
{ key: 2, label: '任务类型', visible: true },
{ key: 3, label: '任务标题', visible: true },
{ key: 4, label: '任务描述', visible: true },
{ key: 5, label: '计划开始', visible: true },
{ key: 6, label: '计划完成', visible: true },
{ key: 7, label: '项目名称', visible: true },
{ key: 8, label: '归集部门', visible: true },
{ key: 9, label: '发起人', visible: true },
{ key: 10, label: '发起部门', visible: true },
{ key: 11, label: '指派人', visible: true },
{ key: 10, label: '实际需求人', visible: true },
{ key: 11, label: '实际需求部门', visible: true },
{ key: 12, label: '软件部领导', visible: true },
{ key: 13, label: '主执行人', visible: true },
{ key: 14, label: '预计工时', visible: true },
{ key: 15, label: '实际工时', visible: true },
{ key: 15, label: '累计工时', visible: true },
{ key: 16, label: '业务状态', visible: true },
{ key: 17, label: '流程状态', visible: true },
{ key: 18, label: '完成结果', visible: true },
{ key: 19, label: '待审批变更', visible: true },
{ key: 20, label: '创建时间', visible: true }
{ key: 18, label: '创建时间', visible: true }
]);
const queryParams = ref<TempTaskQuery>({
@ -231,31 +236,31 @@ const queryParams = ref<TempTaskQuery>({
pageSize: 10,
tempTaskCode: undefined,
taskDesc: undefined,
priority: undefined,
taskType: undefined,
projectId: undefined,
projectName: undefined,
deptId: undefined,
deptName: undefined,
requesterName: undefined,
dispatcherName: undefined,
realRequesterName: undefined,
assigneeName: undefined,
taskStatus: undefined,
flowStatus: undefined,
finishResult: undefined,
params: {}
});
const tabStatusMap: Record<string, string | undefined> = {
all: undefined,
draft: '1',
approving: '2',
running: '3',
pendingFinal: '4',
closed: '5',
invalid: '6'
};
const applyTabFilter = () => {
if (activeTab.value === 'draft') {
queryParams.value.taskStatus = '1';
queryParams.value.finishResult = undefined;
} else if (activeTab.value === 'running') {
queryParams.value.taskStatus = '2';
queryParams.value.finishResult = undefined;
} else if (activeTab.value === 'finished') {
queryParams.value.taskStatus = '3';
} else {
queryParams.value.taskStatus = undefined;
queryParams.value.finishResult = undefined;
}
queryParams.value.taskStatus = tabStatusMap[activeTab.value];
};
const getList = async () => {
@ -266,6 +271,16 @@ const getList = async () => {
total.value = res.total;
};
const getDeptList = async () => {
const res = await allListDept({ status: 0 } as any);
deptList.value = res.data || [];
};
const handleDeptChange = (deptId?: string | number) => {
const dept = deptList.value.find((item) => item.deptId === deptId);
queryParams.value.deptName = dept?.deptName;
};
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
@ -275,6 +290,8 @@ const resetQuery = () => {
queryFormRef.value?.resetFields();
queryParams.value.projectId = undefined;
queryParams.value.projectName = undefined;
queryParams.value.deptId = undefined;
queryParams.value.deptName = undefined;
handleQuery();
};
@ -303,7 +320,11 @@ const handleProjectSelect = (data: ProjectInfoVO[]) => {
};
const canEdit = (row: TempTaskVO) => {
return !row.finishResult && ['draft', 'back', 'cancel'].includes(row.flowStatus || '');
return ['draft', 'back', 'cancel'].includes(row.flowStatus || '');
};
const canDelete = (row: TempTaskVO) => {
return row.taskStatus === '1' && ['draft', 'back', 'cancel'].includes(row.flowStatus || '');
};
const openEditPage = (type: string, id?: string | number) => {
@ -340,16 +361,11 @@ const handleDelete = async (row?: TempTaskVO) => {
};
const handleExport = () => {
proxy?.download(
'oa/erp/tempTask/export',
{
...queryParams.value
},
`tempTask_${new Date().getTime()}.xlsx`
);
proxy?.download('oa/erp/tempTask/export', { ...queryParams.value }, `tempTask_${new Date().getTime()}.xlsx`);
};
onMounted(() => {
getList();
onMounted(async () => {
await getDeptList();
await getList();
});
</script>

@ -3,27 +3,22 @@
<el-card shadow="never" class="mb-3">
<el-form :model="queryParams" :inline="true" label-width="90px">
<el-form-item label="关闭月份">
<el-date-picker
v-model="finishMonth"
type="month"
value-format="YYYY-MM"
placeholder="请选择月份"
clearable
@change="handleQuery"
/>
<el-date-picker v-model="finishMonth" type="month" value-format="YYYY-MM" placeholder="请选择月份" clearable @change="handleQuery" />
</el-form-item>
<el-form-item label="执行人">
<el-input v-model="queryParams.assigneeName" placeholder="请输入执行人" clearable @keyup.enter="handleQuery" />
<el-form-item label="任务类型">
<el-select v-model="queryParams.taskType" placeholder="请选择任务类型" clearable>
<el-option v-for="dict in temp_task_type" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="主执行人">
<el-input v-model="queryParams.assigneeName" placeholder="请输入主执行人" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="项目">
<el-input v-model="queryParams.projectName" placeholder="请输入项目名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="发起部门">
<el-input v-model="queryParams.requestDeptName" placeholder="请输入发起部门" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="完成结果">
<el-select v-model="queryParams.finishResult" placeholder="请选择完成结果" clearable>
<el-option v-for="dict in temp_task_finish_result" :key="dict.value" :label="dict.label" :value="dict.value" />
<el-form-item label="归集部门">
<el-select v-model="queryParams.deptId" placeholder="请选择部门" clearable filterable>
<el-option v-for="dept in deptList" :key="dept.deptId" :label="dept.deptName" :value="dept.deptId" />
</el-select>
</el-form-item>
<el-form-item>
@ -43,45 +38,45 @@
<el-card shadow="never">
<el-tabs v-model="activeDimension">
<el-tab-pane label="按人员" name="assignee" />
<el-tab-pane label="按人员工时" name="member" />
<el-tab-pane label="按项目" name="project" />
<el-tab-pane label="按发起部门" name="dept" />
<el-tab-pane label="按完成结果" name="result" />
<el-tab-pane label="按关联链" name="chain" />
<el-tab-pane label="按归集部门" name="dept" />
<el-tab-pane label="按评分" name="score" />
</el-tabs>
<el-table v-loading="loading" :data="activeRows" border>
<el-table-column type="index" label="序号" width="70" align="center" />
<el-table-column :label="dimensionLabel" prop="name" min-width="220" show-overflow-tooltip align="center" />
<el-table-column label="任务数" prop="count" width="100" align="center" />
<el-table-column label="实际工时" prop="workload" width="120" align="center" />
<el-table-column label="平均工时" prop="avgWorkload" width="120" align="center" />
<el-table-column label="已完成" prop="finishedCount" width="100" align="center" />
<el-table-column label="不执行/终止" prop="terminatedCount" width="120" align="center" />
<el-table-column label="部分完成后终止" prop="partialTerminatedCount" width="140" align="center" />
<el-table-column label="任务数" prop="taskCount" width="100" align="center" />
<el-table-column label="工时合计" prop="hours" width="120" align="center" />
<el-table-column label="平均工时" prop="avgHours" width="120" align="center" />
<el-table-column label="评分数" prop="scoreCount" width="100" align="center" />
<el-table-column label="评分分布" prop="scoreSummary" min-width="180" show-overflow-tooltip align="center" />
</el-table>
<el-divider />
<el-table :data="detailRows" border>
<el-table :data="filteredTasks" border>
<el-table-column type="index" label="序号" width="70" align="center" />
<el-table-column label="任务编号" prop="tempTaskCode" width="150" align="center" />
<el-table-column label="任务类型" prop="taskType" width="100" align="center">
<template #default="scope">
<dict-tag :options="temp_task_type" :value="scope.row.taskType" />
</template>
</el-table-column>
<el-table-column label="任务描述" prop="taskDesc" min-width="240" show-overflow-tooltip align="center" />
<el-table-column label="主执行人" prop="assigneeName" width="110" align="center" />
<el-table-column label="项目名称" prop="projectName" min-width="170" show-overflow-tooltip align="center" />
<el-table-column label="发起部门" prop="requestDeptName" width="130" align="center" />
<el-table-column label="完成结果" prop="finishResult" width="130" align="center">
<template #default="scope">
<dict-tag :options="temp_task_finish_result" :value="scope.row.finishResult" />
</template>
<el-table-column label="归集部门" prop="deptName" width="130" align="center" />
<el-table-column label="工时合计" prop="totalHours" width="100" align="center" />
<el-table-column label="评分摘要" min-width="180" show-overflow-tooltip align="center">
<template #default="scope">{{ buildTaskScoreSummary(scope.row) }}</template>
</el-table-column>
<el-table-column label="实际工时" prop="actualWorkload" width="100" align="center" />
<el-table-column label="关闭时间" prop="actualFinishTime" width="160" align="center">
<template #default="scope">
<span>{{ formatDateTime(scope.row.actualFinishTime) }}</span>
</template>
</el-table-column>
<el-table-column label="关联原任务" prop="relatedTaskCode" width="150" align="center" />
</el-table>
</el-card>
</div>
@ -89,23 +84,43 @@
<script setup name="TempTaskReport" lang="ts">
import { listTempTask } from '@/api/oa/erp/tempTask';
import type { TempTaskQuery, TempTaskVO } from '@/api/oa/erp/tempTask/types';
import type { TempTaskQuery, TempTaskScoreVO, TempTaskVO, TempTaskWorklogVO } from '@/api/oa/erp/tempTask/types';
import type { DeptVO } from '@/api/system/dept/types';
import { allListDept } from '@/api/system/dept';
interface ReportWorklogRow extends TempTaskWorklogVO {
taskId: string | number;
taskCode: string;
projectName?: string;
deptName?: string;
}
interface ReportScoreRow extends TempTaskScoreVO {
taskId: string | number;
}
interface AggregateRow {
name: string;
count: number;
workload: number;
avgWorkload: number;
finishedCount: number;
terminatedCount: number;
partialTerminatedCount: number;
taskCount: number;
hours: number;
avgHours: number;
scoreCount: number;
scoreSummary: string;
}
interface AggregateDraft {
name: string;
taskIds: Set<string | number>;
hours: number;
scoreGrades: string[];
}
const { proxy } = getCurrentInstance() as any;
const { temp_task_finish_result } = toRefs<any>(proxy?.useDict('temp_task_finish_result'));
const { temp_task_type, temp_task_score } = toRefs<any>(proxy?.useDict('temp_task_type', 'temp_task_score'));
const loading = ref(false);
const activeDimension = ref('assignee');
const activeDimension = ref('member');
const deptList = ref<DeptVO[]>([]);
const currentMonth = () => {
const now = new Date();
return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
@ -116,12 +131,12 @@ const runningTotal = ref(0);
const queryParams = ref<TempTaskQuery>({
pageNum: 1,
pageSize: 1000,
taskStatus: '3',
finishResult: undefined,
pageSize: 999999,
taskStatus: '5',
taskType: undefined,
assigneeName: undefined,
projectName: undefined,
requestDeptName: undefined,
deptId: undefined,
params: {}
});
@ -137,49 +152,93 @@ const monthRange = computed(() => {
};
});
const filteredRows = computed(() => {
return detailRows.value.filter((row) => row.finishResult && row.actualFinishTime);
const filteredTasks = computed(() => {
return detailRows.value.filter((row) => {
if (!row.actualFinishTime) {
return false;
}
if (queryParams.value.deptId && String(row.deptId || '') !== String(queryParams.value.deptId)) {
return false;
}
return true;
});
});
const totalWorkload = computed(() => sumWorkload(filteredRows.value));
const worklogRows = computed<ReportWorklogRow[]>(() => {
return filteredTasks.value.flatMap((task) =>
(task.worklogs || []).map((worklog) => ({
...worklog,
taskId: task.tempTaskId,
taskCode: task.tempTaskCode,
projectName: task.projectName,
deptName: task.deptName
}))
);
});
const scoreRows = computed<ReportScoreRow[]>(() => {
return filteredTasks.value.flatMap((task) =>
(task.scores || []).map((score) => ({
...score,
taskId: task.tempTaskId
}))
);
});
const totalHours = computed(() => sumHours(worklogRows.value));
const metrics = computed(() => [
{ label: '闭环任务数', value: filteredRows.value.length },
{ label: '实际工时合计', value: formatNumber(totalWorkload.value) },
{ label: '单任务平均工时', value: formatNumber(filteredRows.value.length ? totalWorkload.value / filteredRows.value.length : 0) },
{ label: '闭任务数', value: filteredTasks.value.length },
{ label: '工时合计', value: formatNumber(totalHours.value) },
{ label: '评分记录数', value: scoreRows.value.length },
{ label: '未关闭任务数', value: runningTotal.value }
]);
const dimensionLabel = computed(() => {
const labelMap: Record<string, string> = {
assignee: '主执行人',
member: '人员',
project: '项目',
dept: '发起部门',
result: '完成结果',
chain: '关联链'
dept: '归集部门',
score: '评分等级'
};
return labelMap[activeDimension.value] || '维度';
});
const activeRows = computed(() => {
const fieldMap: Record<string, (row: TempTaskVO) => string> = {
assignee: (row) => row.assigneeName || '未填写执行人',
project: (row) => row.projectName || row.projectCode || '未绑定项目',
dept: (row) => row.requestDeptName || '未填写部门',
result: (row) => getFinishResultLabel(row.finishResult),
chain: (row) => row.relatedTaskCode || row.tempTaskCode || '未形成关联链'
if (activeDimension.value === 'score') {
return aggregateScores();
}
const fieldMap: Record<string, (row: ReportWorklogRow) => string> = {
member: (row) => row.userName || '未识别人员',
project: (row) => row.projectName || '未绑定项目',
dept: (row) => row.deptName || '未填写归集部门'
};
return aggregateBy(filteredRows.value, fieldMap[activeDimension.value]);
return aggregateWorklogs(fieldMap[activeDimension.value]);
});
const getFinishResultLabel = (value?: string) => {
const dictList = unref(temp_task_finish_result) || [];
const scoreLabel = (value?: string) => {
const dictList = unref(temp_task_score) || [];
const target = dictList.find((item: any) => item.value === value);
return target?.label || value || '未填写完成结果';
return target?.label || value || '未评分';
};
const sumWorkload = (rows: TempTaskVO[]) => {
return rows.reduce((sum, row) => sum + Number(row.actualWorkload || 0), 0);
const buildScoreSummary = (grades: string[]) => {
const countMap = grades.reduce<Record<string, number>>((map, grade) => {
const key = scoreLabel(grade);
map[key] = (map[key] || 0) + 1;
return map;
}, {});
return Object.entries(countMap)
.map(([grade, count]) => `${grade}:${count}`)
.join('');
};
const buildTaskScoreSummary = (row: TempTaskVO) => {
return buildScoreSummary((row.scores || []).map((score) => score.scoreGrade));
};
const sumHours = (rows: Array<{ hours?: number }>) => {
return rows.reduce((sum, row) => sum + Number(row.hours || 0), 0);
};
const formatNumber = (value: number) => {
@ -193,40 +252,113 @@ const formatDateTime = (value?: string) => {
return String(value).replace('T', ' ').slice(0, 16);
};
const aggregateBy = (rows: TempTaskVO[], keyGetter: (row: TempTaskVO) => string) => {
const result = new Map<string, AggregateRow>();
rows.forEach((row) => {
const aggregateWorklogs = (keyGetter: (row: ReportWorklogRow) => string) => {
const result = new Map<string, AggregateDraft>();
worklogRows.value.forEach((row) => {
const key = keyGetter(row);
const current =
result.get(key) ||
({
name: key,
count: 0,
workload: 0,
avgWorkload: 0,
finishedCount: 0,
terminatedCount: 0,
partialTerminatedCount: 0
} as AggregateRow);
current.count += 1;
current.workload += Number(row.actualWorkload || 0);
if (row.finishResult === '1') {
current.finishedCount += 1;
} else if (row.finishResult === '2') {
current.terminatedCount += 1;
} else if (row.finishResult === '3') {
current.partialTerminatedCount += 1;
}
current.avgWorkload = current.count ? formatNumber(current.workload / current.count) : 0;
current.workload = formatNumber(current.workload);
taskIds: new Set<string | number>(),
hours: 0,
scoreGrades: []
} as AggregateDraft);
current.taskIds.add(row.taskId);
current.hours += Number(row.hours || 0);
result.set(key, current);
});
return Array.from(result.values()).sort((a, b) => b.workload - a.workload);
appendScores(result, (score) => {
const member = memberNameById(score.memberId);
if (activeDimension.value === 'member') {
return member || '未识别人员';
}
const task = filteredTasks.value.find((item) => String(item.tempTaskId) === String(score.taskId));
if (activeDimension.value === 'project') {
return task?.projectName || '未绑定项目';
}
return task?.deptName || '未填写归集部门';
});
return toAggregateRows(result);
};
const aggregateScores = () => {
const result = new Map<string, AggregateDraft>();
scoreRows.value.forEach((score) => {
const key = scoreLabel(score.scoreGrade);
const current =
result.get(key) ||
({
name: key,
taskIds: new Set<string | number>(),
hours: 0,
scoreGrades: []
} as AggregateDraft);
current.taskIds.add(score.taskId);
current.scoreGrades.push(score.scoreGrade);
result.set(key, current);
});
return toAggregateRows(result);
};
const appendScores = (result: Map<string, AggregateDraft>, keyGetter: (score: ReportScoreRow) => string) => {
scoreRows.value.forEach((score) => {
const key = keyGetter(score);
const current =
result.get(key) ||
({
name: key,
taskIds: new Set<string | number>(),
hours: 0,
scoreGrades: []
} as AggregateDraft);
current.taskIds.add(score.taskId);
current.scoreGrades.push(score.scoreGrade);
result.set(key, current);
});
};
const memberNameById = (memberId: string | number) => {
for (const task of filteredTasks.value) {
const member = (task.members || []).find((item) => String(item.memberId) === String(memberId));
if (member?.userName) {
return member.userName;
}
}
return '';
};
const toAggregateRows = (result: Map<string, AggregateDraft>): AggregateRow[] => {
return Array.from(result.values())
.map((item) => {
const taskCount = item.taskIds.size;
return {
name: item.name,
taskCount,
hours: formatNumber(item.hours),
avgHours: taskCount ? formatNumber(item.hours / taskCount) : 0,
scoreCount: item.scoreGrades.length,
scoreSummary: buildScoreSummary(item.scoreGrades)
};
})
.sort((a, b) => b.hours - a.hours || b.scoreCount - a.scoreCount);
};
const buildQuery = () => {
queryParams.value.params = { ...monthRange.value };
return { ...queryParams.value };
return {
...queryParams.value,
deptId: undefined,
params: {
...queryParams.value.params,
includeDetail: true
}
};
};
const getDeptList = async () => {
const res = await allListDept({ status: 0 } as any);
deptList.value = res.data || [];
};
const getList = async () => {
@ -234,8 +366,10 @@ const getList = async () => {
try {
const res: any = await listTempTask(buildQuery());
detailRows.value = res.rows || [];
const runningRes: any = await listTempTask({ pageNum: 1, pageSize: 1, taskStatus: '2' });
runningTotal.value = runningRes.total || 0;
const runningResList = await Promise.all(
['2', '3', '4'].map((status) => listTempTask({ pageNum: 1, pageSize: 1, taskStatus: status } as TempTaskQuery))
);
runningTotal.value = runningResList.reduce((sum: number, item: any) => sum + Number(item.total || 0), 0);
} finally {
loading.value = false;
}
@ -248,10 +382,10 @@ const handleQuery = () => {
const resetQuery = () => {
finishMonth.value = currentMonth();
queryParams.value.taskType = undefined;
queryParams.value.assigneeName = undefined;
queryParams.value.projectName = undefined;
queryParams.value.requestDeptName = undefined;
queryParams.value.finishResult = undefined;
queryParams.value.deptId = undefined;
handleQuery();
};
@ -259,8 +393,9 @@ const handleExport = () => {
proxy?.download('oa/erp/tempTask/export', buildQuery(), `tempTask_report_${new Date().getTime()}.xlsx`);
};
onMounted(() => {
getList();
onMounted(async () => {
await getDeptList();
await getList();
});
</script>

Loading…
Cancel
Save