You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

959 lines
35 KiB
Vue

<template>
<div class="p-2" v-loading="pageLoading">
<approvalButton
class="mb-3"
@submitForm="submitForm"
@approvalVerifyOpen="approvalVerifyOpen"
@handleApprovalRecord="handleApprovalRecord"
:buttonLoading="buttonLoading"
:id="form.tempTaskId as any"
:status="form.flowStatus as any"
:pageType="pageType"
:mode="false"
>
<el-button v-if="canSubmitFinish" type="success" icon="CircleCheck" @click="handleSubmitFinish" v-hasPermi="['oa:erp:tempTask:submitFinish']">
提交完成
</el-button>
<el-button v-if="canScoreClose" type="warning" icon="Star" @click="openScoreDialog" v-hasPermi="['oa:erp:tempTask:score']">
评分关闭
</el-button>
</approvalButton>
<el-card shadow="never" class="mb-3">
<el-form ref="tempTaskFormRef" :model="form" :rules="rules" label-width="120px" :disabled="isFormReadOnly">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="任务编号" prop="tempTaskCode">
<el-input v-model="form.tempTaskCode" placeholder="后端自动生成" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="业务状态" prop="taskStatus">
<el-select v-model="form.taskStatus" disabled>
<el-option v-for="dict in temp_task_status" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="累计工时" prop="totalHours">
<el-input-number v-model="form.totalHours" :min="0" :precision="2" disabled controls-position="right" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="任务类型" prop="taskType">
<el-select v-model="form.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-col>
<el-col :span="16">
<el-form-item label="任务标题" prop="taskTitle">
<el-input v-model="form.taskTitle" placeholder="请输入任务标题" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="任务描述" prop="taskDesc">
<el-input v-model="form.taskDesc" type="textarea" :rows="4" placeholder="请输入临时任务描述" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="计划开始" prop="planStartTime">
<el-date-picker v-model="form.planStartTime" type="date" value-format="YYYY-MM-DD" clearable placeholder="请选择计划开始" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="计划完成" prop="planEndTime">
<el-date-picker v-model="form.planEndTime" type="date" value-format="YYYY-MM-DD" clearable placeholder="请选择计划完成" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预计工时" prop="estimateWorkload">
<el-input-number v-model="form.estimateWorkload" :min="0" :step="0.5" :precision="1" controls-position="right" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.taskType === '3'">
<el-form-item label="主报工项目" prop="projectCode">
<el-input v-model="form.projectCode" placeholder="请选择项目" readonly>
<template #suffix>
<el-icon class="cursor-pointer" @click="openProjectSelect"><Search /></el-icon>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.taskType === '3'">
<el-form-item label="项目名称" prop="projectName">
<el-input v-model="form.projectName" disabled placeholder="选择项目后自动填充" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.taskType === '1'">
<el-form-item label="归集部门" prop="deptId">
<el-select v-model="form.deptId" placeholder="请选择归集部门" clearable filterable @change="handleTaskDeptChange">
<el-option v-for="dept in deptList" :key="dept.deptId" :label="dept.deptName" :value="dept.deptId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.taskType === '1'">
<el-form-item label="归集部门名称" prop="deptName">
<el-input v-model="form.deptName" disabled placeholder="选择部门后自动填充" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="发起人" prop="requesterName">
<el-input v-model="form.requesterName" disabled placeholder="后端按当前用户回填" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="实际需求人" prop="realRequesterName">
<el-input v-model="form.realRequesterName" readonly placeholder="默认可为空,代发起时选择">
<template #suffix>
<el-icon class="cursor-pointer" @click="openUserSelect('realRequester')"><Search /></el-icon>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="实际需求部门" prop="realRequestDeptId">
<el-select v-model="form.realRequestDeptId" placeholder="请选择实际需求部门" clearable filterable @change="handleRealDeptChange">
<el-option v-for="dept in deptList" :key="dept.deptId" :label="dept.deptName" :value="dept.deptId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="软件部领导" prop="softwareLeaderName">
<el-input v-model="form.softwareLeaderName" readonly placeholder="请选择软件部领导">
<template #suffix>
<el-icon class="cursor-pointer" @click="openUserSelect('leader')"><Search /></el-icon>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="主执行人" prop="assigneeName">
<el-input v-model="form.assigneeName" readonly placeholder="请选择主执行人">
<template #suffix>
<el-icon class="cursor-pointer" @click="openUserSelect('assignee')"><Search /></el-icon>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="实际开始" prop="actualStartTime">
<el-date-picker v-model="form.actualStartTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" disabled placeholder="流程自动记录" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-row v-if="form.tempTaskId" :gutter="12">
<el-col :span="8">
<el-card shadow="never" class="mb-3">
<template #header>
<div class="flex justify-between items-center">
<span>参与人</span>
<el-button
v-if="canManageMembers"
type="primary"
plain
icon="Plus"
size="small"
@click="openMemberDialog"
v-hasPermi="['oa:erp:tempTask:worklog']"
>
协作人
</el-button>
</div>
</template>
<el-table :data="memberList" border>
<el-table-column label="类型" prop="memberType" width="100" align="center">
<template #default="scope">
<dict-tag :options="temp_task_member_type" :value="scope.row.memberType" />
</template>
</el-table-column>
<el-table-column label="姓名" prop="userName" min-width="100" align="center" />
<el-table-column label="协作说明" prop="joinRemark" min-width="150" show-overflow-tooltip align="center" />
<el-table-column v-if="canManageMembers" label="操作" width="80" align="center">
<template #default="scope">
<el-button v-if="scope.row.memberType === '2'" link type="danger" @click="handleRemoveMember(scope.row.memberId)">移除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
<el-col :span="16">
<el-card shadow="never" class="mb-3">
<template #header>
<div class="flex justify-between items-center">
<span>工时明细</span>
<el-button
v-if="canEditWorklog"
type="primary"
plain
icon="Plus"
size="small"
@click="openWorklogDialog()"
v-hasPermi="['oa:erp:tempTask:worklog']"
>
填报工时
</el-button>
</div>
</template>
<el-table :data="worklogList" border>
<el-table-column label="填报人" prop="userName" width="100" align="center" />
<el-table-column label="工作日期" prop="workDate" width="120" align="center">
<template #default="scope">{{ parseDate(scope.row.workDate) }}</template>
</el-table-column>
<el-table-column label="自然周" min-width="190" align="center">
<template #default="scope">{{ parseDate(scope.row.weekStart) }} ~ {{ parseDate(scope.row.weekEnd) }}</template>
</el-table-column>
<el-table-column label="工时" prop="hours" width="80" align="center" />
<el-table-column label="事项描述" prop="workContent" min-width="180" show-overflow-tooltip align="center" />
<el-table-column label="附件" min-width="160" align="center">
<template #default="scope">
<OssFilePreview v-if="scope.row.ossId" :oss-ids="scope.row.ossId" thumb-size="40px" />
<span v-else>暂无附件</span>
</template>
</el-table-column>
<el-table-column label="状态" prop="lockFlag" width="90" align="center">
<template #default="scope">
<el-tag :type="scope.row.lockFlag === '1' ? 'info' : 'success'">{{ scope.row.lockFlag === '1' ? '已锁定' : '可编辑' }}</el-tag>
</template>
</el-table-column>
<el-table-column v-if="canEditWorklog" label="操作" width="110" align="center">
<template #default="scope">
<el-button v-if="scope.row.lockFlag !== '1'" link type="primary" @click="openWorklogDialog(scope.row)">编辑</el-button>
<el-button v-if="scope.row.lockFlag !== '1'" link type="danger" @click="handleDeleteWorklog(scope.row.worklogId)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
</el-row>
<el-card v-if="form.tempTaskId" shadow="never">
<template #header>
<div class="flex justify-between items-center">
<span>评分结果</span>
<el-button
v-if="canScoreClose"
type="warning"
plain
icon="Star"
size="small"
@click="openScoreDialog"
v-hasPermi="['oa:erp:tempTask:score']"
>
评分关闭
</el-button>
</div>
</template>
<el-table :data="scoreList" border>
<el-table-column label="被评分人" prop="userName" width="120" align="center" />
<el-table-column label="评分等级" prop="scoreGrade" width="140" align="center">
<template #default="scope">
<dict-tag :options="temp_task_score" :value="scope.row.scoreGrade" />
</template>
</el-table-column>
<el-table-column label="评分说明" prop="scoreRemark" min-width="220" show-overflow-tooltip align="center" />
<el-table-column label="评分时间" prop="scoreTime" width="160" align="center">
<template #default="scope">{{ parseDateTime(scope.row.scoreTime) }}</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog v-model="memberDialog.visible" title="新增协作人" width="620px" append-to-body>
<el-form ref="memberFormRef" :model="memberForm" :rules="memberRules" label-width="120px">
<el-form-item label="协作人" prop="userName">
<el-input v-model="memberForm.userName" readonly placeholder="请选择协作人">
<template #suffix>
<el-icon class="cursor-pointer" @click="openUserSelect('member')"><Search /></el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item label="协作说明" prop="joinRemark">
<el-input v-model="memberForm.joinRemark" type="textarea" :rows="3" placeholder="请输入协作事项说明" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="memberDialog.visible = false">取消</el-button>
<el-button type="primary" :loading="buttonLoading" @click="handleAddMember">确定</el-button>
</template>
</el-dialog>
<el-dialog v-model="worklogDialog.visible" title="工时明细" width="720px" append-to-body>
<el-form ref="worklogFormRef" :model="worklogForm" :rules="worklogRules" label-width="120px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="工作日期" prop="workDate">
<el-date-picker v-model="worklogForm.workDate" type="date" value-format="YYYY-MM-DD" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工时" prop="hours">
<el-input-number v-model="worklogForm.hours" :min="0.5" :step="0.5" :precision="1" controls-position="right" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="事项描述" prop="workContent">
<el-input v-model="worklogForm.workContent" type="textarea" :rows="4" placeholder="请输入本次工作内容" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="附件" prop="ossId">
<FileUpload
v-model="worklogOssIdString"
:limit="5"
:file-size="20"
:file-type="['png', 'jpg', 'jpeg', 'doc', 'docx', 'pdf', 'xls', 'xlsx', 'txt']"
:is-show-tip="true"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<el-button @click="worklogDialog.visible = false">取消</el-button>
<el-button type="primary" :loading="buttonLoading" @click="handleSaveWorklog">保存</el-button>
</template>
</el-dialog>
<el-dialog v-model="scoreDialog.visible" title="领导评分关闭" width="820px" append-to-body>
<el-form ref="scoreFormRef" :model="scoreForm" label-width="120px">
<el-table :data="scoreForm.scoreList" border>
<el-table-column label="人员" min-width="140" align="center">
<template #default="scope">
{{ memberNameMap[scope.row.memberId] || scope.row.userId }}
</template>
</el-table-column>
<el-table-column label="评分等级" width="180" align="center">
<template #default="scope">
<el-select v-model="scope.row.scoreGrade" placeholder="请选择评分">
<el-option v-for="dict in temp_task_score" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</template>
</el-table-column>
<el-table-column label="评分说明" min-width="240" align="center">
<template #default="scope">
<el-input v-model="scope.row.scoreRemark" placeholder="请输入评分说明" />
</template>
</el-table-column>
</el-table>
<el-form-item class="mt-3" label="最终审核意见">
<el-input v-model="scoreForm.leaderFinalOpinion" type="textarea" :rows="3" placeholder="请输入最终审核意见" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="scoreDialog.visible = false">取消</el-button>
<el-button type="primary" :loading="buttonLoading" @click="handleScoreAndClose">评分关闭</el-button>
</template>
</el-dialog>
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
<approvalRecord ref="approvalRecordRef" />
<ProjectSelect ref="projectSelectRef" :multiple="false" @confirm-call-back="handleProjectSelect" />
<UserSelect ref="userSelectRef" :multiple="userSelectMode === 'cc'" @confirm-call-back="handleUserSelect" />
</div>
</template>
<script setup name="TempTaskEdit" lang="ts">
import {
addTempTask,
addTempTaskMember,
assigneeReviewTempTask,
delTempTaskMember,
delTempTaskWorklog,
getTempTask,
leaderReviewAndCompleteTempTask,
listTempTaskMember,
listTempTaskScore,
listTempTaskWorklog,
saveTempTaskWorklog,
scoreAndCloseTempTask,
submitFinishTempTask,
tempTaskSubmitAndFlowStart,
updateTempTask
} from '@/api/oa/erp/tempTask';
import type {
TempTaskForm,
TempTaskMemberForm,
TempTaskMemberVO,
TempTaskScoreSubmitForm,
TempTaskScoreVO,
TempTaskWorklogForm,
TempTaskWorklogVO
} from '@/api/oa/erp/tempTask/types';
import type { ProjectInfoVO } from '@/api/oa/erp/projectInfo/types';
import type { DeptVO } from '@/api/system/dept/types';
import { allListDept } from '@/api/system/dept';
import { getTask } from '@/api/workflow/task';
import { FlowCodeEnum } from '@/enums/OAEnum';
import ApprovalButton from '@/components/Process/approvalButton.vue';
import SubmitVerify from '@/components/Process/submitVerify.vue';
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
import ProjectSelect from '@/components/ProjectSelect/index.vue';
import UserSelect from '@/components/UserSelect/index.vue';
import FileUpload from '@/components/FileUpload/index.vue';
import OssFilePreview from '@/components/OssFilePreview/index.vue';
type UserSelectMode = 'leader' | 'assignee' | 'realRequester' | 'member' | 'cc';
const { proxy } = getCurrentInstance() as any;
const route = useRoute();
const router = useRouter();
const { temp_task_type, temp_task_status, temp_task_member_type, temp_task_score } = toRefs<any>(
proxy?.useDict('temp_task_type', 'temp_task_status', 'temp_task_member_type', 'temp_task_score')
);
const pageLoading = ref(false);
const buttonLoading = ref(false);
const pageType = ref<string>((route.query.type as string) || 'add');
const tempTaskFormRef = ref<ElFormInstance>();
const memberFormRef = ref<ElFormInstance>();
const worklogFormRef = ref<ElFormInstance>();
const scoreFormRef = ref<ElFormInstance>();
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
const projectSelectRef = ref<InstanceType<typeof ProjectSelect>>();
const userSelectRef = ref<InstanceType<typeof UserSelect>>();
const userSelectMode = ref<UserSelectMode>('leader');
const taskVariables = ref<Record<string, unknown>>({});
const currentNodeCode = ref<string>('');
const deptList = ref<DeptVO[]>([]);
const memberList = ref<TempTaskMemberVO[]>([]);
const worklogList = ref<TempTaskWorklogVO[]>([]);
const scoreList = ref<TempTaskScoreVO[]>([]);
const initFormData: TempTaskForm = {
tempTaskId: undefined,
taskId: undefined,
tempTaskCode: undefined,
taskTitle: undefined,
taskDesc: undefined,
taskType: '1',
planStartTime: undefined,
planEndTime: undefined,
actualStartTime: undefined,
actualFinishTime: undefined,
projectId: undefined,
projectCode: undefined,
projectName: undefined,
deptId: undefined,
deptName: undefined,
requesterId: undefined,
requesterName: undefined,
realRequesterId: undefined,
realRequesterName: undefined,
realRequestDeptId: undefined,
realRequestDeptName: undefined,
softwareLeaderId: undefined,
softwareLeaderName: undefined,
assigneeId: undefined,
assigneeName: undefined,
estimateWorkload: undefined,
totalHours: undefined,
taskStatus: '1',
flowStatus: 'draft',
ccUserIds: undefined,
remark: undefined,
flowCode: FlowCodeEnum.TEMP_TASK_CODE,
variables: {},
bizExt: {}
};
const form = ref<TempTaskForm>({ ...initFormData });
const rules: ElFormRules = {
taskDesc: [{ required: true, message: '任务描述不能为空', trigger: 'blur' }],
taskType: [{ required: true, message: '任务类型不能为空', trigger: 'change' }],
softwareLeaderName: [{ required: true, message: '软件部领导不能为空', trigger: 'change' }],
projectCode: [
{
validator: (_rule, value, callback) => {
if (form.value.taskType === '3' && !value) {
callback(new Error('项目任务必须选择项目'));
} else {
callback();
}
},
trigger: 'change'
}
],
deptId: [
{
validator: (_rule, value, callback) => {
if (form.value.taskType === '1' && !value) {
callback(new Error('部门任务必须选择归集部门'));
} else {
callback();
}
},
trigger: 'change'
}
]
};
const memberDialog = reactive({ visible: false });
const memberForm = ref<TempTaskMemberForm>({});
const memberRules: ElFormRules = {
userName: [{ required: true, message: '协作人不能为空', trigger: 'change' }]
};
const worklogDialog = reactive({ visible: false });
const worklogForm = ref<TempTaskWorklogForm>({});
const worklogRules: ElFormRules = {
workDate: [{ required: true, message: '工作日期不能为空', trigger: 'change' }],
hours: [{ required: true, message: '工时不能为空', trigger: 'blur' }],
workContent: [{ required: true, message: '事项描述不能为空', trigger: 'blur' }]
};
const scoreDialog = reactive({ visible: false });
const scoreForm = ref<TempTaskScoreSubmitForm>({
tempTaskId: '',
taskId: '',
leaderFinalOpinion: undefined,
scoreList: []
});
const isFormReadOnly = computed(
() => pageType.value === 'view' || (pageType.value === 'approval' && !['leader_review', 'assignee_review'].includes(currentNodeCode.value))
);
const canManageMembers = computed(() => !!form.value.tempTaskId && pageType.value !== 'view' && form.value.taskStatus === '3');
const canEditWorklog = computed(() => !!form.value.tempTaskId && pageType.value !== 'view' && form.value.taskStatus === '3');
const canSubmitFinish = computed(
() =>
!!form.value.tempTaskId &&
!!route.query.taskId &&
pageType.value !== 'view' &&
form.value.taskStatus === '3' &&
currentNodeCode.value === 'execute'
);
const canScoreClose = computed(
() =>
!!form.value.tempTaskId &&
!!route.query.taskId &&
pageType.value !== 'view' &&
form.value.taskStatus === '4' &&
currentNodeCode.value === 'leader_final'
);
const memberNameMap = computed<Record<string, string>>(() => {
const map: Record<string, string> = {};
memberList.value.forEach((member) => {
map[String(member.memberId)] = member.userName || '';
});
return map;
});
const worklogOssIdString = computed({
get() {
return worklogForm.value.ossId ? String(worklogForm.value.ossId) : '';
},
set(val: string) {
worklogForm.value.ossId = val || undefined;
}
});
const parseDate = (value?: string) => {
return value ? String(value).slice(0, 10) : '';
};
const parseDateTime = (value?: string) => {
return value ? String(value).replace('T', ' ').slice(0, 16) : '';
};
const getDeptList = async () => {
const res = await allListDept({ status: 0 } as any);
deptList.value = res.data || [];
};
const findDept = (deptId?: string | number) => {
return deptList.value.find((dept) => dept.deptId === deptId);
};
const handleTaskDeptChange = (deptId?: string | number) => {
form.value.deptName = findDept(deptId)?.deptName;
};
const handleRealDeptChange = (deptId?: string | number) => {
form.value.realRequestDeptName = findDept(deptId)?.deptName;
};
watch(
() => form.value.taskType,
(taskType) => {
if (taskType !== '3') {
form.value.projectId = undefined;
form.value.projectCode = undefined;
form.value.projectName = undefined;
}
if (taskType !== '1') {
form.value.deptId = undefined;
form.value.deptName = undefined;
}
}
);
const openProjectSelect = () => {
if (isFormReadOnly.value) {
return;
}
projectSelectRef.value?.open();
};
const handleProjectSelect = (data: ProjectInfoVO[]) => {
const project = data?.[0];
if (!project) {
return;
}
form.value.projectId = project.projectId;
form.value.projectCode = project.projectCode;
form.value.projectName = project.projectName;
};
const openUserSelect = (mode: UserSelectMode) => {
if (isFormReadOnly.value && mode !== 'member') {
return;
}
userSelectMode.value = mode;
userSelectRef.value?.open();
};
const handleUserSelect = (users: Array<Record<string, any>>) => {
const selected = users?.[0];
if (!selected) {
return;
}
const userId = selected.userId;
const name = selected.nickName || selected.userName;
if (userSelectMode.value === 'leader') {
form.value.softwareLeaderId = userId;
form.value.softwareLeaderName = name;
} else if (userSelectMode.value === 'assignee') {
form.value.assigneeId = userId;
form.value.assigneeName = name;
} else if (userSelectMode.value === 'realRequester') {
form.value.realRequesterId = userId;
form.value.realRequesterName = name;
if (selected.deptId) {
form.value.realRequestDeptId = selected.deptId;
form.value.realRequestDeptName = selected.deptName;
}
} else if (userSelectMode.value === 'member') {
memberForm.value.userId = userId;
memberForm.value.userName = name;
memberForm.value.memberDeptId = selected.deptId;
} else {
form.value.ccUserIds = users.map((item) => item.userId).join(',');
}
};
const loadSubLists = async () => {
if (!form.value.tempTaskId) {
memberList.value = [];
worklogList.value = [];
scoreList.value = [];
return;
}
const tempTaskId = form.value.tempTaskId;
const [memberRes, worklogRes, scoreRes] = await Promise.all([
listTempTaskMember(tempTaskId),
listTempTaskWorklog(tempTaskId),
listTempTaskScore(tempTaskId)
]);
memberList.value = memberRes.data || [];
worklogList.value = worklogRes.data || [];
scoreList.value = scoreRes.data || [];
};
const loadDetail = async (id: string | number) => {
const res = await getTempTask(id);
form.value = {
...initFormData,
...res.data,
flowCode: FlowCodeEnum.TEMP_TASK_CODE
};
memberList.value = res.data?.members || [];
worklogList.value = res.data?.worklogs || [];
scoreList.value = res.data?.scores || [];
await loadSubLists();
};
const loadCurrentWorkflowTask = async () => {
const taskId = route.query.taskId as string | undefined;
if (!taskId) {
currentNodeCode.value = '';
return;
}
const res = await getTask(taskId);
currentNodeCode.value = res.data?.nodeCode || '';
};
const buildVariables = () => {
taskVariables.value = {
has_assignee: form.value.assigneeId ? '1' : '0',
reassigned: (form.value.variables as Record<string, unknown>)?.reassigned || '0',
requesterId: form.value.requesterId,
realRequesterId: form.value.realRequesterId,
realRequestDeptId: form.value.realRequestDeptId,
softwareLeaderId: form.value.softwareLeaderId,
assigneeId: form.value.assigneeId,
ccUserIds: form.value.ccUserIds,
taskTitle: form.value.taskTitle,
taskDesc: form.value.taskDesc,
taskType: form.value.taskType,
projectId: form.value.projectId,
deptId: form.value.deptId,
planStartTime: form.value.planStartTime,
planEndTime: form.value.planEndTime,
estimateWorkload: form.value.estimateWorkload,
actualStartTime: form.value.actualStartTime,
assigneeOpinion: form.value.assigneeOpinion,
leaderOpinion: form.value.leaderOpinion,
leaderFinalOpinion: scoreForm.value.leaderFinalOpinion
};
Object.keys(taskVariables.value).forEach((key) => {
if (taskVariables.value[key] === undefined || taskVariables.value[key] === null || taskVariables.value[key] === '') {
delete taskVariables.value[key];
}
});
form.value.variables = { ...taskVariables.value };
const businessTitle = `${form.value.tempTaskCode || '临时任务'}-${form.value.taskDesc || form.value.taskTitle || ''}`;
form.value.bizExt = {
businessId: form.value.tempTaskId,
businessCode: form.value.tempTaskCode,
businessTitle: businessTitle.slice(0, 80)
};
};
const validateMainForm = async () => {
if (!tempTaskFormRef.value) {
return true;
}
return await tempTaskFormRef.value.validate().catch(() => false);
};
const submitForm = async (status: string) => {
const valid = await validateMainForm();
if (!valid) {
return;
}
buttonLoading.value = true;
try {
buildVariables();
if (status !== 'draft') {
const res = await tempTaskSubmitAndFlowStart(form.value);
form.value = { ...initFormData, ...res.data, flowCode: FlowCodeEnum.TEMP_TASK_CODE };
proxy?.$modal.msgSuccess('操作成功');
} else {
form.value.taskStatus = '1';
form.value.flowStatus = 'draft';
if (form.value.tempTaskId) {
await updateTempTask(form.value);
} else {
await addTempTask(form.value);
}
proxy?.$modal.msgSuccess('暂存成功');
}
proxy?.$tab.closePage(route);
router.go(-1);
} finally {
buttonLoading.value = false;
}
};
const openMemberDialog = () => {
memberForm.value = {
tempTaskId: form.value.tempTaskId,
memberType: '2'
};
memberDialog.visible = true;
};
const handleAddMember = async () => {
const valid = await memberFormRef.value?.validate().catch(() => false);
if (!valid) {
return;
}
buttonLoading.value = true;
try {
await addTempTaskMember(memberForm.value);
proxy?.$modal.msgSuccess('协作人已添加');
memberDialog.visible = false;
await loadSubLists();
} finally {
buttonLoading.value = false;
}
};
const handleRemoveMember = async (memberId: string | number) => {
await proxy?.$modal.confirm('确认移除该协作人?');
await delTempTaskMember(memberId);
proxy?.$modal.msgSuccess('移除成功');
await loadSubLists();
};
const openWorklogDialog = (row?: TempTaskWorklogVO) => {
worklogForm.value = row
? { ...row }
: {
tempTaskId: form.value.tempTaskId,
workDate: undefined,
hours: 0.5,
workContent: undefined,
ossId: undefined
};
worklogDialog.visible = true;
};
const handleSaveWorklog = async () => {
const valid = await worklogFormRef.value?.validate().catch(() => false);
if (!valid) {
return;
}
buttonLoading.value = true;
try {
await saveTempTaskWorklog(worklogForm.value);
proxy?.$modal.msgSuccess('工时明细已保存');
worklogDialog.visible = false;
await loadSubLists();
} finally {
buttonLoading.value = false;
}
};
const handleDeleteWorklog = async (worklogId: string | number) => {
await proxy?.$modal.confirm('确认删除该工时明细?');
await delTempTaskWorklog(worklogId);
proxy?.$modal.msgSuccess('删除成功');
await loadSubLists();
};
const handleSubmitFinish = async () => {
const taskId = route.query.taskId as string | undefined;
if (!form.value.tempTaskId || !taskId) {
proxy?.$modal.msgWarning('请从执行待办进入后提交完成');
return;
}
if (!currentNodeCode.value) {
await loadCurrentWorkflowTask();
}
if (currentNodeCode.value !== 'execute') {
proxy?.$modal.msgWarning('当前流程节点不是执行节点,不能提交完成');
return;
}
await proxy?.$modal.confirm('确认提交完成并锁定全部工时明细?');
buttonLoading.value = true;
try {
await submitFinishTempTask({
tempTaskId: form.value.tempTaskId,
taskId
});
proxy?.$modal.msgSuccess('提交完成成功');
proxy?.$tab.closePage(route);
router.go(-1);
} finally {
buttonLoading.value = false;
}
};
const openScoreDialog = () => {
const taskId = route.query.taskId as string | undefined;
if (!form.value.tempTaskId || !taskId) {
return;
}
scoreForm.value = {
tempTaskId: form.value.tempTaskId,
taskId,
leaderFinalOpinion: undefined,
scoreList: memberList.value.map((member) => {
const oldScore = scoreList.value.find((score) => String(score.memberId) === String(member.memberId));
return {
memberId: member.memberId,
userId: member.userId,
scoreGrade: oldScore?.scoreGrade || '',
scoreRemark: oldScore?.scoreRemark
};
})
};
scoreDialog.visible = true;
};
const handleScoreAndClose = async () => {
if (scoreForm.value.scoreList.some((item) => !item.scoreGrade)) {
proxy?.$modal.msgWarning('请为全部参与人选择评分等级');
return;
}
buttonLoading.value = true;
try {
await scoreAndCloseTempTask(scoreForm.value);
proxy?.$modal.msgSuccess('评分关闭成功');
scoreDialog.visible = false;
proxy?.$tab.closePage(route);
router.go(-1);
} finally {
buttonLoading.value = false;
}
};
const approvalVerifyOpen = async () => {
const taskId = route.query.taskId as string;
if (!taskId) {
return;
}
if (!currentNodeCode.value) {
await loadCurrentWorkflowTask();
}
if (currentNodeCode.value === 'leader_review') {
const valid = await validateMainForm();
if (!valid) {
return;
}
await leaderReviewAndCompleteTempTask({ ...form.value, taskId });
proxy?.$modal.msgSuccess('领导审批成功');
await proxy?.$tab.closePage(route);
router.go(-1);
return;
} else if (currentNodeCode.value === 'assignee_review') {
await assigneeReviewTempTask(form.value);
buildVariables();
} else {
buildVariables();
}
await submitVerifyRef.value?.openDialog(taskId);
};
const handleApprovalRecord = () => {
if (form.value.tempTaskId) {
approvalRecordRef.value?.init(form.value.tempTaskId);
}
};
const submitCallback = async () => {
await proxy?.$tab.closePage(route);
router.go(-1);
};
onMounted(async () => {
pageLoading.value = true;
try {
pageType.value = (route.query.type as string) || 'add';
await getDeptList();
await loadCurrentWorkflowTask();
const id = route.query.id as string | number | undefined;
if (id) {
await loadDetail(id);
}
} finally {
pageLoading.value = false;
}
});
</script>