feat: 添加项目进度统计功能,支持在列表中显示各项目的进度步骤统计信息,以及跳转

This commit is contained in:
2026-04-23 12:47:23 +08:00
parent 335dc88a2a
commit db90e2a084
12 changed files with 480 additions and 18 deletions

View File

@@ -87,6 +87,15 @@ export default {
tabNode: this.defaultTabNode,
firstLevelNode: this.defaultFirstLevelNode
});
},
/** 外部(路由深链等)同步选中进度类别与一级分类,并通知父级更新筛选 */
setSelection (tabNode, firstLevelNode) {
this.defaultTabNode = tabNode != null ? String(tabNode) : "";
this.defaultFirstLevelNode = firstLevelNode != null ? String(firstLevelNode) : "";
this.$emit("change", {
tabNode: this.defaultTabNode,
firstLevelNode: this.defaultFirstLevelNode
});
}
}
};

View File

@@ -107,6 +107,11 @@ export default {
type: Boolean | Number,
default: false
},
/** 打开进度详情时由路由传入定位左侧分类与表格筛选tabNode / firstLevelNode / trackId */
initialStepFocus: {
type: Object,
default: null
}
},
components: {
StepTable,
@@ -289,8 +294,44 @@ export default {
},
immediate: true
},
initialStepFocus: {
handler () {
this.$nextTick(() => this.applyInitialStepFocus());
},
deep: true
}
},
methods: {
applyInitialStepFocus () {
const hint = this.initialStepFocus;
if (!hint || !this.projectScheduleStepList.length) {
return;
}
let tabNode = hint.tabNode != null ? String(hint.tabNode) : "";
let firstLevelNode = hint.firstLevelNode != null ? String(hint.firstLevelNode) : "";
if ((!tabNode || !firstLevelNode) && hint.trackId != null && hint.trackId !== "") {
const st = this.projectScheduleStepList.find(
(s) => String(s.trackId) === String(hint.trackId)
);
if (st) {
tabNode = st.tabNode != null ? String(st.tabNode) : tabNode;
firstLevelNode = st.firstLevelNode != null ? String(st.firstLevelNode) : firstLevelNode;
}
}
if (!tabNode) {
return;
}
this.viewMode = "table";
this.$nextTick(() => {
const menu = this.$refs.menuSelectRef;
if (menu && typeof menu.setSelection === "function") {
menu.setSelection(tabNode, firstLevelNode);
} else {
this.defaultTabNode = tabNode;
this.defaultFirstLevelNode = firstLevelNode;
}
});
},
/** 查询项目进度步骤跟踪列表 */
getList () {
this.loading = true;
@@ -298,6 +339,7 @@ export default {
this.projectScheduleStepList = response.rows;
this.total = response.total;
this.loading = false;
this.$nextTick(() => this.applyInitialStepFocus());
});
},
handleOverview () {

View File

@@ -140,7 +140,8 @@
<div style="padding:0 20px">
<project-schedule-step :scheduleId="scheduleDetail.scheduleId" :master="scheduleDetail.functionary"
:projectName="scheduleDetail.projectName" :projectStatus="scheduleDetail.projectStatus"
:isTop="scheduleDetail.isTop" :projectId="scheduleDetail.projectId" />
:isTop="scheduleDetail.isTop" :projectId="scheduleDetail.projectId"
:initial-step-focus="scheduleStepFocusHint" />
</div>
</el-drawer>
@@ -153,7 +154,7 @@
</template>
<script>
import { listProject } from "@/api/oa/project";
import { addByProjectId, delProjectSchedule, listProjectSchedule, updateProjectSchedule } from "@/api/oa/projectSchedule";
import { addByProjectId, delProjectSchedule, getProjectSchedule, listProjectSchedule, updateProjectSchedule } from "@/api/oa/projectSchedule";
import { listUser } from "@/api/system/user";
import ProjectSelect from "@/components/fad-service/ProjectSelect/index.vue";
import UserSelect from "@/components/UserSelect/index.vue";
@@ -194,12 +195,34 @@ export default {
recentProjects: [],
scheduleDetail: {},
userList: [],
postponeDrawer: false
postponeDrawer: false,
/** 综合看板等深链:打开抽屉后传给 step用于选中进度类别/一级节点 */
scheduleStepFocusHint: null
};
},
watch: {
'$route.query': {
handler (newQ, oldQ) {
this.applyPaceRouteQueryBeforeFetch();
const n = newQ || {};
const o = oldQ || {};
if (n.scheduleId != null && n.scheduleId !== '') {
this.handleQuery();
return;
}
const np = n.projectId != null ? String(n.projectId) : '';
const op = o.projectId != null ? String(o.projectId) : '';
if (np !== '' && np !== op) {
this.handleQuery();
}
},
deep: true
}
},
mounted () {
this.currentUser = this.$store.state.user
this.applyPaceRouteQueryBeforeFetch();
this.getList();
this.getProjectList();
this.getAllUser();
@@ -209,8 +232,59 @@ export default {
}
},
methods: {
applyPaceRouteQueryBeforeFetch () {
const q = this.$route.query || {};
if (q.projectId != null && q.projectId !== '') {
this.queryParams.projectId = q.projectId;
}
},
clearPaceDeepLinkQuery () {
const q = { ...(this.$route.query || {}) };
delete q.scheduleId;
delete q.trackId;
delete q.tabNode;
delete q.firstLevelNode;
if (Object.keys(q).length) {
this.$router.replace({ path: this.$route.path, query: q });
} else {
this.$router.replace({ path: this.$route.path });
}
},
async maybeOpenScheduleFromRoute () {
const q = this.$route.query || {};
if (!q.scheduleId) {
return;
}
let row = this.scheduleList.find((s) => String(s.scheduleId) === String(q.scheduleId));
if (!row) {
try {
const res = await getProjectSchedule(q.scheduleId);
row = res.data;
} catch (e) {
this.$modal.msgError('未找到该进度或无权访问');
return;
}
}
if (!row) {
return;
}
const hasFocus =
(q.trackId != null && q.trackId !== '') ||
(q.tabNode != null && q.tabNode !== '') ||
(q.firstLevelNode != null && q.firstLevelNode !== '');
this.scheduleStepFocusHint = hasFocus
? {
trackId: q.trackId != null ? String(q.trackId) : '',
tabNode: q.tabNode != null ? String(q.tabNode) : '',
firstLevelNode: q.firstLevelNode != null ? String(q.firstLevelNode) : ''
}
: null;
this.getScheduleDetail(row);
this.$nextTick(() => this.clearPaceDeepLinkQuery());
},
// 关闭细节窗口
closeDetailShow (done) {
this.scheduleStepFocusHint = null;
this.getList();
done()
},
@@ -273,6 +347,7 @@ export default {
this.recentProjects = cache
/* 3. 结束 loading */
this.loading = false
this.maybeOpenScheduleFromRoute()
})
},
getProjectList () {
@@ -293,6 +368,7 @@ export default {
})
},
handleDetail (row) {
this.scheduleStepFocusHint = null;
// 把当前项目放到数组最前面,去重
const list = [row, ...this.recentProjects.filter(p => p.projectId !== row.projectId)];
// 只保留前 2 条