feat: 添加项目进度统计功能,支持在列表中显示各项目的进度步骤统计信息,以及跳转
This commit is contained in:
@@ -87,7 +87,8 @@ const actions = {
|
||||
const query = {
|
||||
pageNum: merged.pageNum,
|
||||
pageSize: merged.pageSize,
|
||||
keyword: (merged.keyword != null ? String(merged.keyword) : '').trim()
|
||||
keyword: (merged.keyword != null ? String(merged.keyword) : '').trim(),
|
||||
scheduleStats: true
|
||||
}
|
||||
commit('SET_PROJECT_QUERY', query)
|
||||
commit('SET_LOADING', true)
|
||||
|
||||
139
ruoyi-ui/src/utils/oaMenuNavigate.js
Normal file
139
ruoyi-ui/src/utils/oaMenuNavigate.js
Normal file
@@ -0,0 +1,139 @@
|
||||
import store from '@/store'
|
||||
|
||||
function isHttpUrl (path) {
|
||||
return path && /^(https?:|mailto:|tel:)/.test(path)
|
||||
}
|
||||
|
||||
function joinPaths (parentPath, segment) {
|
||||
if (segment == null || segment === '') {
|
||||
return parentPath || '/'
|
||||
}
|
||||
if (isHttpUrl(segment)) {
|
||||
return segment
|
||||
}
|
||||
if (segment.startsWith('/')) {
|
||||
return segment.replace(/\/+/g, '/')
|
||||
}
|
||||
const base = (parentPath || '').replace(/\/+$/, '')
|
||||
const rel = segment.replace(/^\//, '')
|
||||
if (!base) {
|
||||
return '/' + rel
|
||||
}
|
||||
return (base + '/' + rel).replace(/\/+/g, '/')
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历侧边栏路由树,得到所有带 meta.title 的叶子及其完整 path(与菜单渲染路径一致)
|
||||
*/
|
||||
export function flattenSidebarLeaves (routes, parentPath = '') {
|
||||
const out = []
|
||||
if (!routes || !routes.length) {
|
||||
return out
|
||||
}
|
||||
for (const r of routes) {
|
||||
if (!r || r.hidden) {
|
||||
continue
|
||||
}
|
||||
const current = joinPaths(parentPath, r.path)
|
||||
if (r.children && r.children.length > 0) {
|
||||
out.push(...flattenSidebarLeaves(r.children, current))
|
||||
} else if (r.meta && r.meta.title) {
|
||||
out.push({ fullPath: current, title: r.meta.title, name: r.name })
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* 按菜单名称(与 sys_menu.menu_name 一致)查找已注册的前端 path
|
||||
*/
|
||||
export function findMenuFullPathByTitles (titles) {
|
||||
const set = new Set((titles || []).filter(Boolean))
|
||||
if (!set.size) {
|
||||
return null
|
||||
}
|
||||
const routes = store.getters.sidebarRouters || []
|
||||
const leaves = flattenSidebarLeaves(routes)
|
||||
const hit = leaves.find((l) => set.has(l.title))
|
||||
return hit ? hit.fullPath : null
|
||||
}
|
||||
|
||||
/**
|
||||
* 将当前路由最后一级替换为另一段,用于「综合看板」与「任务」「进度」在同一父菜单下的场景
|
||||
*/
|
||||
export function siblingPathReplaceLast (currentPath, newLastSegment) {
|
||||
if (!currentPath || !newLastSegment) {
|
||||
return null
|
||||
}
|
||||
const normalized = String(currentPath).replace(/\/+$/, '')
|
||||
const idx = normalized.lastIndexOf('/')
|
||||
if (idx < 0) {
|
||||
return '/' + newLastSegment
|
||||
}
|
||||
return `${normalized.slice(0, idx)}/${newLastSegment}`.replace(/\/+/g, '/')
|
||||
}
|
||||
|
||||
/**
|
||||
* 在候选 path 中选第一个 resolve 后不是 404 页的地址
|
||||
*/
|
||||
export function pickExistingRoutePath (router, candidates) {
|
||||
for (const p of candidates) {
|
||||
if (!p) {
|
||||
continue
|
||||
}
|
||||
try {
|
||||
const { route } = router.resolve({ path: p })
|
||||
if (!route || !route.matched || route.matched.length === 0) {
|
||||
continue
|
||||
}
|
||||
if (route.path === '/404' || (route.fullPath && route.fullPath.includes('/404'))) {
|
||||
continue
|
||||
}
|
||||
return p
|
||||
} catch (e) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function findLeafPathMatchingPath (predicate) {
|
||||
const routes = store.getters.sidebarRouters || []
|
||||
const leaves = flattenSidebarLeaves(routes)
|
||||
const hit = leaves.find((l) => predicate(l.fullPath))
|
||||
return hit ? hit.fullPath : null
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析「我的任务」对应前端 path(勿硬编码父级目录,避免项目中心与项目管理 path 不一致导致 404)
|
||||
*/
|
||||
export function resolveOaTaskCenterPath (vm) {
|
||||
const fromMenuTitle = findMenuFullPathByTitles(['我的任务', '任务管理'])
|
||||
const fromPathEndsTask = findLeafPathMatchingPath((p) => /\/task(\/|$)/i.test(p))
|
||||
const sib = siblingPathReplaceLast(vm.$route.path, 'task')
|
||||
const candidates = [fromMenuTitle, fromPathEndsTask, sib, '/project/task'].filter(Boolean)
|
||||
return pickExistingRoutePath(vm.$router, candidates) || candidates[candidates.length - 1]
|
||||
}
|
||||
|
||||
const PACE_MENU_TITLES = [
|
||||
'项目进度',
|
||||
'进度管理',
|
||||
'进度跟踪',
|
||||
'绑定进度',
|
||||
'进度中心'
|
||||
]
|
||||
|
||||
/**
|
||||
* 解析进度中心(pace 列表+抽屉)页面前端 path
|
||||
*/
|
||||
export function resolveOaPaceCenterPath (vm) {
|
||||
const fromMenu = findMenuFullPathByTitles(PACE_MENU_TITLES)
|
||||
const fromPathEndsPace = findLeafPathMatchingPath((p) => /\/pace$/i.test(p))
|
||||
const base = vm.$route.path
|
||||
const siblingSegs = ['pace', 'schedule', 'projectSchedule', 'project-schedule']
|
||||
const fromSiblings = siblingSegs
|
||||
.map((s) => siblingPathReplaceLast(base, s))
|
||||
.filter(Boolean)
|
||||
const candidates = [fromMenu, fromPathEndsPace, ...fromSiblings, '/project/pace'].filter(Boolean)
|
||||
return pickExistingRoutePath(vm.$router, candidates) || candidates[candidates.length - 1]
|
||||
}
|
||||
@@ -27,13 +27,18 @@
|
||||
class="project-item"
|
||||
:class="{ active: String(p.projectId) === String(currentProjectId) }"
|
||||
@click="handleSelectProject(p)"
|
||||
:title="p.projectName"
|
||||
>
|
||||
<div class="project-name text-ellipsis">{{ p.projectName }}</div>
|
||||
<div class="project-meta text-ellipsis">
|
||||
<span v-if="p.projectCode" class="code">{{ p.projectCode }}</span>
|
||||
<span class="time">{{ formatDate(p.beginTime) }} ~ {{ formatDate(p.finishTime) }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="project-progress-row"
|
||||
:title="'当前进度:' + projectListScheduleLine(p)"
|
||||
>
|
||||
<span class="project-progress-label">当前进度:</span><span class="project-progress-value">{{ projectListScheduleLine(p) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!projectList || projectList.length === 0" class="left-empty">
|
||||
@@ -99,7 +104,11 @@
|
||||
:row-config="{ isHover: true }"
|
||||
>
|
||||
<vxe-column field="projectCode" title="代号" width="72"></vxe-column>
|
||||
<vxe-column field="taskTitle" title="任务主题" min-width="96"></vxe-column>
|
||||
<vxe-column field="taskTitle" title="任务主题" min-width="96">
|
||||
<template #default="{ row }">
|
||||
<span class="dashboard-link" @click.stop="goToTaskCenter(row)">{{ row.taskTitle || '-' }}</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="scheduleProgress" title="对应进度" min-width="112">
|
||||
<template #default="{ row }">
|
||||
<div v-if="scheduleProgressUnlinked(row)" class="schedule-progress-wrap">
|
||||
@@ -109,6 +118,7 @@
|
||||
v-else
|
||||
class="schedule-progress-wrap schedule-progress-wrap--linked"
|
||||
:title="scheduleProgressTitle(row)"
|
||||
@click.stop="goToPaceFromTaskRow(row)"
|
||||
>
|
||||
<el-tag :type="scheduleStepTagType(row)" size="mini" class="schedule-progress-status-tag">
|
||||
{{ scheduleStepStatusLabel(row) }}
|
||||
@@ -167,12 +177,7 @@
|
||||
<el-col :span="12">
|
||||
<div style="font-size: small;">
|
||||
<span style="color:#d0d0d0 ">项目名:</span>
|
||||
<el-popover placement="bottom" trigger="hover" width="800">
|
||||
<template slot="reference">
|
||||
<span style="color: #409eff;">{{ projectDisplayName }}</span>
|
||||
</template>
|
||||
<ProjectInfo :info="projectDetail || {}" />
|
||||
</el-popover>
|
||||
<span style="color: #409eff;">{{ projectDisplayName }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
@@ -217,7 +222,11 @@
|
||||
>
|
||||
<el-table-column prop="firstLevelNode" label="一级节点" min-width="112" show-overflow-tooltip />
|
||||
<el-table-column prop="secondLevelNode" label="二级节点" min-width="112" show-overflow-tooltip />
|
||||
<el-table-column prop="stepName" label="步骤名称" min-width="128" show-overflow-tooltip />
|
||||
<el-table-column prop="stepName" label="步骤名称" min-width="128" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<el-button type="text" size="mini" @click="goToPaceFromStepRow(row)">{{ row.stepName || '-' }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="92" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-tag :type="stepStatusTagType(row)" size="mini">{{ stepStatusLabel(row) }}</el-tag>
|
||||
@@ -282,11 +291,10 @@
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import Xmind from '@/views/oa/project/pace/components/xmind.vue'
|
||||
import ProjectInfo from '@/components/fad-service/ProjectInfo/index.vue'
|
||||
|
||||
import { resolveOaPaceCenterPath, resolveOaTaskCenterPath } from '@/utils/oaMenuNavigate'
|
||||
export default {
|
||||
name: 'OaProjectDashboard2',
|
||||
components: { Xmind, ProjectInfo },
|
||||
components: { Xmind },
|
||||
dicts: ['sys_work_type', 'sys_sort_grade'],
|
||||
data () {
|
||||
return {
|
||||
@@ -497,6 +505,67 @@ export default {
|
||||
await this.refreshCurrent()
|
||||
},
|
||||
|
||||
goToTaskCenter (row) {
|
||||
if (!row || row.taskId == null || row.taskId === '') {
|
||||
return
|
||||
}
|
||||
const path = resolveOaTaskCenterPath(this)
|
||||
this.$router.push({ path, query: { taskId: String(row.taskId) } })
|
||||
},
|
||||
|
||||
resolveScheduleIdByTaskTrack (trackId) {
|
||||
if (trackId == null || trackId === '') {
|
||||
return null
|
||||
}
|
||||
const hit = (this.stepList || []).find((s) => String(s.trackId) === String(trackId))
|
||||
return hit && hit.scheduleId != null ? hit.scheduleId : null
|
||||
},
|
||||
|
||||
goToPaceFromTaskRow (row) {
|
||||
if (this.scheduleProgressUnlinked(row)) {
|
||||
this.$message.warning('该任务未关联进度')
|
||||
return
|
||||
}
|
||||
const scheduleId = this.resolveScheduleIdByTaskTrack(row.trackId)
|
||||
if (!scheduleId || !this.currentProjectId) {
|
||||
this.$message.warning('未找到对应进度主表')
|
||||
return
|
||||
}
|
||||
const path = resolveOaPaceCenterPath(this)
|
||||
this.$router.push({
|
||||
path,
|
||||
query: {
|
||||
projectId: String(this.currentProjectId),
|
||||
scheduleId: String(scheduleId),
|
||||
trackId: String(row.trackId),
|
||||
tabNode: row.tabNode != null ? String(row.tabNode) : '',
|
||||
firstLevelNode: row.firstLevelNode != null ? String(row.firstLevelNode) : ''
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
goToPaceFromStepRow (row) {
|
||||
if (!row || row.scheduleId == null || row.scheduleId === '' || !this.currentProjectId) {
|
||||
this.$message.warning('缺少进度或项目信息')
|
||||
return
|
||||
}
|
||||
const query = {
|
||||
projectId: String(this.currentProjectId),
|
||||
scheduleId: String(row.scheduleId)
|
||||
}
|
||||
if (row.trackId != null && row.trackId !== '') {
|
||||
query.trackId = String(row.trackId)
|
||||
}
|
||||
if (row.tabNode) {
|
||||
query.tabNode = String(row.tabNode)
|
||||
}
|
||||
if (row.firstLevelNode) {
|
||||
query.firstLevelNode = String(row.firstLevelNode)
|
||||
}
|
||||
const path = resolveOaPaceCenterPath(this)
|
||||
this.$router.push({ path, query })
|
||||
},
|
||||
|
||||
noop () {},
|
||||
|
||||
/** 无 track_id 或无步骤名称 → 未关联(后端联表 oa_project_schedule_step,use_flag=1) */
|
||||
@@ -542,6 +611,14 @@ export default {
|
||||
return this.scheduleStepTagType({ scheduleStatus: row && row.status })
|
||||
},
|
||||
|
||||
/** 左侧列表:与进度中心一致的「当前进度」文案(数据来自 list scheduleStats) */
|
||||
projectListScheduleLine (p) {
|
||||
const total = Number(p && p.scheduleStepTotal != null ? p.scheduleStepTotal : 0)
|
||||
const done = Number(p && p.scheduleStepCompleted != null ? p.scheduleStepCompleted : 0)
|
||||
const pend = Number(p && p.scheduleStepPendingAccept != null ? p.scheduleStepPendingAccept : 0)
|
||||
return `已完成(${done})+ 待验收(${pend}) / 总节点数(${total})`
|
||||
},
|
||||
|
||||
formatDate (val) {
|
||||
if (!val) return '-'
|
||||
const s = String(val)
|
||||
@@ -631,13 +708,34 @@ export default {
|
||||
border-bottom: 1px solid #eef0f3;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 2px;
|
||||
min-height: 42px;
|
||||
min-height: 52px;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
transition: background 0.15s ease;
|
||||
}
|
||||
|
||||
/* 单行展示:缩小字号 + 不换行,仍过长则省略号(悬停 title 看全文) */
|
||||
.project-progress-row {
|
||||
margin-top: 3px;
|
||||
min-width: 0;
|
||||
font-size: 10px;
|
||||
line-height: 1.35;
|
||||
letter-spacing: -0.02em;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.project-progress-label {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.project-progress-value {
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.project-item:hover {
|
||||
background: #f0f2f5;
|
||||
}
|
||||
@@ -883,6 +981,16 @@ export default {
|
||||
|
||||
.schedule-progress-wrap--linked {
|
||||
min-width: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dashboard-link {
|
||||
color: #409eff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dashboard-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.schedule-progress-status-tag {
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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 () {
|
||||
|
||||
@@ -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 条
|
||||
|
||||
Reference in New Issue
Block a user