Files
SPDM/src/views/task/projectDetail/index.vue
2026-04-17 14:08:58 +08:00

515 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="gl-page-content-full">
<!-- 顶部选择器区域 -->
<div class="top-selector">
<div class="select-content">
<el-form :inline="true" class="demo-form-inline">
<div class="project-name">
{{ currentProjectInfo.nodeName }}
{{ currentProjectInfo.nodeCode ? '' + currentProjectInfo.nodeCode + '' : '' }}
</div>
</el-form>
<!-- <el-select v-model="nodeLevel2Uuid" placeholder="节点" style="margin-right: 10px">
<el-option label="T01" value="T01"></el-option>
</el-select> -->
</div>
<div class="top-icons">
<el-button link @click="goProjectListFun">返回列表</el-button>
<el-button
v-if="isMember"
:disabled="currentProjectInfo.exeStatus === PROJECT_EXE_STATUS_CODE.CLOSED"
icon="setting"
@click="openEditBasicDialogFun"
>
项目设置
</el-button>
<el-button
v-if="isMember"
:disabled="currentProjectInfo.exeStatus === PROJECT_EXE_STATUS_CODE.CLOSED"
icon="operation"
@click="openEditNodeDialogFun"
>
阶段设置
</el-button>
<el-button
v-if="isMember"
:disabled="currentProjectInfo.exeStatus === PROJECT_EXE_STATUS_CODE.CLOSED"
icon="calendar"
@click="openAddTaskDialogFun"
>
仿真策划
</el-button>
<el-popconfirm
v-if="currentProjectInfo.exeStatus === PROJECT_EXE_STATUS_CODE.COMPLETED"
title="项目关闭后,项目中的数据就无法再变更,确认是否关闭?"
@confirm="closeProject"
>
<template #reference>
<el-button icon="Lock">关闭</el-button>
</template>
</el-popconfirm>
</div>
</div>
<!-- 标签页区域 -->
<el-tabs v-model="activeTab" type="card" class="tab-card" @tab-change="tabChangeFun">
<el-tab-pane label="任务列表" name="taskList">
<loadcase
ref="loadcaseRef"
v-if="displayedTabs.includes('taskList') && projectUuid && isLoadProjectInfo"
:projectUuid="projectUuid"
:projectCode="currentProjectInfo.nodeCode"
:canPushReport="isMember"
:projectInfo="currentProjectInfo"
@getPhaseList="getPhaseListFun"
:currentPhase="currentProjectInfo.currentPhase"
/>
</el-tab-pane>
<!-- <el-tab-pane label="团队成员" name="teamMembers">
<teamMember
v-if="displayedTabs.includes('teamMembers') && projectUuid"
:nodeLevel1Uuid="projectUuid"
/>
</el-tab-pane> -->
<el-tab-pane :label="$t('项目详情页.项目详情')" name="projectDetail">
<div class="project-detail-content">
<div class="section-block">
<div class="section-title">{{ $t('项目详情页.基本信息') }}</div>
<baseInfo
ref="basePageRef"
@update:projectInfo="updateProjectInfo"
@loaded="projectInfoLoadCompleteFun"
:nodeId="projectUuid"
/>
</div>
<div class="section-block">
<div class="section-title">{{ $t('项目详情页.团队成员') }}</div>
<teamMember v-if="projectUuid" :nodeLevel1Uuid="projectUuid" />
</div>
<template v-if="enableConfigByTenant([TENANT_ENUM.LYRIC])">
<!-- <div class="section-block">
<div class="section-title">{{ $t('项目详情页.参与人员') }}</div>
<teamMember
v-if="projectUuid"
type="temporary-add"
:isMember="isMember"
:nodeLevel1Uuid="projectUuid"
/>
</div> -->
<div class="section-block">
<div class="section-title">{{ $t('项目详情页.方案维护') }}</div>
<SchemeMaintain ref="schemeMaintainRef" :nodeId="projectUuid" />
</div>
<div class="section-block">
<div class="section-title">{{ $t('项目详情页.批次信息') }}</div>
<BatchInfo ref="batchInfoRef" :nodeId="projectUuid" />
</div>
<div class="section-block">
<div class="section-title">{{ $t('项目详情页.产线信息') }}</div>
<productionLine ref="productionLineRef" :nodeCode="currentProjectInfo.nodeCode" />
</div>
<div class="section-block">
<div class="section-title">{{ $t('项目详情页.项目参与人员') }}</div>
<PDT ref="pdtRef" :nodeId="projectUuid" />
</div>
</template>
</div>
</el-tab-pane>
<el-tab-pane label="统计分析" name="statisticAnalysis">
<StatisticAnalysis
v-if="displayedTabs.includes('statisticAnalysis') && currentProjectInfo.uuid"
:projectUuid="currentProjectInfo.uuid"
></StatisticAnalysis>
</el-tab-pane>
<el-tab-pane label="项目文件" name="projectFiles">
<projectFile
v-if="displayedTabs.includes('projectFiles') && currentProjectInfo.id"
:projectId="currentProjectInfo.id"
:projectUuid="currentProjectInfo.uuid"
:projectName="currentProjectInfo.nodeName"
:freeze="currentProjectInfo.exeStatus === PROJECT_EXE_STATUS_CODE.CLOSED"
/>
</el-tab-pane>
<el-tab-pane
v-if="enableConfigByTenant([TENANT_ENUM.LYRIC])"
:label="$t('项目详情页.工位时间维护')"
name="workspaceTime"
>
<WorkspaceTime
v-if="displayedTabs.includes('workspaceTime') && projectUuid"
:projectUuid="projectUuid"
:readonly="!isMember"
:currentPhaseName="currentProjectInfo.currentPhase"
/>
</el-tab-pane>
<el-tab-pane label="文件数据" name="projectData">
<DataOverView
v-if="displayedTabs.includes('projectData') && projectUuid"
:defaultProjectId="projectUuid"
hideAddBtn
hideTree
/>
</el-tab-pane>
<el-tab-pane
label="策划记录"
name="planningRecord"
v-if="!enableConfigByTenant([TENANT_ENUM.LYRIC])"
>
<planningRecord
v-if="displayedTabs.includes('planningRecord') && projectUuid"
:project-info="currentProjectInfo"
></planningRecord>
</el-tab-pane>
<el-tab-pane
label="任务指标"
name="proformance"
v-if="enableConfigByTenant([TENANT_ENUM.BASE])"
>
<projectTaskPerformanceList
v-if="displayedTabs.includes('proformance') && projectUuid"
:projectUuid="projectUuid"
></projectTaskPerformanceList>
</el-tab-pane>
</el-tabs>
</div>
<projectInfoDialog
:projectId="currentProjectInfo.uuid"
ref="basePageFormRef"
v-if="showProjectInfoDialog"
v-model="showProjectInfoDialog"
:nodeLevel1List="nodeLevel1List"
@update:currentProjectBaseInfo="updateCurrentProjectBaseInfo"
@completeFun="completeFun"
/>
<nodeInfoDialog
ref="nodePageRef"
v-if="showNodeInfoDialog"
:nodeLevel1Uuid="projectUuid"
:projectBeginTime="currentProjectInfo.beginTime"
:projectEndTime="currentProjectInfo.endTime"
:projectInfo="currentProjectInfo"
v-model:showNodeInfoDialog="showNodeInfoDialog"
dialogType="edit"
@completeFun="completeFun"
/>
<TaskDialog
v-if="showTaskDialog && isLoadProjectInfo"
v-model:showTaskDialog="showTaskDialog"
dialogType="edit"
:nodeLevel1Name="currentProjectInfo.nodeName"
:nodeLevel1Info="currentProjectInfo"
:nodeLevel1Uuid="projectUuid"
:projectBeginTime="currentProjectInfo.beginTime"
:projectEndTime="currentProjectInfo.endTime"
@taskComplete="completeFun"
:currentPhase="currentProjectInfo.currentPhase"
/>
</template>
<script lang="ts" setup>
import { reactive, ref, watch } from 'vue';
import projectFile from './components/projectFile.vue';
import teamMember from './components/teamMember.vue';
import loadcase from './components/loadcase.vue';
import projectInfoDialog from '@/components/project/projectInfoDialog.vue';
import nodeInfoDialog from '@/components/project/phaseInfoDialog.vue';
import TaskDialog from '../projectList/components/taskDialog.vue';
import baseInfo from './components/baseInfo.vue';
import { editNodeApi } from '@/api/project/node';
import { PROJECT_EXE_STATUS_CODE } from '@/utils/enum/project';
import { ElMessage } from 'element-plus';
import StatisticAnalysis from './components/statisticAnalysis.vue';
import SchemeMaintain from '@/tenants/lyric/views/project/schemeMaintain.vue';
import BatchInfo from '@/tenants/lyric/views/project/batchInfo.vue';
import productionLine from '@/tenants/lyric/views/project/productionLine.vue';
import PDT from '@/tenants/lyric/views/project/PDT.vue';
import WorkspaceTime from '@/tenants/lyric/views/project/workspaceTime.vue';
import { enableConfigByTenant, TENANT_ENUM } from '@/tenants/tenant';
import { disposeAsyncPhase } from '@/tenants/lyric/views/project/project';
import DataOverView from '@/views/data/overview/components/index.vue';
import planningRecord from './components/planningRecord.vue';
import projectTaskPerformanceList from './components/projectTaskPerformanceList.vue';
import { isSimProjectManager } from '@/utils/task';
import { useRoute } from 'vue-router';
import { jumpPage } from '@/utils/common';
// import { queryNodeListApi } from '@/api/project/node';
// import { NODE_TYPE } from '@/utils/enum/node';
const props = defineProps({
projectUuid: {
type: String,
default: '',
},
});
const route = useRoute();
const nodeLevel1List = ref<any>([]);
// 表单弹窗ref
const basePageFormRef = ref();
// 项目信息界面ref
const basePageRef = ref();
const activeTab = ref('taskList');
const listPagePath: any = {
'0': '/project/allProject',
'1': '/project/followProject',
'2': '/project/chargeProject',
};
const goProjectListFun = () => {
const projectType: any = route.query?.projectType || '0';
jumpPage({
path: listPagePath[projectType],
});
};
const showProjectInfoDialog = ref(false);
// const currentProjectBaseInfo = reactive({
// id: '',
// projectName: '项目名称',
// projectCode: '项目代号',
// projectType: '项目类型',
// projectManager: '项目经理',
// progressStatus: '进行中',
// currentNode: 'T01',
// planStartTime: '2024-01-01',
// planEndTime: '2024-12-31',
// actualStartTime: '2024-01-05',
// actualEndTime: '',
// });
const openEditBasicDialogFun = () => {
showProjectInfoDialog.value = true;
// setTimeout(() => {
// nextTick(
// () => {
// basePageFormRef.value.setEditForm({ ...currentProjectInfo });
// const statusList = getProjectExeStatus(currentProjectInfo.exeStatus as PROJECT_EXE_STATUS_CODE);
// basePageFormRef.value.setOptionsFun('exeStatus', statusList);
// }
// );
// }, 500);
};
const showNodeInfoDialog = ref(false);
const openEditNodeDialogFun = () => {
showNodeInfoDialog.value = true;
};
const showTaskDialog = ref(false);
const openAddTaskDialogFun = async () => {
if (enableConfigByTenant([TENANT_ENUM.LYRIC])) {
const isSync = await disposeAsyncPhase(phaseList.value, currentProjectInfo);
if (isSync) {
showTaskDialog.value = true;
}
}
if (phaseList.value.length === 0) {
ElMessage.warning('请先创建阶段');
return;
}
showTaskDialog.value = true;
};
const currentProjectInfo = reactive<any>({
id: '',
projectId: '', // EP的项目id
projectSource: '',
uuid: '',
nodeName: '',
nodeCode: '',
nodeType: '',
nodeSubType: '',
progressStatus: '',
currentPhase: '',
beginTime: '',
endTime: '',
exeStatus: '',
actualStartTime: '',
actualEndTime: '',
description: '',
memberList: [],
});
const updateProjectInfo = (projectInfo: any) => {
for (const key in currentProjectInfo) {
currentProjectInfo[key] = projectInfo[key];
}
};
// const getProjectListApi = async() => {
// const res:any = await queryNodeListApi({ current: 1, size: 999, nodeType: NODE_TYPE.PROJECT });
// if (res && res.code === 200) {
// nodeLevel1List.value = res.data.data.map((item: { nodeName: string; uuid: string; }) => {
// // 赋予projectUuid初始值
// if (!projectUuid.value) {
// projectUuid.value = item.uuid;
// projectName.value = item.nodeName;
// }
// return { label: item.nodeName, info: { ...item }, value: item.uuid };
// });
// } else {
// nodeLevel1List.value = [];
// }
// };
const updateCurrentProjectBaseInfo = (projectInfo: any) => {
for (const key in currentProjectInfo) {
currentProjectInfo[key] = projectInfo[key];
}
basePageRef.value.updateBaseInfo(projectInfo);
};
const loadcaseRef = ref();
const completeFun = async (page: string) => {
if (page === 'projectBasePage') {
basePageRef.value.refresh();
}
if (page === 'phasePage') {
// 先刷新阶段信息 刷新currentProjectInfo.currentPhase
await basePageRef.value.refresh();
loadcaseRef.value.refreshPhaseList();
}
if (page === 'taskPlanPage') {
loadcaseRef.value.getTaskTreeList();
}
};
const closeProject = async () => {
const res: any = await editNodeApi({
editNodeList: [{ uuid: props.projectUuid, exeStatus: PROJECT_EXE_STATUS_CODE.CLOSED }],
});
if (res && res.code === 200) {
ElMessage.success('关闭项目成功!');
} else {
ElMessage.error(res.message || '关闭项目失败!');
}
};
const phaseList = ref<any[]>([]);
const getPhaseListFun = (phaseArr: any[]) => {
phaseList.value = phaseArr;
};
const displayedTabs = ref(['taskList']);
const tabChangeFun = (tab: string) => {
if (!displayedTabs.value.includes(tab)) {
displayedTabs.value.push(tab);
}
};
const isLoadProjectInfo = ref(false);
const projectInfoLoadCompleteFun = () => {
isLoadProjectInfo.value = true;
};
// if (route.query?.nodeId) {
// projectUuid.value = route.query?.nodeId;
// projectName.value = route.query?.nodeName;
// sessionStorage.setItem('projectUuid', projectUuid.value);
// sessionStorage.setItem('projectName', projectName.value);
// } else {
// // 使用上一次查看的项目id
// if (sessionStorage.getItem('projectUuid')) {
// projectUuid.value = sessionStorage.getItem('projectUuid');
// projectName.value = sessionStorage.getItem('projectName');
// } else {
// getProjectListApi();
// }
// }
// 当前用户是不是项目经理
const isMember = ref(false);
watch(
() => currentProjectInfo.memberList,
(newVal) => {
isMember.value = isSimProjectManager(newVal);
},
{ immediate: true }
);
</script>
<style lang="scss" scoped>
.app-container {
padding: 16px;
}
.select-content {
width: 500px;
display: flex;
align-items: center;
span {
display: inline-block;
width: 100px;
white-space: nowrap;
}
}
.top-selector {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.top-icons {
margin-left: auto;
// display: flex;
// gap: 16px;
.el-icon {
cursor: pointer;
}
}
.project-name {
font-size: 16px;
}
.node-select {
width: 120px;
}
.el-tabs {
height: calc(100% - 68px);
.el-tab-pane {
height: 100%;
}
}
.project-detail-content {
height: 100%;
overflow-y: auto;
padding-right: 10px;
}
.section-block {
margin-bottom: 24px;
padding-bottom: 20px;
&:last-child {
border-bottom: none;
margin-bottom: 0;
}
}
.section-title {
font-size: 16px;
font-weight: 600;
color: var(--el-text-color-primary);
margin-bottom: 12px;
padding-left: 10px;
border-left: 3px solid var(--el-color-primary);
}
</style>
<style lang="scss">
.tab-card {
.darg-line {
display: none !important;
}
}
</style>